Repository: rust-analyzer/rust-analyzer
Pull request #10877 (2021-11-27 18:16:57)

feat: make hightlighting linear
In https://youtu.be/qvIZZf5dmTE, we've noticed that AstIdMap does a
linear lookup when going from SyntaxNode to Id. This leads to
accidentally quadratic overall performance. Replace linear lookup with a
O(1) hashmap lookup.

Future work: don't duplicate `SyntaxNodePtr` in `AstIdMap` and switch to
"call site dependency injection" style storage (eg, store a
`HashSet<ErasedFileAstId>`).

See the explanation of the work here on YouTube :-)

As you can see from then benchmark results, this doesn't actually make analysis stats fastre. I am a bit mystified as to why this is happening to be honest. 

Baseline
```
Database loaded:     598.40ms, 304minstr, 118mb (metadata 390.57ms, 21minstr, 841kb; build 111.31ms, 8764kinstr, -214kb)
  crates: 39, mods: 824, decls: 18647, fns: 13910
Item Collection:     9.70s, 75ginstr, 377mb
  exprs: 382426, ??ty: 387 (0%), ?ty: 285 (0%), !ty: 145
Inference:           43.16s, 342ginstr, 641mb
Total:               52.86s, 417ginstr, 1018mb
```

This PR:
```
Database loaded:     626.34ms, 304minstr, 118mb (metadata 416.26ms, 21minstr, 841kb; build 113.67ms, 8750kinstr, -209kb)
  crates: 39, mods: 824, decls: 18647, fns: 13910
Item Collection:     10.16s, 75ginstr, 389mb
  exprs: 382426, ??ty: 387 (0%), ?ty: 285 (0%), !ty: 145
Inference:           44.51s, 342ginstr, 644mb
Total:               54.67s, 417ginstr, 1034mb
```

I think we probably should merge the first commit here, but not the second. 

matklad: https://youtu.be/wvEgymUm7cY <- me not understanding what's going on here :-) 
flodiebold: Even if it doesn't improve performance, you'd expect _some_ kind of change in the instruction counts, wouldn't you? :confused: 

Patch:
diff --git a/.gitignore b/.gitignore
index 68c87a6b1e..f3e3cab1d6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,4 +13,3 @@ generated_diagnostic.adoc
 .DS_Store
 /out/
 /dump.lsif
-.envrc
diff --git a/Cargo.lock b/Cargo.lock
index 92f98b536c..173bbb801d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -525,6 +525,7 @@ dependencies = [
  "cfg",
  "cov-mark",
  "either",
+ "hashbrown",
  "itertools",
  "la-arena",
  "limit",
@@ -881,9 +882,9 @@ dependencies = [
 
 [[package]]
 name = "matchers"
-version = "0.1.0"
+version = "0.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
+checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1"
 dependencies = [
  "regex-automata",
 ]
@@ -1071,7 +1072,6 @@ name = "parser"
 version = "0.0.0"
 dependencies = [
  "drop_bomb",
- "limit",
 ]
 
 [[package]]
@@ -1731,9 +1731,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-subscriber"
-version = "0.3.3"
+version = "0.2.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "245da694cc7fc4729f3f418b304cb57789f1bed2a78c575407ab8a23f53cb4d3"
+checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71"
 dependencies = [
  "lazy_static",
  "matchers",
@@ -1747,9 +1747,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-tree"
-version = "0.2.0"
+version = "0.1.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ce989c9962c7f61fe084dd4a230eec784649dfc2392467c790007c3a6e134e7"
+checksum = "a2a408a91fbd4850982080e643a261aef2a2ef72c8263ce353b61d25acfc2c49"
 dependencies = [
  "ansi_term",
  "atty",
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs
index 54e95cf7c3..2f6eed82cb 100644
--- a/crates/hir/src/attrs.rs
+++ b/crates/hir/src/attrs.rs
@@ -137,7 +137,6 @@ fn resolve_doc_path(
         AttrDefId::TraitId(it) => it.resolver(db.upcast()),
         AttrDefId::TypeAliasId(it) => it.resolver(db.upcast()),
         AttrDefId::ImplId(it) => it.resolver(db.upcast()),
-        AttrDefId::ExternBlockId(it) => it.resolver(db.upcast()),
         AttrDefId::GenericParamId(it) => match it {
             GenericParamId::TypeParamId(it) => it.parent,
             GenericParamId::LifetimeParamId(it) => it.parent,
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index 17465dc2b0..38bbf41797 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -12,10 +12,7 @@ use hir_ty::{
     },
     Interner, TraitRefExt, WhereClause,
 };
-use syntax::{
-    ast::{self, HasName},
-    SmolStr,
-};
+use syntax::ast::{self, HasName};
 
 use crate::{
     Adt, Const, ConstParam, Enum, Field, Function, GenericParam, HasCrate, HasVisibility,
@@ -250,8 +247,7 @@ impl HirDisplay for TypeParam {
             bounds.iter().cloned().map(|b| b.substitute(&Interner, &substs)).collect();
         let krate = self.id.parent.krate(f.db).id;
         let sized_trait =
-            f.db.lang_item(krate, SmolStr::new_inline("sized"))
-                .and_then(|lang_item| lang_item.as_trait());
+            f.db.lang_item(krate, "sized".into()).and_then(|lang_item| lang_item.as_trait());
         let has_only_sized_bound = predicates.iter().all(move |pred| match pred.skip_binders() {
             WhereClause::Implemented(it) => Some(it.hir_trait_id()) == sized_trait,
             _ => false,
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 7add0f4a43..4d758c7df7 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -114,11 +114,11 @@ pub use {
         type_ref::{Mutability, TypeRef},
         visibility::Visibility,
         AdtId,
+        AssocContainerId,
         AssocItemId,
         AssocItemLoc,
         DefWithBodyId,
         ImplId,
-        ItemContainerId,
         ItemLoc,
         Lookup,
         ModuleDefId,
@@ -1550,7 +1550,7 @@ impl Static {
     pub fn ty(self, db: &dyn HirDatabase) -> Type {
         let data = db.static_data(self.id);
         let resolver = self.id.resolver(db.upcast());
-        let krate = self.id.lookup(db.upcast()).container.module(db.upcast()).krate();
+        let krate = self.id.lookup(db.upcast()).container.krate();
         let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
         let ty = ctx.lower_ty(&data.type_ref);
         Type::new_with_resolver_inner(db, krate, &resolver, ty)
@@ -1716,10 +1716,6 @@ impl MacroDef {
             MacroKind::Attr | MacroKind::Derive => false,
         }
     }
-
-    pub fn is_attr(&self) -> bool {
-        matches!(self.kind(), MacroKind::Attr)
-    }
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
@@ -1820,8 +1816,8 @@ where
     AST: ItemTreeNode,
 {
     match id.lookup(db.upcast()).container {
-        ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => Some(ctor(DEF::from(id))),
-        ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
+        AssocContainerId::TraitId(_) | AssocContainerId::ImplId(_) => Some(ctor(DEF::from(id))),
+        AssocContainerId::ModuleId(_) => None,
     }
 }
 
@@ -1847,11 +1843,9 @@ impl AssocItem {
             AssocItem::TypeAlias(it) => it.id.lookup(db.upcast()).container,
         };
         match container {
-            ItemContainerId::TraitId(id) => AssocItemContainer::Trait(id.into()),
-            ItemContainerId::ImplId(id) => AssocItemContainer::Impl(id.into()),
-            ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
-                panic!("invalid AssocItem")
-            }
+            AssocContainerId::TraitId(id) => AssocItemContainer::Trait(id.into()),
+            AssocContainerId::ImplId(id) => AssocItemContainer::Impl(id.into()),
+            AssocContainerId::ModuleId(_) => panic!("invalid AssocItem"),
         }
     }
 
@@ -2427,7 +2421,7 @@ impl Type {
         let krate = self.krate;
 
         let std_future_trait =
-            db.lang_item(krate, SmolStr::new_inline("future_trait")).and_then(|it| it.as_trait());
+            db.lang_item(krate, "future_trait".into()).and_then(|it| it.as_trait());
         let std_future_trait = match std_future_trait {
             Some(it) => it,
             None => return false,
@@ -2516,7 +2510,7 @@ impl Type {
     }
 
     pub fn is_copy(&self, db: &dyn HirDatabase) -> bool {
-        let lang_item = db.lang_item(self.krate, SmolStr::new_inline("copy"));
+        let lang_item = db.lang_item(self.krate, SmolStr::new("copy"));
         let copy_trait = match lang_item {
             Some(LangItemTarget::TraitId(it)) => it,
             _ => return false,
@@ -2623,15 +2617,13 @@ impl Type {
     }
 
     pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a {
-        self.autoderef_(db).map(move |ty| self.derived(ty))
-    }
-
-    pub fn autoderef_<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Ty> + 'a {
         // There should be no inference vars in types passed here
         let canonical = hir_ty::replace_errors_with_variables(&self.ty);
         let environment = self.env.env.clone();
         let ty = InEnvironment { goal: canonical, environment };
-        autoderef(db, Some(self.krate), ty).map(|canonical| canonical.value)
+        autoderef(db, Some(self.krate), ty)
+            .map(|canonical| canonical.value)
+            .map(move |ty| self.derived(ty))
     }
 
     // This would be nicer if it just returned an iterator, but that runs into
@@ -2810,32 +2802,22 @@ impl Type {
         db: &'a dyn HirDatabase,
     ) -> impl Iterator<Item = Trait> + 'a {
         let _p = profile::span("applicable_inherent_traits");
-        self.autoderef_(db)
-            .filter_map(|ty| ty.dyn_trait())
+        self.autoderef(db)
+            .filter_map(|derefed_type| derefed_type.ty.dyn_trait())
             .flat_map(move |dyn_trait_id| hir_ty::all_super_traits(db.upcast(), dyn_trait_id))
             .map(Trait::from)
     }
 
-    pub fn env_traits<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Trait> + 'a {
-        let _p = profile::span("env_traits");
-        self.autoderef_(db)
-            .filter(|ty| matches!(ty.kind(&Interner), TyKind::Placeholder(_)))
-            .flat_map(|ty| {
-                self.env
-                    .traits_in_scope_from_clauses(ty)
-                    .flat_map(|t| hir_ty::all_super_traits(db.upcast(), t))
-            })
-            .map(Trait::from)
-    }
-
-    pub fn as_impl_traits(&self, db: &dyn HirDatabase) -> Option<impl Iterator<Item = Trait>> {
+    pub fn as_impl_traits(&self, db: &dyn HirDatabase) -> Option<Vec<Trait>> {
         self.ty.impl_trait_bounds(db).map(|it| {
-            it.into_iter().filter_map(|pred| match pred.skip_binders() {
-                hir_ty::WhereClause::Implemented(trait_ref) => {
-                    Some(Trait::from(trait_ref.hir_trait_id()))
-                }
-                _ => None,
-            })
+            it.into_iter()
+                .filter_map(|pred| match pred.skip_binders() {
+                    hir_ty::WhereClause::Implemented(trait_ref) => {
+                        Some(Trait::from(trait_ref.hir_trait_id()))
+                    }
+                    _ => None,
+                })
+                .collect()
         })
     }
 
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 880596b37c..762f172c2a 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -335,16 +335,17 @@ impl SourceAnalyzer {
                 }
             }
         } else if is_path_of_attr {
-            let name_ref = path.as_single_name_ref();
-            let builtin =
-                name_ref.as_ref().map(ast::NameRef::text).as_deref().and_then(BuiltinAttr::by_name);
-            if let builtin @ Some(_) = builtin {
-                return builtin.map(PathResolution::BuiltinAttr);
-            }
-            return match resolve_hir_path_as_macro(db, &self.resolver, &hir_path) {
-                res @ Some(m) if m.is_attr() => res.map(PathResolution::Macro),
-                _ => name_ref.and_then(|name_ref| {
-                    ToolModule::by_name(&name_ref.text()).map(PathResolution::ToolModule)
+            let res = resolve_hir_path_as_macro(db, &self.resolver, &hir_path);
+            return match res {
+                Some(_) => res.map(PathResolution::Macro),
+                None => path.as_single_name_ref().and_then(|name_ref| {
+                    if let builtin @ Some(_) = BuiltinAttr::by_name(&name_ref.text()) {
+                        builtin.map(PathResolution::BuiltinAttr)
+                    } else if let tool @ Some(_) = ToolModule::by_name(&name_ref.text()) {
+                        tool.map(PathResolution::ToolModule)
+                    } else {
+                        None
+                    }
                 }),
             };
         }
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 36e46a103c..711062c713 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -362,7 +362,6 @@ impl AttrsWithOwner {
                     RawAttrs::from_attrs_owner(db, src.with_value(&src.value[it.local_id]))
                 }
             },
-            AttrDefId::ExternBlockId(it) => attrs_from_item_tree(it.lookup(db).id, db),
         };
 
         let attrs = raw_attrs.filter(db, def.krate(db));
@@ -444,7 +443,6 @@ impl AttrsWithOwner {
                     .child_source(db)
                     .map(|source| ast::AnyHasAttrs::new(source[id.local_id].clone())),
             },
-            AttrDefId::ExternBlockId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
         };
 
         AttrSourceMap::new(owner.as_ref().map(|node| node as &dyn HasAttrs))
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs
index b9f8c2f297..f4d0c3af90 100644
--- a/crates/hir_def/src/data.rs
+++ b/crates/hir_def/src/data.rs
@@ -13,8 +13,8 @@ use crate::{
     item_tree::{self, AssocItem, FnFlags, ItemTreeId, ModItem, Param},
     type_ref::{TraitRef, TypeBound, TypeRef},
     visibility::RawVisibility,
-    AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, Intern,
-    ItemContainerId, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc,
+    AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId,
+    Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc,
 };
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -54,10 +54,6 @@ impl FunctionData {
             flags.bits |= FnFlags::IS_VARARGS;
         }
 
-        if matches!(loc.container, ItemContainerId::ExternBlockId(_)) {
-            flags.bits |= FnFlags::IS_IN_EXTERN_BLOCK;
-        }
-
         Arc::new(FunctionData {
             name: func.name.clone(),
             params: enabled_params
@@ -134,7 +130,7 @@ impl TypeAliasData {
             name: typ.name.clone(),
             type_ref: typ.type_ref.clone(),
             visibility: item_tree[typ.visibility].clone(),
-            is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
+            is_extern: typ.is_extern,
             bounds: typ.bounds.to_vec(),
         })
     }
@@ -166,7 +162,7 @@ impl TraitData {
         let is_auto = tr_def.is_auto;
         let is_unsafe = tr_def.is_unsafe;
         let module_id = tr_loc.container;
-        let container = ItemContainerId::TraitId(tr);
+        let container = AssocContainerId::TraitId(tr);
         let visibility = item_tree[tr_def.visibility].clone();
         let mut expander = Expander::new(db, tr_loc.id.file_id(), module_id);
         let skip_array_during_method_dispatch = item_tree
@@ -235,7 +231,7 @@ impl ImplData {
         let self_ty = impl_def.self_ty.clone();
         let is_negative = impl_def.is_negative;
         let module_id = impl_loc.container;
-        let container = ItemContainerId::ImplId(id);
+        let container = AssocContainerId::ImplId(id);
         let mut expander = Expander::new(db, impl_loc.id.file_id(), module_id);
 
         let items = collect_items(
@@ -255,7 +251,7 @@ impl ImplData {
 
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct ConstData {
-    /// `None` for `const _: () = ();`
+    /// const _: () = ();
     pub name: Option<Name>,
     pub type_ref: Interned<TypeRef>,
     pub visibility: RawVisibility,
@@ -286,16 +282,16 @@ pub struct StaticData {
 
 impl StaticData {
     pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<StaticData> {
-        let loc = konst.lookup(db);
-        let item_tree = loc.id.item_tree(db);
-        let statik = &item_tree[loc.id.value];
+        let node = konst.lookup(db);
+        let item_tree = node.id.item_tree(db);
+        let statik = &item_tree[node.id.value];
 
         Arc::new(StaticData {
             name: statik.name.clone(),
             type_ref: statik.type_ref.clone(),
             visibility: item_tree[statik.visibility].clone(),
             mutable: statik.mutable,
-            is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
+            is_extern: statik.is_extern,
         })
     }
 }
@@ -306,7 +302,7 @@ fn collect_items(
     expander: &mut Expander,
     assoc_items: impl Iterator<Item = AssocItem>,
     tree_id: item_tree::TreeId,
-    container: ItemContainerId,
+    container: AssocContainerId,
     limit: usize,
 ) -> Vec<(Name, AssocItemId)> {
     if limit == 0 {
diff --git a/crates/hir_def/src/db.rs b/crates/hir_def/src/db.rs
index 7946558311..c977971cd4 100644
--- a/crates/hir_def/src/db.rs
+++ b/crates/hir_def/src/db.rs
@@ -19,10 +19,10 @@ use crate::{
     lang_item::{LangItemTarget, LangItems},
     nameres::DefMap,
     visibility::{self, Visibility},
-    AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, ExternBlockId,
-    ExternBlockLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalEnumVariantId,
-    LocalFieldId, StaticId, StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId,
-    TypeAliasLoc, UnionId, UnionLoc, VariantId,
+    AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId,
+    FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalEnumVariantId, LocalFieldId, StaticId,
+    StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId,
+    UnionLoc, VariantId,
 };
 
 #[salsa::query_group(InternDatabaseStorage)]
@@ -46,8 +46,6 @@ pub trait InternDatabase: SourceDatabase {
     #[salsa::interned]
     fn intern_impl(&self, loc: ImplLoc) -> ImplId;
     #[salsa::interned]
-    fn intern_extern_block(&self, loc: ExternBlockLoc) -> ExternBlockId;
-    #[salsa::interned]
     fn intern_block(&self, loc: BlockLoc) -> BlockId;
 }
 
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs
index 27a05b87c1..404e3e1539 100644
--- a/crates/hir_def/src/import_map.rs
+++ b/crates/hir_def/src/import_map.rs
@@ -468,7 +468,7 @@ mod tests {
     use base_db::{fixture::WithFixture, SourceDatabase, Upcast};
     use expect_test::{expect, Expect};
 
-    use crate::{test_db::TestDB, ItemContainerId, Lookup};
+    use crate::{test_db::TestDB, AssocContainerId, Lookup};
 
     use super::*;
 
@@ -563,7 +563,7 @@ mod tests {
         };
 
         match container {
-            ItemContainerId::TraitId(it) => Some(ItemInNs::Types(it.into())),
+            AssocContainerId::TraitId(it) => Some(ItemInNs::Types(it.into())),
             _ => None,
         }
     }
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index 68d77084a3..aab3f4b3c8 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -648,7 +648,7 @@ pub struct Enum {
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Const {
-    /// `None` for `const _: () = ();`
+    /// const _: () = ();
     pub name: Option<Name>,
     pub visibility: RawVisibilityId,
     pub type_ref: Interned<TypeRef>,
@@ -660,6 +660,8 @@ pub struct Static {
     pub name: Name,
     pub visibility: RawVisibilityId,
     pub mutable: bool,
+    /// Whether the static is in an `extern` block.
+    pub is_extern: bool,
     pub type_ref: Interned<TypeRef>,
     pub ast_id: FileAstId<ast::Static>,
 }
@@ -693,6 +695,7 @@ pub struct TypeAlias {
     pub bounds: Box<[Interned<TypeBound>]>,
     pub generic_params: Interned<GenericParams>,
     pub type_ref: Option<Interned<TypeRef>>,
+    pub is_extern: bool,
     pub ast_id: FileAstId<ast::TypeAlias>,
 }
 
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 4396801116..32213aac39 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -360,6 +360,7 @@ impl<'a> Ctx<'a> {
             generic_params,
             type_ref,
             ast_id,
+            is_extern: false,
         };
         Some(id(self.data().type_aliases.alloc(res)))
     }
@@ -370,12 +371,17 @@ impl<'a> Ctx<'a> {
         let visibility = self.lower_visibility(static_);
         let mutable = static_.mut_token().is_some();
         let ast_id = self.source_ast_id_map.ast_id(static_);
-        let res = Static { name, visibility, mutable, type_ref, ast_id };
+        let res = Static { name, visibility, mutable, type_ref, ast_id, is_extern: false };
         Some(id(self.data().statics.alloc(res)))
     }
 
     fn lower_const(&mut self, konst: &ast::Const) -> FileItemTreeId<Const> {
-        let name = konst.name().map(|it| it.as_name());
+        let mut name = konst.name().map(|it| it.as_name());
+        if name.as_ref().map_or(false, |n| n.to_smol_str().starts_with("_DERIVE_")) {
+            // FIXME: this is a hack to treat consts generated by synstructure as unnamed
+            // remove this some time in the future
+            name = None;
+        }
         let type_ref = self.lower_type_ref_opt(konst.ty());
         let visibility = self.lower_visibility(konst);
         let ast_id = self.source_ast_id_map.ast_id(konst);
@@ -519,23 +525,27 @@ impl<'a> Ctx<'a> {
         let children: Box<[_]> = block.extern_item_list().map_or(Box::new([]), |list| {
             list.extern_items()
                 .filter_map(|item| {
-                    // Note: All items in an `extern` block need to be lowered as if they're outside of one
-                    // (in other words, the knowledge that they're in an extern block must not be used).
-                    // This is because an extern block can contain macros whose ItemTree's top-level items
-                    // should be considered to be in an extern block too.
                     let attrs = RawAttrs::new(self.db, &item, &self.hygiene);
                     let id: ModItem = match item {
                         ast::ExternItem::Fn(ast) => {
                             let func_id = self.lower_function(&ast)?;
                             let func = &mut self.data().functions[func_id.index];
                             if is_intrinsic_fn_unsafe(&func.name) {
-                                // FIXME: this breaks in macros
                                 func.flags.bits |= FnFlags::IS_UNSAFE;
                             }
+                            func.flags.bits |= FnFlags::IS_IN_EXTERN_BLOCK;
                             func_id.into()
                         }
-                        ast::ExternItem::Static(ast) => self.lower_static(&ast)?.into(),
-                        ast::ExternItem::TypeAlias(ty) => self.lower_type_alias(&ty)?.into(),
+                        ast::ExternItem::Static(ast) => {
+                            let statik = self.lower_static(&ast)?;
+                            self.data().statics[statik.index].is_extern = true;
+                            statik.into()
+                        }
+                        ast::ExternItem::TypeAlias(ty) => {
+                            let foreign_ty = self.lower_type_alias(&ty)?;
+                            self.data().type_aliases[foreign_ty.index].is_extern = true;
+                            foreign_ty.into()
+                        }
                         ast::ExternItem::MacroCall(call) => {
                             // FIXME: we need some way of tracking that the macro call is in an
                             // extern block
diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs
index 4b46283743..49dc1eef18 100644
--- a/crates/hir_def/src/item_tree/pretty.rs
+++ b/crates/hir_def/src/item_tree/pretty.rs
@@ -328,7 +328,8 @@ impl<'a> Printer<'a> {
                 wln!(self, " = _;");
             }
             ModItem::Static(it) => {
-                let Static { name, visibility, mutable, type_ref, ast_id: _ } = &self.tree[it];
+                let Static { name, visibility, mutable, is_extern, type_ref, ast_id: _ } =
+                    &self.tree[it];
                 self.print_visibility(*visibility);
                 w!(self, "static ");
                 if *mutable {
@@ -337,6 +338,9 @@ impl<'a> Printer<'a> {
                 w!(self, "{}: ", name);
                 self.print_type_ref(type_ref);
                 w!(self, " = _;");
+                if *is_extern {
+                    w!(self, "  // extern");
+                }
                 wln!(self);
             }
             ModItem::Trait(it) => {
@@ -389,8 +393,15 @@ impl<'a> Printer<'a> {
                 wln!(self, "}}");
             }
             ModItem::TypeAlias(it) => {
-                let TypeAlias { name, visibility, bounds, type_ref, generic_params, ast_id: _ } =
-                    &self.tree[it];
+                let TypeAlias {
+                    name,
+                    visibility,
+                    bounds,
+                    type_ref,
+                    is_extern,
+                    generic_params,
+                    ast_id: _,
+                } = &self.tree[it];
                 self.print_visibility(*visibility);
                 w!(self, "type {}", name);
                 self.print_generic_params(generic_params);
@@ -404,6 +415,9 @@ impl<'a> Printer<'a> {
                 }
                 self.print_where_clause(generic_params);
                 w!(self, ";");
+                if *is_extern {
+                    w!(self, "  // extern");
+                }
                 wln!(self);
             }
             ModItem::Mod(it) => {
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index c8e60032df..b68ede4003 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -65,7 +65,6 @@ use hir_expand::{
     hygiene::Hygiene,
     AstId, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
 };
-use item_tree::ExternBlock;
 use la_arena::Idx;
 use nameres::DefMap;
 use path::ModPath;
@@ -154,7 +153,7 @@ impl<N: ItemTreeNode> Hash for ItemLoc<N> {
 
 #[derive(Debug)]
 pub struct AssocItemLoc<N: ItemTreeNode> {
-    pub container: ItemContainerId,
+    pub container: AssocContainerId,
     pub id: ItemTreeId<N>,
 }
 
@@ -245,7 +244,7 @@ impl_intern!(ConstId, ConstLoc, intern_const, lookup_intern_const);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct StaticId(salsa::InternId);
-pub type StaticLoc = AssocItemLoc<Static>;
+pub type StaticLoc = ItemLoc<Static>;
 impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -263,11 +262,6 @@ pub struct ImplId(salsa::InternId);
 type ImplLoc = ItemLoc<Impl>;
 impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl);
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
-pub struct ExternBlockId(salsa::InternId);
-type ExternBlockLoc = ItemLoc<ExternBlock>;
-impl_intern!(ExternBlockId, ExternBlockLoc, intern_extern_block, lookup_intern_extern_block);
-
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
 pub struct BlockId(salsa::InternId);
 #[derive(Debug, Hash, PartialEq, Eq, Clone)]
@@ -301,13 +295,12 @@ pub struct ConstParamId {
 pub type LocalConstParamId = Idx<generics::ConstParamData>;
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub enum ItemContainerId {
-    ExternBlockId(ExternBlockId),
+pub enum AssocContainerId {
     ModuleId(ModuleId),
     ImplId(ImplId),
     TraitId(TraitId),
 }
-impl_from!(ModuleId for ItemContainerId);
+impl_from!(ModuleId for AssocContainerId);
 
 /// A Data Type
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
@@ -434,7 +427,6 @@ pub enum AttrDefId {
     MacroDefId(MacroDefId),
     ImplId(ImplId),
     GenericParamId(GenericParamId),
-    ExternBlockId(ExternBlockId),
 }
 
 impl_from!(
@@ -453,13 +445,12 @@ impl_from!(
     for AttrDefId
 );
 
-impl From<ItemContainerId> for AttrDefId {
-    fn from(acid: ItemContainerId) -> Self {
+impl From<AssocContainerId> for AttrDefId {
+    fn from(acid: AssocContainerId) -> Self {
         match acid {
-            ItemContainerId::ModuleId(mid) => AttrDefId::ModuleId(mid),
-            ItemContainerId::ImplId(iid) => AttrDefId::ImplId(iid),
-            ItemContainerId::TraitId(tid) => AttrDefId::TraitId(tid),
-            ItemContainerId::ExternBlockId(id) => AttrDefId::ExternBlockId(id),
+            AssocContainerId::ModuleId(mid) => AttrDefId::ModuleId(mid),
+            AssocContainerId::ImplId(iid) => AttrDefId::ImplId(iid),
+            AssocContainerId::TraitId(tid) => AttrDefId::TraitId(tid),
         }
     }
 }
@@ -514,13 +505,12 @@ pub trait HasModule {
     fn module(&self, db: &dyn db::DefDatabase) -> ModuleId;
 }
 
-impl HasModule for ItemContainerId {
+impl HasModule for AssocContainerId {
     fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
         match *self {
-            ItemContainerId::ModuleId(it) => it,
-            ItemContainerId::ImplId(it) => it.lookup(db).container,
-            ItemContainerId::TraitId(it) => it.lookup(db).container,
-            ItemContainerId::ExternBlockId(it) => it.lookup(db).container,
+            AssocContainerId::ModuleId(it) => it,
+            AssocContainerId::ImplId(it) => it.lookup(db).container,
+            AssocContainerId::TraitId(it) => it.lookup(db).container,
         }
     }
 }
@@ -597,6 +587,12 @@ impl HasModule for TraitId {
     }
 }
 
+impl HasModule for StaticLoc {
+    fn module(&self, _db: &dyn db::DefDatabase) -> ModuleId {
+        self.container
+    }
+}
+
 impl ModuleDefId {
     /// Returns the module containing `self` (or `self`, if `self` is itself a module).
     ///
@@ -608,7 +604,7 @@ impl ModuleDefId {
             ModuleDefId::AdtId(id) => id.module(db),
             ModuleDefId::EnumVariantId(id) => id.parent.lookup(db).container,
             ModuleDefId::ConstId(id) => id.lookup(db).container.module(db),
-            ModuleDefId::StaticId(id) => id.lookup(db).module(db),
+            ModuleDefId::StaticId(id) => id.lookup(db).container,
             ModuleDefId::TraitId(id) => id.lookup(db).container,
             ModuleDefId::TypeAliasId(id) => id.lookup(db).module(db),
             ModuleDefId::BuiltinType(_) => return None,
@@ -629,7 +625,6 @@ impl AttrDefId {
             AttrDefId::TraitId(it) => it.lookup(db).container.krate,
             AttrDefId::TypeAliasId(it) => it.lookup(db).module(db).krate,
             AttrDefId::ImplId(it) => it.lookup(db).container.krate,
-            AttrDefId::ExternBlockId(it) => it.lookup(db).container.krate,
             AttrDefId::GenericParamId(it) => {
                 match it {
                     GenericParamId::TypeParamId(it) => it.parent,
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 8c0ba3c056..ad4a4aa752 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -44,9 +44,9 @@ use crate::{
     path::{ImportAlias, ModPath, PathKind},
     per_ns::PerNs,
     visibility::{RawVisibility, Visibility},
-    AdtId, AstId, AstIdWithPath, ConstLoc, EnumLoc, EnumVariantId, ExternBlockLoc, FunctionLoc,
-    ImplLoc, Intern, ItemContainerId, LocalModuleId, ModuleDefId, StaticLoc, StructLoc, TraitLoc,
-    TypeAliasLoc, UnionLoc, UnresolvedMacro,
+    AdtId, AstId, AstIdWithPath, ConstLoc, EnumLoc, EnumVariantId, FunctionLoc, ImplLoc, Intern,
+    LocalModuleId, ModuleDefId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc,
+    UnresolvedMacro,
 };
 
 static GLOB_RECURSION_LIMIT: Limit = Limit::new(100);
@@ -213,7 +213,6 @@ struct MacroDirective {
     module_id: LocalModuleId,
     depth: usize,
     kind: MacroDirectiveKind,
-    container: ItemContainerId,
 }
 
 #[derive(Clone, Debug, Eq, PartialEq)]
@@ -307,7 +306,7 @@ impl DefCollector<'_> {
                 item_tree: &item_tree,
                 mod_dir: ModDir::root(),
             }
-            .collect_in_top_module(item_tree.top_level_items());
+            .collect(item_tree.top_level_items());
         }
     }
 
@@ -328,7 +327,7 @@ impl DefCollector<'_> {
                 item_tree: &item_tree,
                 mod_dir: ModDir::root(),
             }
-            .collect_in_top_module(item_tree.top_level_items());
+            .collect(item_tree.top_level_items());
         }
     }
 
@@ -434,7 +433,7 @@ impl DefCollector<'_> {
                     item_tree: &item_tree,
                     mod_dir,
                 }
-                .collect(&[*mod_item], directive.container);
+                .collect(&[*mod_item]);
                 true
             } else {
                 false
@@ -1054,12 +1053,7 @@ impl DefCollector<'_> {
                         &mut |_err| (),
                     );
                     if let Ok(Ok(call_id)) = call_id {
-                        resolved.push((
-                            directive.module_id,
-                            call_id,
-                            directive.depth,
-                            directive.container,
-                        ));
+                        resolved.push((directive.module_id, call_id, directive.depth));
                         res = ReachedFixedPoint::No;
                         return false;
                     }
@@ -1079,12 +1073,7 @@ impl DefCollector<'_> {
                             *derive_attr,
                         );
 
-                        resolved.push((
-                            directive.module_id,
-                            call_id,
-                            directive.depth,
-                            directive.container,
-                        ));
+                        resolved.push((directive.module_id, call_id, directive.depth));
                         res = ReachedFixedPoint::No;
                         return false;
                     }
@@ -1107,7 +1096,7 @@ impl DefCollector<'_> {
                             item_tree: &item_tree,
                             mod_dir,
                         }
-                        .collect(&[*mod_item], directive.container);
+                        .collect(&[*mod_item]);
                         res = ReachedFixedPoint::No;
                         false
                     };
@@ -1155,7 +1144,6 @@ impl DefCollector<'_> {
                                             ast_id,
                                             derive_attr: attr.id,
                                         },
-                                        container: directive.container,
                                     });
                                 }
                             }
@@ -1211,12 +1199,7 @@ impl DefCollector<'_> {
                                 .scope
                                 .add_attr_macro_invoc(ast_id, call_id);
 
-                            resolved.push((
-                                directive.module_id,
-                                call_id,
-                                directive.depth,
-                                directive.container,
-                            ));
+                            resolved.push((directive.module_id, call_id, directive.depth));
                             res = ReachedFixedPoint::No;
                             return false;
                         }
@@ -1230,8 +1213,8 @@ impl DefCollector<'_> {
         // Attribute resolution can add unresolved macro invocations, so concatenate the lists.
         self.unresolved_macros.extend(macros);
 
-        for (module_id, macro_call_id, depth, container) in resolved {
-            self.collect_macro_expansion(module_id, macro_call_id, depth, container);
+        for (module_id, macro_call_id, depth) in resolved {
+            self.collect_macro_expansion(module_id, macro_call_id, depth);
         }
 
         res
@@ -1242,7 +1225,6 @@ impl DefCollector<'_> {
         module_id: LocalModuleId,
         macro_call_id: MacroCallId,
         depth: usize,
-        container: ItemContainerId,
     ) {
         if EXPANSION_DEPTH_LIMIT.check(depth).is_err() {
             cov_mark::hit!(macro_expansion_overflow);
@@ -1294,7 +1276,7 @@ impl DefCollector<'_> {
             item_tree: &item_tree,
             mod_dir,
         }
-        .collect(item_tree.top_level_items(), container);
+        .collect(item_tree.top_level_items());
     }
 
     fn finish(mut self) -> DefMap {
@@ -1390,12 +1372,7 @@ struct ModCollector<'a, 'b> {
 }
 
 impl ModCollector<'_, '_> {
-    fn collect_in_top_module(&mut self, items: &[ModItem]) {
-        let module = self.def_collector.def_map.module_id(self.module_id);
-        self.collect(items, module.into())
-    }
-
-    fn collect(&mut self, items: &[ModItem], container: ItemContainerId) {
+    fn collect(&mut self, items: &[ModItem]) {
         struct DefData<'a> {
             id: ModuleDefId,
             name: &'a Name,
@@ -1446,7 +1423,7 @@ impl ModCollector<'_, '_> {
                 }
             }
 
-            if let Err(()) = self.resolve_attributes(&attrs, item, container) {
+            if let Err(()) = self.resolve_attributes(&attrs, item) {
                 // Do not process the item. It has at least one non-builtin attribute, so the
                 // fixed-point algorithm is required to resolve the rest of them.
                 continue;
@@ -1485,17 +1462,8 @@ impl ModCollector<'_, '_> {
                         status: PartialResolvedImport::Unresolved,
                     })
                 }
-                ModItem::ExternBlock(block) => self.collect(
-                    &self.item_tree[block].children,
-                    ItemContainerId::ExternBlockId(
-                        ExternBlockLoc {
-                            container: module,
-                            id: ItemTreeId::new(self.tree_id, block),
-                        }
-                        .intern(self.def_collector.db),
-                    ),
-                ),
-                ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac], container),
+                ModItem::ExternBlock(block) => self.collect(&self.item_tree[block].children),
+                ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac]),
                 ModItem::MacroRules(id) => self.collect_macro_rules(id),
                 ModItem::MacroDef(id) => self.collect_macro_def(id),
                 ModItem::Impl(imp) => {
@@ -1512,9 +1480,12 @@ impl ModCollector<'_, '_> {
                     self.collect_proc_macro_def(&func.name, ast_id, &attrs);
 
                     def = Some(DefData {
-                        id: FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }
-                            .intern(self.def_collector.db)
-                            .into(),
+                        id: FunctionLoc {
+                            container: module.into(),
+                            id: ItemTreeId::new(self.tree_id, id),
+                        }
+                        .intern(self.def_collector.db)
+                        .into(),
                         name: &func.name,
                         visibility: &self.item_tree[func.visibility],
                         has_constructor: false,
@@ -1558,8 +1529,11 @@ impl ModCollector<'_, '_> {
                 }
                 ModItem::Const(id) => {
                     let it = &self.item_tree[id];
-                    let const_id = ConstLoc { container, id: ItemTreeId::new(self.tree_id, id) }
-                        .intern(self.def_collector.db);
+                    let const_id = ConstLoc {
+                        container: module.into(),
+                        id: ItemTreeId::new(self.tree_id, id),
+                    }
+                    .intern(self.def_collector.db);
 
                     match &it.name {
                         Some(name) => {
@@ -1582,7 +1556,7 @@ impl ModCollector<'_, '_> {
                     let it = &self.item_tree[id];
 
                     def = Some(DefData {
-                        id: StaticLoc { container, id: ItemTreeId::new(self.tree_id, id) }
+                        id: StaticLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
                             .intern(self.def_collector.db)
                             .into(),
                         name: &it.name,
@@ -1606,9 +1580,12 @@ impl ModCollector<'_, '_> {
                     let it = &self.item_tree[id];
 
                     def = Some(DefData {
-                        id: TypeAliasLoc { container, id: ItemTreeId::new(self.tree_id, id) }
-                            .intern(self.def_collector.db)
-                            .into(),
+                        id: TypeAliasLoc {
+                            container: module.into(),
+                            id: ItemTreeId::new(self.tree_id, id),
+                        }
+                        .intern(self.def_collector.db)
+                        .into(),
                         name: &it.name,
                         visibility: &self.item_tree[it.visibility],
                         has_constructor: false,
@@ -1656,7 +1633,7 @@ impl ModCollector<'_, '_> {
                         item_tree: self.item_tree,
                         mod_dir,
                     }
-                    .collect_in_top_module(&*items);
+                    .collect(&*items);
                     if is_macro_use {
                         self.import_all_legacy_macros(module_id);
                     }
@@ -1689,7 +1666,7 @@ impl ModCollector<'_, '_> {
                                 item_tree: &item_tree,
                                 mod_dir,
                             }
-                            .collect_in_top_module(item_tree.top_level_items());
+                            .collect(item_tree.top_level_items());
                             let is_macro_use = is_macro_use
                                 || item_tree
                                     .top_level_attrs(db, self.def_collector.def_map.krate)
@@ -1757,12 +1734,7 @@ impl ModCollector<'_, '_> {
     ///
     /// If `ignore_up_to` is `Some`, attributes preceding and including that attribute will be
     /// assumed to be resolved already.
-    fn resolve_attributes(
-        &mut self,
-        attrs: &Attrs,
-        mod_item: ModItem,
-        container: ItemContainerId,
-    ) -> Result<(), ()> {
+    fn resolve_attributes(&mut self, attrs: &Attrs, mod_item: ModItem) -> Result<(), ()> {
         let mut ignore_up_to =
             self.def_collector.skip_attrs.get(&InFile::new(self.file_id(), mod_item)).copied();
         let iter = attrs
@@ -1805,7 +1777,6 @@ impl ModCollector<'_, '_> {
                     mod_item,
                     tree: self.tree_id,
                 },
-                container,
             });
 
             return Err(());
@@ -1980,7 +1951,7 @@ impl ModCollector<'_, '_> {
         );
     }
 
-    fn collect_macro_call(&mut self, mac: &MacroCall, container: ItemContainerId) {
+    fn collect_macro_call(&mut self, mac: &MacroCall) {
         let ast_id = AstIdWithPath::new(self.file_id(), mac.ast_id, ModPath::clone(&mac.path));
 
         // Case 1: try to resolve in legacy scope and expand macro_rules
@@ -2010,7 +1981,6 @@ impl ModCollector<'_, '_> {
                     self.module_id,
                     macro_call_id,
                     self.macro_depth + 1,
-                    container,
                 );
 
                 if let Some(err) = error {
@@ -2041,7 +2011,6 @@ impl ModCollector<'_, '_> {
             module_id: self.module_id,
             depth: self.macro_depth + 1,
             kind: MacroDirectiveKind::FnLike { ast_id, expand_to: mac.expand_to },
-            container,
         });
     }
 
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs
index 9f68b800a5..0cf28acf7f 100644
--- a/crates/hir_def/src/resolver.rs
+++ b/crates/hir_def/src/resolver.rs
@@ -8,7 +8,7 @@ use hir_expand::{
 };
 use indexmap::IndexMap;
 use rustc_hash::FxHashSet;
-use smallvec::{smallvec, SmallVec};
+use smallvec::SmallVec;
 
 use crate::{
     body::scope::{ExprScopes, ScopeId},
@@ -22,8 +22,8 @@ use crate::{
     path::{ModPath, PathKind},
     per_ns::PerNs,
     visibility::{RawVisibility, Visibility},
-    AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId,
-    FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
+    AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId,
+    EnumVariantId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, LifetimeParamId,
     LocalModuleId, Lookup, ModuleDefId, ModuleId, StaticId, StructId, TraitId, TypeAliasId,
     TypeParamId, VariantId,
 };
@@ -567,8 +567,6 @@ pub fn resolver_for_scope(
     let mut r = owner.resolver(db);
     let scopes = db.expr_scopes(owner);
     let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>();
-    r.scopes.reserve(scope_chain.len());
-
     for scope in scope_chain.into_iter().rev() {
         if let Some(block) = scopes.block(scope) {
             if let Some(def_map) = db.block_def_map(block) {
@@ -741,13 +739,12 @@ pub trait HasResolver: Copy {
 impl HasResolver for ModuleId {
     fn resolver(self, db: &dyn DefDatabase) -> Resolver {
         let mut def_map = self.def_map(db);
-        let mut modules: SmallVec<[_; 2]> = smallvec![(def_map.clone(), self.local_id)];
+        let mut modules = vec![(def_map.clone(), self.local_id)];
         while let Some(parent) = def_map.parent() {
             def_map = parent.def_map(db);
             modules.push((def_map.clone(), parent.local_id));
         }
         let mut resolver = Resolver::default();
-        resolver.scopes.reserve(modules.len());
         for (def_map, module) in modules.into_iter().rev() {
             resolver = resolver.push_module_scope(def_map, module);
         }
@@ -805,13 +802,6 @@ impl HasResolver for ImplId {
     }
 }
 
-impl HasResolver for ExternBlockId {
-    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
-        // Same as parent's
-        self.lookup(db).container.resolver(db)
-    }
-}
-
 impl HasResolver for DefWithBodyId {
     fn resolver(self, db: &dyn DefDatabase) -> Resolver {
         match self {
@@ -822,13 +812,12 @@ impl HasResolver for DefWithBodyId {
     }
 }
 
-impl HasResolver for ItemContainerId {
+impl HasResolver for AssocContainerId {
     fn resolver(self, db: &dyn DefDatabase) -> Resolver {
         match self {
-            ItemContainerId::ModuleId(it) => it.resolver(db),
-            ItemContainerId::TraitId(it) => it.resolver(db),
-            ItemContainerId::ImplId(it) => it.resolver(db),
-            ItemContainerId::ExternBlockId(it) => it.resolver(db),
+            AssocContainerId::ModuleId(it) => it.resolver(db),
+            AssocContainerId::TraitId(it) => it.resolver(db),
+            AssocContainerId::ImplId(it) => it.resolver(db),
         }
     }
 }
diff --git a/crates/hir_expand/Cargo.toml b/crates/hir_expand/Cargo.toml
index 380b7ef877..039861f7f7 100644
--- a/crates/hir_expand/Cargo.toml
+++ b/crates/hir_expand/Cargo.toml
@@ -16,6 +16,7 @@ either = "1.5.3"
 rustc-hash = "1.0.0"
 la-arena = { version = "0.3.0", path = "../../lib/arena" }
 itertools = "0.10.0"
+hashbrown = { version = "0.11", features = ["inline-more"], default-features = false }
 
 base_db = { path = "../base_db", version = "0.0.0" }
 cfg = { path = "../cfg", version = "0.0.0" }
diff --git a/crates/hir_expand/src/ast_id_map.rs b/crates/hir_expand/src/ast_id_map.rs
index 16cf299076..43c8a3db5c 100644
--- a/crates/hir_expand/src/ast_id_map.rs
+++ b/crates/hir_expand/src/ast_id_map.rs
@@ -8,12 +8,13 @@
 use std::{
     any::type_name,
     fmt,
-    hash::{Hash, Hasher},
+    hash::{BuildHasher, BuildHasherDefault, Hash, Hasher},
     marker::PhantomData,
 };
 
 use la_arena::{Arena, Idx};
 use profile::Count;
+use rustc_hash::FxHasher;
 use syntax::{ast, match_ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr};
 
 /// `AstId` points to an AST node in a specific file.
@@ -60,12 +61,28 @@ impl<N: AstNode> FileAstId<N> {
 type ErasedFileAstId = Idx<SyntaxNodePtr>;
 
 /// Maps items' `SyntaxNode`s to `ErasedFileAstId`s and back.
-#[derive(Debug, PartialEq, Eq, Default)]
+#[derive(Default)]
 pub struct AstIdMap {
+    /// Maps stable id to unstable ptr.
     arena: Arena<SyntaxNodePtr>,
+    /// Reverse: map ptr to id.
+    map: hashbrown::HashMap<Idx<SyntaxNodePtr>, (), ()>,
     _c: Count<Self>,
 }
 
+impl fmt::Debug for AstIdMap {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("AstIdMap").field("arena", &self.arena).finish()
+    }
+}
+
+impl PartialEq for AstIdMap {
+    fn eq(&self, other: &Self) -> bool {
+        self.arena == other.arena
+    }
+}
+impl Eq for AstIdMap {}
+
 impl AstIdMap {
     pub(crate) fn from_source(node: &SyntaxNode) -> AstIdMap {
         assert!(node.parent().is_none());
@@ -89,6 +106,16 @@ impl AstIdMap {
                 }
             }
         });
+        res.map = hashbrown::HashMap::with_capacity_and_hasher(res.arena.len(), ());
+        for (idx, ptr) in res.arena.iter() {
+            let hash = hash_ptr(ptr);
+            match res.map.raw_entry_mut().from_hash(hash, |idx2| *idx2 == idx) {
+                hashbrown::hash_map::RawEntryMut::Occupied(_) => unreachable!(),
+                hashbrown::hash_map::RawEntryMut::Vacant(entry) => {
+                    entry.insert_with_hasher(hash, idx, (), |&idx| hash_ptr(&res.arena[idx]));
+                }
+            }
+        }
         res
     }
 
@@ -98,8 +125,9 @@ impl AstIdMap {
     }
     fn erased_ast_id(&self, item: &SyntaxNode) -> ErasedFileAstId {
         let ptr = SyntaxNodePtr::new(item);
-        match self.arena.iter().find(|(_id, i)| **i == ptr) {
-            Some((it, _)) => it,
+        let hash = hash_ptr(&ptr);
+        match self.map.raw_entry().from_hash(hash, |&idx| self.arena[idx] == ptr) {
+            Some((&idx, &())) => idx,
             None => panic!(
                 "Can't find {:?} in AstIdMap:\n{:?}",
                 item,
@@ -117,6 +145,12 @@ impl AstIdMap {
     }
 }
 
+fn hash_ptr(ptr: &SyntaxNodePtr) -> u64 {
+    let mut hasher = BuildHasherDefault::<FxHasher>::default().build_hasher();
+    ptr.hash(&mut hasher);
+    hasher.finish()
+}
+
 /// Walks the subtree in bdfs order, calling `f` for each node. What is bdfs
 /// order? It is a mix of breadth-first and depth first orders. Nodes for which
 /// `f` returns true are visited breadth-first, all the other nodes are explored
diff --git a/crates/hir_expand/src/builtin_fn_macro.rs b/crates/hir_expand/src/builtin_fn_macro.rs
index 57e66e5cc4..3add4c1103 100644
--- a/crates/hir_expand/src/builtin_fn_macro.rs
+++ b/crates/hir_expand/src/builtin_fn_macro.rs
@@ -386,18 +386,7 @@ fn concat_expand(
 ) -> ExpandResult<Option<ExpandedEager>> {
     let mut err = None;
     let mut text = String::new();
-    for (i, mut t) in tt.token_trees.iter().enumerate() {
-        // FIXME: hack on top of a hack: `$e:expr` captures get surrounded in parentheses
-        // to ensure the right parsing order, so skip the parentheses here. Ideally we'd
-        // implement rustc's model. cc https://github.com/rust-analyzer/rust-analyzer/pull/10623
-        if let tt::TokenTree::Subtree(tt::Subtree { delimiter: Some(delim), token_trees }) = t {
-            if let [tt] = &**token_trees {
-                if delim.kind == tt::DelimiterKind::Parenthesis {
-                    t = tt;
-                }
-            }
-        }
-
+    for (i, t) in tt.token_trees.iter().enumerate() {
         match t {
             tt::TokenTree::Leaf(tt::Leaf::Literal(it)) if i % 2 == 0 => {
                 // concat works with string and char literals, so remove any quotes.
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs
index 23f81d3c7f..ab730b54bc 100644
--- a/crates/hir_expand/src/name.rs
+++ b/crates/hir_expand/src/name.rs
@@ -334,13 +334,6 @@ pub mod known {
         gt,
         le,
         lt,
-        // lang items
-        not,
-        neg,
-        future_trait,
-        owned_box,
-        index,
-        partial_ord
     );
 
     // self/Self cannot be used as an identifier
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index 5c6525c0f4..4ec8749f87 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -36,8 +36,8 @@ limit = { path = "../limit", version = "0.0.0" }
 test_utils = { path = "../test_utils" }
 expect-test = "1.2.0-pre.1"
 tracing = "0.1"
-tracing-subscriber = { version = "0.3", default-features = false, features = [
+tracing-subscriber = { version = "0.2", default-features = false, features = [
     "env-filter",
     "registry",
 ] }
-tracing-tree = "0.2"
+tracing-tree = { version = "0.1.10" }
diff --git a/crates/hir_ty/src/autoderef.rs b/crates/hir_ty/src/autoderef.rs
index 2d3d16cda0..1eb5490507 100644
--- a/crates/hir_ty/src/autoderef.rs
+++ b/crates/hir_ty/src/autoderef.rs
@@ -10,7 +10,6 @@ use chalk_ir::{cast::Cast, fold::Fold, interner::HasInterner, VariableKind};
 use hir_def::lang_item::LangItemTarget;
 use hir_expand::name::name;
 use limit::Limit;
-use syntax::SmolStr;
 use tracing::{info, warn};
 
 use crate::{
@@ -72,10 +71,7 @@ impl Iterator for Autoderef<'_> {
         }
 
         let (kind, new_ty) = if let Some(derefed) = builtin_deref(&self.ty.value) {
-            (
-                AutoderefKind::Builtin,
-                Canonical { value: derefed.clone(), binders: self.ty.binders.clone() },
-            )
+            (AutoderefKind::Builtin, Canonical { value: derefed, binders: self.ty.binders.clone() })
         } else {
             (
                 AutoderefKind::Overloaded,
@@ -114,17 +110,15 @@ pub(crate) fn deref(
 ) -> Option<Canonical<Ty>> {
     let _p = profile::span("deref");
     match builtin_deref(&ty.goal.value) {
-        Some(derefed) => {
-            Some(Canonical { value: derefed.clone(), binders: ty.goal.binders.clone() })
-        }
+        Some(derefed) => Some(Canonical { value: derefed, binders: ty.goal.binders.clone() }),
         None => deref_by_trait(db, krate, ty),
     }
 }
 
-fn builtin_deref(ty: &Ty) -> Option<&Ty> {
+fn builtin_deref(ty: &Ty) -> Option<Ty> {
     match ty.kind(&Interner) {
-        TyKind::Ref(.., ty) => Some(ty),
-        TyKind::Raw(.., ty) => Some(ty),
+        TyKind::Ref(.., ty) => Some(ty.clone()),
+        TyKind::Raw(.., ty) => Some(ty.clone()),
         _ => None,
     }
 }
@@ -135,7 +129,7 @@ fn deref_by_trait(
     ty: InEnvironment<&Canonical<Ty>>,
 ) -> Option<Canonical<Ty>> {
     let _p = profile::span("deref_by_trait");
-    let deref_trait = match db.lang_item(krate, SmolStr::new_inline("deref"))? {
+    let deref_trait = match db.lang_item(krate, "deref".into())? {
         LangItemTarget::TraitId(it) => it,
         _ => return None,
     };
diff --git a/crates/hir_ty/src/chalk_db.rs b/crates/hir_ty/src/chalk_db.rs
index 4a7b2d7363..f58339286f 100644
--- a/crates/hir_ty/src/chalk_db.rs
+++ b/crates/hir_ty/src/chalk_db.rs
@@ -3,7 +3,6 @@
 use std::sync::Arc;
 
 use cov_mark::hit;
-use syntax::SmolStr;
 use tracing::debug;
 
 use chalk_ir::{cast::Cast, fold::shift::Shift, CanonicalVarKinds};
@@ -12,7 +11,7 @@ use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
 use base_db::CrateId;
 use hir_def::{
     lang_item::{lang_attr, LangItemTarget},
-    AssocItemId, GenericDefId, HasModule, ItemContainerId, Lookup, ModuleId, TypeAliasId,
+    AssocContainerId, AssocItemId, GenericDefId, HasModule, Lookup, ModuleId, TypeAliasId,
 };
 use hir_expand::name::name;
 
@@ -214,7 +213,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
             crate::ImplTraitId::AsyncBlockTypeImplTrait(..) => {
                 if let Some((future_trait, future_output)) = self
                     .db
-                    .lang_item(self.krate, SmolStr::new_inline("future_trait"))
+                    .lang_item(self.krate, "future_trait".into())
                     .and_then(|item| item.as_trait())
                     .and_then(|trait_| {
                         let alias =
@@ -397,7 +396,7 @@ pub(crate) fn associated_ty_data_query(
     debug!("associated_ty_data {:?}", id);
     let type_alias: TypeAliasId = from_assoc_type_id(id);
     let trait_ = match type_alias.lookup(db.upcast()).container {
-        ItemContainerId::TraitId(t) => t,
+        AssocContainerId::TraitId(t) => t,
         _ => panic!("associated type not in trait"),
     };
 
@@ -420,7 +419,7 @@ pub(crate) fn associated_ty_data_query(
     if !ctx.unsized_types.borrow().contains(&self_ty) {
         let sized_trait = resolver
             .krate()
-            .and_then(|krate| db.lang_item(krate, SmolStr::new_inline("sized")))
+            .and_then(|krate| db.lang_item(krate, "sized".into()))
             .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
         let sized_bound = sized_trait.into_iter().map(|sized_trait| {
             let trait_bound =
@@ -635,7 +634,7 @@ fn type_alias_associated_ty_value(
 ) -> Arc<AssociatedTyValue> {
     let type_alias_data = db.type_alias_data(type_alias);
     let impl_id = match type_alias.lookup(db.upcast()).container {
-        ItemContainerId::ImplId(it) => it,
+        AssocContainerId::ImplId(it) => it,
         _ => panic!("assoc ty value should be in impl"),
     };
 
diff --git a/crates/hir_ty/src/chalk_ext.rs b/crates/hir_ty/src/chalk_ext.rs
index 97d1ad0f9c..36c56820eb 100644
--- a/crates/hir_ty/src/chalk_ext.rs
+++ b/crates/hir_ty/src/chalk_ext.rs
@@ -4,9 +4,8 @@ use chalk_ir::{FloatTy, IntTy, Mutability, Scalar, UintTy};
 use hir_def::{
     builtin_type::{BuiltinFloat, BuiltinInt, BuiltinType, BuiltinUint},
     type_ref::Rawness,
-    FunctionId, GenericDefId, HasModule, ItemContainerId, Lookup, TraitId,
+    AssocContainerId, FunctionId, GenericDefId, HasModule, Lookup, TraitId,
 };
-use syntax::SmolStr;
 
 use crate::{
     db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
@@ -188,7 +187,7 @@ impl TyExt for Ty {
                     ImplTraitId::AsyncBlockTypeImplTrait(def, _expr) => {
                         let krate = def.module(db.upcast()).krate();
                         if let Some(future_trait) = db
-                            .lang_item(krate, SmolStr::new_inline("future_trait"))
+                            .lang_item(krate, "future_trait".into())
                             .and_then(|item| item.as_trait())
                         {
                             // This is only used by type walking.
@@ -269,7 +268,7 @@ impl TyExt for Ty {
         match self.kind(&Interner) {
             TyKind::AssociatedType(id, ..) => {
                 match from_assoc_type_id(*id).lookup(db.upcast()).container {
-                    ItemContainerId::TraitId(trait_id) => Some(trait_id),
+                    AssocContainerId::TraitId(trait_id) => Some(trait_id),
                     _ => None,
                 }
             }
@@ -278,7 +277,7 @@ impl TyExt for Ty {
                     .lookup(db.upcast())
                     .container
                 {
-                    ItemContainerId::TraitId(trait_id) => Some(trait_id),
+                    AssocContainerId::TraitId(trait_id) => Some(trait_id),
                     _ => None,
                 }
             }
@@ -332,7 +331,7 @@ impl ProjectionTyExt for ProjectionTy {
 
     fn trait_(&self, db: &dyn HirDatabase) -> TraitId {
         match from_assoc_type_id(self.associated_ty_id).lookup(db.upcast()).container {
-            ItemContainerId::TraitId(it) => it,
+            AssocContainerId::TraitId(it) => it,
             _ => panic!("projection ty without parent trait"),
         }
     }
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs
index a1e7198bc2..6a3588dc74 100644
--- a/crates/hir_ty/src/diagnostics/decl_check.rs
+++ b/crates/hir_ty/src/diagnostics/decl_check.rs
@@ -178,7 +178,6 @@ impl<'a> DeclValidator<'a> {
                 AttrDefId::ConstId(cid) => Some(cid.lookup(self.db.upcast()).container.into()),
                 AttrDefId::TraitId(tid) => Some(tid.lookup(self.db.upcast()).container.into()),
                 AttrDefId::ImplId(iid) => Some(iid.lookup(self.db.upcast()).container.into()),
-                AttrDefId::ExternBlockId(id) => Some(id.lookup(self.db.upcast()).container.into()),
                 // These warnings should not explore macro definitions at all
                 AttrDefId::MacroDefId(_) => None,
                 // Will never occur under an enum/struct/union/type alias
diff --git a/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs b/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs
index f268746809..f9439c706e 100644
--- a/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs
+++ b/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs
@@ -50,7 +50,6 @@ use std::{
 use hir_def::{EnumVariantId, HasModule, LocalFieldId, VariantId};
 use smallvec::{smallvec, SmallVec};
 use stdx::never;
-use syntax::SmolStr;
 
 use crate::{AdtId, Interner, Scalar, Ty, TyExt, TyKind};
 
@@ -906,7 +905,7 @@ fn is_field_list_non_exhaustive(variant_id: VariantId, cx: &MatchCheckCtx<'_>) -
 
 fn adt_is_box(adt: hir_def::AdtId, cx: &MatchCheckCtx<'_>) -> bool {
     use hir_def::lang_item::LangItemTarget;
-    match cx.db.lang_item(cx.module.krate(), SmolStr::new_inline("owned_box")) {
+    match cx.db.lang_item(cx.module.krate(), "owned_box".into()) {
         Some(LangItemTarget::StructId(box_id)) => adt == box_id.into(),
         _ => false,
     }
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index c09f8db86e..e2b4e92575 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -16,11 +16,10 @@ use hir_def::{
     path::{Path, PathKind},
     type_ref::{TraitBoundModifier, TypeBound, TypeRef},
     visibility::Visibility,
-    HasModule, ItemContainerId, Lookup, ModuleId, TraitId,
+    AssocContainerId, HasModule, Lookup, ModuleId, TraitId,
 };
 use hir_expand::{hygiene::Hygiene, name::Name};
 use itertools::Itertools;
-use syntax::SmolStr;
 
 use crate::{
     const_from_placeholder_idx,
@@ -577,7 +576,7 @@ impl HirDisplay for Ty {
             TyKind::AssociatedType(assoc_type_id, parameters) => {
                 let type_alias = from_assoc_type_id(*assoc_type_id);
                 let trait_ = match type_alias.lookup(f.db.upcast()).container {
-                    ItemContainerId::TraitId(it) => it,
+                    AssocContainerId::TraitId(it) => it,
                     _ => panic!("not an associated type"),
                 };
                 let trait_ = f.db.trait_data(trait_);
@@ -775,9 +774,8 @@ impl SizedByDefault {
         match self {
             Self::NotSized => false,
             Self::Sized { anchor } => {
-                let sized_trait = db
-                    .lang_item(anchor, SmolStr::new_inline("sized"))
-                    .and_then(|lang_item| lang_item.as_trait());
+                let sized_trait =
+                    db.lang_item(anchor, "sized".into()).and_then(|lang_item| lang_item.as_trait());
                 Some(trait_) == sized_trait
             }
         }
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index ce6cb81540..d07a939583 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -28,10 +28,11 @@ use hir_def::{
     AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule, Lookup,
     TraitId, TypeAliasId, VariantId,
 };
-use hir_expand::name::{name, Name};
+use hir_expand::name::name;
 use la_arena::ArenaMap;
 use rustc_hash::FxHashMap;
 use stdx::impl_from;
+use syntax::SmolStr;
 
 use crate::{
     db::HirDatabase, fold_tys, infer::coerce::CoerceMany, lower::ImplTraitLoweringMode,
@@ -520,7 +521,7 @@ impl<'a> InferenceContext<'a> {
         match assoc_ty {
             Some(res_assoc_ty) => {
                 let trait_ = match res_assoc_ty.lookup(self.db.upcast()).container {
-                    hir_def::ItemContainerId::TraitId(trait_) => trait_,
+                    hir_def::AssocContainerId::TraitId(trait_) => trait_,
                     _ => panic!("resolve_associated_type called with non-associated type"),
                 };
                 let ty = self.table.new_type_var();
@@ -718,9 +719,10 @@ impl<'a> InferenceContext<'a> {
         self.infer_expr_coerce(self.body.body_expr, &Expectation::has_type(self.return_ty.clone()));
     }
 
-    fn resolve_lang_item(&self, name: Name) -> Option<LangItemTarget> {
+    fn resolve_lang_item(&self, name: &str) -> Option<LangItemTarget> {
         let krate = self.resolver.krate()?;
-        self.db.lang_item(krate, name.to_smol_str())
+        let name = SmolStr::new_inline(name);
+        self.db.lang_item(krate, name)
     }
 
     fn resolve_into_iter_item(&self) -> Option<TypeAliasId> {
@@ -741,22 +743,22 @@ impl<'a> InferenceContext<'a> {
     }
 
     fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> {
-        let trait_ = self.resolve_lang_item(name![neg])?.as_trait()?;
+        let trait_ = self.resolve_lang_item("neg")?.as_trait()?;
         self.db.trait_data(trait_).associated_type_by_name(&name![Output])
     }
 
     fn resolve_ops_not_output(&self) -> Option<TypeAliasId> {
-        let trait_ = self.resolve_lang_item(name![not])?.as_trait()?;
+        let trait_ = self.resolve_lang_item("not")?.as_trait()?;
         self.db.trait_data(trait_).associated_type_by_name(&name![Output])
     }
 
     fn resolve_future_future_output(&self) -> Option<TypeAliasId> {
-        let trait_ = self.resolve_lang_item(name![future_trait])?.as_trait()?;
+        let trait_ = self.resolve_lang_item("future_trait")?.as_trait()?;
         self.db.trait_data(trait_).associated_type_by_name(&name![Output])
     }
 
     fn resolve_boxed_box(&self) -> Option<AdtId> {
-        let struct_ = self.resolve_lang_item(name![owned_box])?.as_struct()?;
+        let struct_ = self.resolve_lang_item("owned_box")?.as_struct()?;
         Some(struct_.into())
     }
 
@@ -797,7 +799,7 @@ impl<'a> InferenceContext<'a> {
     }
 
     fn resolve_ops_index(&self) -> Option<TraitId> {
-        self.resolve_lang_item(name![index])?.as_trait()
+        self.resolve_lang_item("index")?.as_trait()
     }
 
     fn resolve_ops_index_output(&self) -> Option<TypeAliasId> {
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs
index aebff59113..4d7ac6fd85 100644
--- a/crates/hir_ty/src/infer/coerce.rs
+++ b/crates/hir_ty/src/infer/coerce.rs
@@ -10,7 +10,6 @@ use std::iter;
 use chalk_ir::{cast::Cast, Goal, Mutability, TyVariableKind};
 use hir_def::{expr::ExprId, lang_item::LangItemTarget};
 use stdx::always;
-use syntax::SmolStr;
 
 use crate::{
     autoderef::{Autoderef, AutoderefKind},
@@ -537,11 +536,10 @@ impl<'a> InferenceContext<'a> {
             reborrow.as_ref().map_or_else(|| from_ty.clone(), |(_, adj)| adj.target.clone());
 
         let krate = self.resolver.krate().unwrap();
-        let coerce_unsized_trait =
-            match self.db.lang_item(krate, SmolStr::new_inline("coerce_unsized")) {
-                Some(LangItemTarget::TraitId(trait_)) => trait_,
-                _ => return Err(TypeError),
-            };
+        let coerce_unsized_trait = match self.db.lang_item(krate, "coerce_unsized".into()) {
+            Some(LangItemTarget::TraitId(trait_)) => trait_,
+            _ => return Err(TypeError),
+        };
 
         let coerce_unsized_tref = {
             let b = TyBuilder::trait_ref(self.db, coerce_unsized_trait);
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 2b8dc793cc..5fb227c0e4 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -14,7 +14,7 @@ use hir_def::{
     },
     path::{GenericArg, GenericArgs},
     resolver::resolver_for_expr,
-    FieldId, FunctionId, ItemContainerId, Lookup,
+    AssocContainerId, FieldId, FunctionId, Lookup,
 };
 use hir_expand::name::{name, Name};
 use stdx::always;
@@ -1167,7 +1167,8 @@ impl<'a> InferenceContext<'a> {
             // add obligation for trait implementation, if this is a trait method
             match def {
                 CallableDefId::FunctionId(f) => {
-                    if let ItemContainerId::TraitId(trait_) = f.lookup(self.db.upcast()).container {
+                    if let AssocContainerId::TraitId(trait_) = f.lookup(self.db.upcast()).container
+                    {
                         // construct a TraitRef
                         let substs = crate::subst_prefix(
                             &*parameters,
@@ -1276,43 +1277,41 @@ impl<'a> InferenceContext<'a> {
         let (name, lang_item) = match op {
             BinaryOp::LogicOp(_) => return None,
             BinaryOp::ArithOp(aop) => match aop {
-                ArithOp::Add => (name!(add), name!(add)),
-                ArithOp::Mul => (name!(mul), name!(mul)),
-                ArithOp::Sub => (name!(sub), name!(sub)),
-                ArithOp::Div => (name!(div), name!(div)),
-                ArithOp::Rem => (name!(rem), name!(rem)),
-                ArithOp::Shl => (name!(shl), name!(shl)),
-                ArithOp::Shr => (name!(shr), name!(shr)),
-                ArithOp::BitXor => (name!(bitxor), name!(bitxor)),
-                ArithOp::BitOr => (name!(bitor), name!(bitor)),
-                ArithOp::BitAnd => (name!(bitand), name!(bitand)),
+                ArithOp::Add => (name!(add), "add"),
+                ArithOp::Mul => (name!(mul), "mul"),
+                ArithOp::Sub => (name!(sub), "sub"),
+                ArithOp::Div => (name!(div), "div"),
+                ArithOp::Rem => (name!(rem), "rem"),
+                ArithOp::Shl => (name!(shl), "shl"),
+                ArithOp::Shr => (name!(shr), "shr"),
+                ArithOp::BitXor => (name!(bitxor), "bitxor"),
+                ArithOp::BitOr => (name!(bitor), "bitor"),
+                ArithOp::BitAnd => (name!(bitand), "bitand"),
             },
             BinaryOp::Assignment { op: Some(aop) } => match aop {
-                ArithOp::Add => (name!(add_assign), name!(add_assign)),
-                ArithOp::Mul => (name!(mul_assign), name!(mul_assign)),
-                ArithOp::Sub => (name!(sub_assign), name!(sub_assign)),
-                ArithOp::Div => (name!(div_assign), name!(div_assign)),
-                ArithOp::Rem => (name!(rem_assign), name!(rem_assign)),
-                ArithOp::Shl => (name!(shl_assign), name!(shl_assign)),
-                ArithOp::Shr => (name!(shr_assign), name!(shr_assign)),
-                ArithOp::BitXor => (name!(bitxor_assign), name!(bitxor_assign)),
-                ArithOp::BitOr => (name!(bitor_assign), name!(bitor_assign)),
-                ArithOp::BitAnd => (name!(bitand_assign), name!(bitand_assign)),
+                ArithOp::Add => (name!(add_assign), "add_assign"),
+                ArithOp::Mul => (name!(mul_assign), "mul_assign"),
+                ArithOp::Sub => (name!(sub_assign), "sub_assign"),
+                ArithOp::Div => (name!(div_assign), "div_assign"),
+                ArithOp::Rem => (name!(rem_assign), "rem_assign"),
+                ArithOp::Shl => (name!(shl_assign), "shl_assign"),
+                ArithOp::Shr => (name!(shr_assign), "shr_assign"),
+                ArithOp::BitXor => (name!(bitxor_assign), "bitxor_assign"),
+                ArithOp::BitOr => (name!(bitor_assign), "bitor_assign"),
+                ArithOp::BitAnd => (name!(bitand_assign), "bitand_assign"),
             },
             BinaryOp::CmpOp(cop) => match cop {
-                CmpOp::Eq { negated: false } => (name!(eq), name!(eq)),
-                CmpOp::Eq { negated: true } => (name!(ne), name!(eq)),
+                CmpOp::Eq { negated: false } => (name!(eq), "eq"),
+                CmpOp::Eq { negated: true } => (name!(ne), "eq"),
                 CmpOp::Ord { ordering: Ordering::Less, strict: false } => {
-                    (name!(le), name!(partial_ord))
-                }
-                CmpOp::Ord { ordering: Ordering::Less, strict: true } => {
-                    (name!(lt), name!(partial_ord))
+                    (name!(le), "partial_ord")
                 }
+                CmpOp::Ord { ordering: Ordering::Less, strict: true } => (name!(lt), "partial_ord"),
                 CmpOp::Ord { ordering: Ordering::Greater, strict: false } => {
-                    (name!(ge), name!(partial_ord))
+                    (name!(ge), "partial_ord")
                 }
                 CmpOp::Ord { ordering: Ordering::Greater, strict: true } => {
-                    (name!(gt), name!(partial_ord))
+                    (name!(gt), "partial_ord")
                 }
             },
             BinaryOp::Assignment { op: None } => return None,
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs
index a84501fa54..056cdb5d5b 100644
--- a/crates/hir_ty/src/infer/path.rs
+++ b/crates/hir_ty/src/infer/path.rs
@@ -6,7 +6,7 @@ use chalk_ir::cast::Cast;
 use hir_def::{
     path::{Path, PathSegment},
     resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs},
-    AdtId, AssocItemId, EnumVariantId, ItemContainerId, Lookup,
+    AdtId, AssocContainerId, AssocItemId, EnumVariantId, Lookup,
 };
 use hir_expand::name::Name;
 
@@ -241,7 +241,7 @@ impl<'a> InferenceContext<'a> {
                     AssocItemId::TypeAliasId(_) => unreachable!(),
                 };
                 let substs = match container {
-                    ItemContainerId::ImplId(impl_id) => {
+                    AssocContainerId::ImplId(impl_id) => {
                         let impl_substs = TyBuilder::subst_for_def(self.db, impl_id)
                             .fill(iter::repeat_with(|| self.table.new_type_var()))
                             .build();
@@ -250,7 +250,7 @@ impl<'a> InferenceContext<'a> {
                         self.unify(&impl_self_ty, &ty);
                         Some(impl_substs)
                     }
-                    ItemContainerId::TraitId(trait_) => {
+                    AssocContainerId::TraitId(trait_) => {
                         // we're picking this method
                         let trait_ref = TyBuilder::trait_ref(self.db, trait_)
                             .push(ty.clone())
@@ -259,7 +259,7 @@ impl<'a> InferenceContext<'a> {
                         self.push_obligation(trait_ref.clone().cast(&Interner));
                         Some(trait_ref.substitution)
                     }
-                    ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
+                    AssocContainerId::ModuleId(_) => None,
                 };
 
                 self.write_assoc_resolution(id, item);
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 7373c9eb8b..af1d5fdb6a 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -19,8 +19,8 @@ use hir_def::{
     path::{GenericArg, Path, PathSegment, PathSegments},
     resolver::{HasResolver, Resolver, TypeNs},
     type_ref::{TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef},
-    AdtId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId,
-    HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
+    AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId,
+    GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
     TypeAliasId, TypeParamId, UnionId, VariantId,
 };
 use hir_expand::{name::Name, ExpandResult};
@@ -28,7 +28,7 @@ use la_arena::ArenaMap;
 use rustc_hash::FxHashSet;
 use smallvec::SmallVec;
 use stdx::impl_from;
-use syntax::{ast, SmolStr};
+use syntax::ast;
 
 use crate::all_super_traits;
 use crate::{
@@ -96,9 +96,9 @@ impl<'a> TyLoweringContext<'a> {
         debruijn: DebruijnIndex,
         f: impl FnOnce(&TyLoweringContext) -> T,
     ) -> T {
-        let opaque_ty_data_vec = self.opaque_type_data.take();
-        let expander = self.expander.take();
-        let unsized_types = self.unsized_types.take();
+        let opaque_ty_data_vec = self.opaque_type_data.replace(Vec::new());
+        let expander = self.expander.replace(None);
+        let unsized_types = self.unsized_types.replace(Default::default());
         let new_ctx = Self {
             in_binders: debruijn,
             impl_trait_counter: Cell::new(self.impl_trait_counter.get()),
@@ -615,7 +615,7 @@ impl<'a> TyLoweringContext<'a> {
                 // `Option::None::<T>` are both allowed (though the former is
                 // preferred). See also `def_ids_for_path_segments` in rustc.
                 let len = path.segments().len();
-                let penultimate = len.checked_sub(2).and_then(|idx| path.segments().get(idx));
+                let penultimate = if len >= 2 { path.segments().get(len - 2) } else { None };
                 let segment = match penultimate {
                     Some(segment) if segment.args_and_bindings.is_some() => segment,
                     _ => last,
@@ -797,7 +797,7 @@ impl<'a> TyLoweringContext<'a> {
                 let sized_trait = self
                     .resolver
                     .krate()
-                    .and_then(|krate| self.db.lang_item(krate, SmolStr::new_inline("sized")))
+                    .and_then(|krate| self.db.lang_item(krate, "sized".into()))
                     .and_then(|lang_item| lang_item.as_trait());
                 // Don't lower associated type bindings as the only possible relaxed trait bound
                 // `?Sized` has no of them.
@@ -841,8 +841,8 @@ impl<'a> TyLoweringContext<'a> {
         };
         last_segment
             .into_iter()
-            .filter_map(|segment| segment.args_and_bindings)
-            .flat_map(|args_and_bindings| &args_and_bindings.bindings)
+            .flat_map(|segment| segment.args_and_bindings.into_iter())
+            .flat_map(|args_and_bindings| args_and_bindings.bindings.iter())
             .flat_map(move |binding| {
                 let found = associated_type_by_name_including_super_traits(
                     self.db,
@@ -850,14 +850,14 @@ impl<'a> TyLoweringContext<'a> {
                     &binding.name,
                 );
                 let (super_trait_ref, associated_ty) = match found {
-                    None => return SmallVec::new(),
+                    None => return SmallVec::<[QuantifiedWhereClause; 1]>::new(),
                     Some(t) => t,
                 };
                 let projection_ty = ProjectionTy {
                     associated_ty_id: to_assoc_type_id(associated_ty),
                     substitution: super_trait_ref.substitution,
                 };
-                let mut preds: SmallVec<[_; 1]> = SmallVec::with_capacity(
+                let mut preds = SmallVec::with_capacity(
                     binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
                 );
                 if let Some(type_ref) = &binding.type_ref {
@@ -895,7 +895,7 @@ impl<'a> TyLoweringContext<'a> {
                 let krate = func.lookup(ctx.db.upcast()).module(ctx.db.upcast()).krate();
                 let sized_trait = ctx
                     .db
-                    .lang_item(krate, SmolStr::new_inline("sized"))
+                    .lang_item(krate, "sized".into())
                     .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
                 let sized_clause = sized_trait.map(|trait_id| {
                     let clause = WhereClause::Implemented(TraitRef {
@@ -1125,7 +1125,7 @@ pub(crate) fn trait_environment_query(
         }
     }
 
-    let container: Option<ItemContainerId> = match def {
+    let container: Option<AssocContainerId> = match def {
         // FIXME: is there a function for this?
         GenericDefId::FunctionId(f) => Some(f.lookup(db.upcast()).container),
         GenericDefId::AdtId(_) => None,
@@ -1135,7 +1135,7 @@ pub(crate) fn trait_environment_query(
         GenericDefId::EnumVariantId(_) => None,
         GenericDefId::ConstId(c) => Some(c.lookup(db.upcast()).container),
     };
-    if let Some(ItemContainerId::TraitId(trait_id)) = container {
+    if let Some(AssocContainerId::TraitId(trait_id)) = container {
         // add `Self: Trait<T1, T2, ...>` to the environment in trait
         // function default implementations (and speculative code
         // inside consts or type aliases)
@@ -1200,7 +1200,7 @@ fn implicitly_sized_clauses<'a>(
     let generic_args = &substitution.as_slice(&Interner)[is_trait_def as usize..];
     let sized_trait = resolver
         .krate()
-        .and_then(|krate| db.lang_item(krate, SmolStr::new_inline("sized")))
+        .and_then(|krate| db.lang_item(krate, "sized".into()))
         .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
 
     sized_trait.into_iter().flat_map(move |sized_trait| {
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index 1549a40c91..8e19928746 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -8,9 +8,8 @@ use arrayvec::ArrayVec;
 use base_db::{CrateId, Edition};
 use chalk_ir::{cast::Cast, Mutability, UniverseIndex};
 use hir_def::{
-    item_scope::ItemScope, lang_item::LangItemTarget, nameres::DefMap, AssocItemId, BlockId,
-    ConstId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId,
-    ModuleId, TraitId,
+    lang_item::LangItemTarget, nameres::DefMap, AssocContainerId, AssocItemId, BlockId, FunctionId,
+    GenericDefId, HasModule, ImplId, Lookup, ModuleId, TraitId,
 };
 use hir_expand::name::Name;
 use rustc_hash::{FxHashMap, FxHashSet};
@@ -142,7 +141,6 @@ impl TraitImpls {
 
         let crate_def_map = db.crate_def_map(krate);
         impls.collect_def_map(db, &crate_def_map);
-        impls.shrink_to_fit();
 
         Arc::new(impls)
     }
@@ -156,32 +154,10 @@ impl TraitImpls {
 
         let block_def_map = db.block_def_map(block)?;
         impls.collect_def_map(db, &block_def_map);
-        impls.shrink_to_fit();
 
         Some(Arc::new(impls))
     }
 
-    pub(crate) fn trait_impls_in_deps_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
-        let _p = profile::span("trait_impls_in_deps_query");
-        let crate_graph = db.crate_graph();
-        let mut res = Self { map: FxHashMap::default() };
-
-        for krate in crate_graph.transitive_deps(krate) {
-            res.merge(&db.trait_impls_in_crate(krate));
-        }
-        res.shrink_to_fit();
-
-        Arc::new(res)
-    }
-
-    fn shrink_to_fit(&mut self) {
-        self.map.shrink_to_fit();
-        self.map.values_mut().for_each(|map| {
-            map.shrink_to_fit();
-            map.values_mut().for_each(Vec::shrink_to_fit);
-        });
-    }
-
     fn collect_def_map(&mut self, db: &dyn HirDatabase, def_map: &DefMap) {
         for (_module_id, module_data) in def_map.modules() {
             for impl_id in module_data.scope.impls() {
@@ -201,7 +177,7 @@ impl TraitImpls {
 
             // To better support custom derives, collect impls in all unnamed const items.
             // const _: () = { ... };
-            for konst in collect_unnamed_consts(db, &module_data.scope) {
+            for konst in module_data.scope.unnamed_consts() {
                 let body = db.body(konst.into());
                 for (_, block_def_map) in body.blocks(db.upcast()) {
                     self.collect_def_map(db, &block_def_map);
@@ -210,6 +186,18 @@ impl TraitImpls {
         }
     }
 
+    pub(crate) fn trait_impls_in_deps_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
+        let _p = profile::span("trait_impls_in_deps_query");
+        let crate_graph = db.crate_graph();
+        let mut res = Self { map: FxHashMap::default() };
+
+        for krate in crate_graph.transitive_deps(krate) {
+            res.merge(&db.trait_impls_in_crate(krate));
+        }
+
+        Arc::new(res)
+    }
+
     fn merge(&mut self, other: &Self) {
         for (trait_, other_map) in &other.map {
             let map = self.map.entry(*trait_).or_default();
@@ -275,7 +263,6 @@ impl InherentImpls {
 
         let crate_def_map = db.crate_def_map(krate);
         impls.collect_def_map(db, &crate_def_map);
-        impls.shrink_to_fit();
 
         return Arc::new(impls);
     }
@@ -287,17 +274,11 @@ impl InherentImpls {
         let mut impls = Self { map: FxHashMap::default() };
         if let Some(block_def_map) = db.block_def_map(block) {
             impls.collect_def_map(db, &block_def_map);
-            impls.shrink_to_fit();
             return Some(Arc::new(impls));
         }
         return None;
     }
 
-    fn shrink_to_fit(&mut self) {
-        self.map.values_mut().for_each(Vec::shrink_to_fit);
-        self.map.shrink_to_fit();
-    }
-
     fn collect_def_map(&mut self, db: &dyn HirDatabase, def_map: &DefMap) {
         for (_module_id, module_data) in def_map.modules() {
             for impl_id in module_data.scope.impls() {
@@ -316,7 +297,7 @@ impl InherentImpls {
 
             // To better support custom derives, collect impls in all unnamed const items.
             // const _: () = { ... };
-            for konst in collect_unnamed_consts(db, &module_data.scope) {
+            for konst in module_data.scope.unnamed_consts() {
                 let body = db.body(konst.into());
                 for (_, block_def_map) in body.blocks(db.upcast()) {
                     self.collect_def_map(db, &block_def_map);
@@ -337,34 +318,6 @@ impl InherentImpls {
     }
 }
 
-fn collect_unnamed_consts<'a>(
-    db: &'a dyn HirDatabase,
-    scope: &'a ItemScope,
-) -> impl Iterator<Item = ConstId> + 'a {
-    let unnamed_consts = scope.unnamed_consts();
-
-    // FIXME: Also treat consts named `_DERIVE_*` as unnamed, since synstructure generates those.
-    // Should be removed once synstructure stops doing that.
-    let synstructure_hack_consts = scope.values().filter_map(|(item, _)| match item {
-        ModuleDefId::ConstId(id) => {
-            let loc = id.lookup(db.upcast());
-            let item_tree = loc.id.item_tree(db.upcast());
-            if item_tree[loc.id.value]
-                .name
-                .as_ref()
-                .map_or(false, |n| n.to_smol_str().starts_with("_DERIVE_"))
-            {
-                Some(id)
-            } else {
-                None
-            }
-        }
-        _ => None,
-    });
-
-    unnamed_consts.chain(synstructure_hack_consts)
-}
-
 pub fn def_crates(
     db: &dyn HirDatabase,
     ty: &Ty,
@@ -541,10 +494,9 @@ pub fn iterate_method_candidates_dyn(
             // types*.
 
             let deref_chain = autoderef_method_receiver(db, krate, ty);
-            let mut deref_chains = stdx::slice_tails(&deref_chain);
-            deref_chains.try_for_each(|deref_chain| {
+            for i in 0..deref_chain.len() {
                 iterate_method_candidates_with_autoref(
-                    deref_chain,
+                    &deref_chain[i..],
                     db,
                     env.clone(),
                     krate,
@@ -552,8 +504,9 @@ pub fn iterate_method_candidates_dyn(
                     visible_from_module,
                     name,
                     callback,
-                )
-            })
+                )?;
+            }
+            ControlFlow::Continue(())
         }
         LookupMode::Path => {
             // No autoderef for path lookups
@@ -716,14 +669,15 @@ fn iterate_trait_method_candidates(
     // if ty is `dyn Trait`, the trait doesn't need to be in scope
     let inherent_trait =
         self_ty.value.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t));
-    let env_traits = matches!(self_ty.value.kind(&Interner), TyKind::Placeholder(_))
-        // if we have `T: Trait` in the param env, the trait doesn't need to be in scope
-        .then(|| {
-            env.traits_in_scope_from_clauses(self_ty.value.clone())
+    let env_traits = match self_ty.value.kind(&Interner) {
+        TyKind::Placeholder(_) => {
+            // if we have `T: Trait` in the param env, the trait doesn't need to be in scope
+            env.traits_in_scope_from_clauses(&self_ty.value)
                 .flat_map(|t| all_super_traits(db.upcast(), t))
-        })
-        .into_iter()
-        .flatten();
+                .collect()
+        }
+        _ => Vec::new(),
+    };
     let traits = inherent_trait.chain(env_traits).chain(traits_in_scope.iter().copied());
 
     'traits: for t in traits {
@@ -746,10 +700,10 @@ fn iterate_trait_method_candidates(
         // trait, but if we find out it doesn't, we'll skip the rest of the
         // iteration
         let mut known_implemented = false;
-        for &(_, item) in data.items.iter() {
+        for (_name, item) in data.items.iter() {
             // Don't pass a `visible_from_module` down to `is_valid_candidate`,
             // since only inherent methods should be included into visibility checking.
-            if !is_valid_candidate(db, env.clone(), name, receiver_ty, item, self_ty, None) {
+            if !is_valid_candidate(db, env.clone(), name, receiver_ty, *item, self_ty, None) {
                 continue;
             }
             if !known_implemented {
@@ -760,7 +714,7 @@ fn iterate_trait_method_candidates(
             }
             known_implemented = true;
             // FIXME: we shouldn't be ignoring the binders here
-            callback(self_ty, item)?
+            callback(self_ty, *item)?
         }
     }
     ControlFlow::Continue(())
@@ -773,14 +727,18 @@ fn filter_inherent_impls_for_self_ty<'i>(
     // inherent methods on arrays are fingerprinted as [T; {unknown}], so we must also consider them when
     // resolving a method call on an array with a known len
     let array_impls = {
-        match self_ty.kind(&Interner) {
-            TyKind::Array(parameters, array_len) if !array_len.is_unknown() => {
+        if let TyKind::Array(parameters, array_len) = self_ty.kind(&Interner) {
+            if !array_len.is_unknown() {
                 let unknown_array_len_ty =
-                    TyKind::Array(parameters.clone(), consteval::usize_const(None));
+                    TyKind::Array(parameters.clone(), consteval::usize_const(None))
+                        .intern(&Interner);
 
-                Some(impls.for_self_ty(&unknown_array_len_ty.intern(&Interner)))
+                Some(impls.for_self_ty(&unknown_array_len_ty))
+            } else {
+                None
             }
-            _ => None,
+        } else {
+            None
         }
     }
     .into_iter()
@@ -1021,19 +979,18 @@ fn transform_receiver_ty(
     self_ty: &Canonical<Ty>,
 ) -> Option<Ty> {
     let substs = match function_id.lookup(db.upcast()).container {
-        ItemContainerId::TraitId(_) => TyBuilder::subst_for_def(db, function_id)
+        AssocContainerId::TraitId(_) => TyBuilder::subst_for_def(db, function_id)
             .push(self_ty.value.clone())
             .fill_with_unknown()
             .build(),
-        ItemContainerId::ImplId(impl_id) => {
+        AssocContainerId::ImplId(impl_id) => {
             let impl_substs = inherent_impl_substs(db, env, impl_id, self_ty)?;
             TyBuilder::subst_for_def(db, function_id)
                 .use_parent_substs(&impl_substs)
                 .fill_with_unknown()
                 .build()
         }
-        // No receiver
-        ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => unreachable!(),
+        AssocContainerId::ModuleId(_) => unreachable!(),
     };
     let sig = db.callable_item_signature(function_id.into());
     Some(sig.map(|s| s.params()[0].clone()).substitute(&Interner, &substs))
diff --git a/crates/hir_ty/src/tls.rs b/crates/hir_ty/src/tls.rs
index 18a07f2c64..6a662dcf7b 100644
--- a/crates/hir_ty/src/tls.rs
+++ b/crates/hir_ty/src/tls.rs
@@ -7,7 +7,7 @@ use crate::{
     chalk_db, db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, mapping::from_chalk,
     CallableDefId, Interner,
 };
-use hir_def::{AdtId, ItemContainerId, Lookup, TypeAliasId};
+use hir_def::{AdtId, AssocContainerId, Lookup, TypeAliasId};
 
 pub(crate) use unsafe_tls::{set_current_program, with_current_program};
 
@@ -45,7 +45,7 @@ impl DebugContext<'_> {
         let type_alias: TypeAliasId = from_assoc_type_id(id);
         let type_alias_data = self.0.type_alias_data(type_alias);
         let trait_ = match type_alias.lookup(self.0.upcast()).container {
-            ItemContainerId::TraitId(t) => t,
+            AssocContainerId::TraitId(t) => t,
             _ => panic!("associated type not in trait"),
         };
         let trait_data = self.0.trait_data(trait_);
@@ -60,7 +60,7 @@ impl DebugContext<'_> {
         let type_alias = from_assoc_type_id(projection_ty.associated_ty_id);
         let type_alias_data = self.0.type_alias_data(type_alias);
         let trait_ = match type_alias.lookup(self.0.upcast()).container {
-            ItemContainerId::TraitId(t) => t,
+            AssocContainerId::TraitId(t) => t,
             _ => panic!("associated type not in trait"),
         };
         let trait_data = self.0.trait_data(trait_);
diff --git a/crates/hir_ty/src/traits.rs b/crates/hir_ty/src/traits.rs
index 0d135651c7..4b89fd5a85 100644
--- a/crates/hir_ty/src/traits.rs
+++ b/crates/hir_ty/src/traits.rs
@@ -9,7 +9,6 @@ use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver};
 use base_db::CrateId;
 use hir_def::{lang_item::LangItemTarget, TraitId};
 use stdx::panic_context;
-use syntax::SmolStr;
 
 use crate::{
     db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Goal, Guidance, InEnvironment,
@@ -55,13 +54,17 @@ impl TraitEnvironment {
         }
     }
 
-    pub fn traits_in_scope_from_clauses<'a>(
+    pub(crate) fn traits_in_scope_from_clauses<'a>(
         &'a self,
-        ty: Ty,
+        ty: &'a Ty,
     ) -> impl Iterator<Item = TraitId> + 'a {
-        self.traits_from_clauses
-            .iter()
-            .filter_map(move |(self_ty, trait_id)| (*self_ty == ty).then(|| *trait_id))
+        self.traits_from_clauses.iter().filter_map(move |(self_ty, trait_id)| {
+            if self_ty == ty {
+                Some(*trait_id)
+            } else {
+                None
+            }
+        })
     }
 }
 
@@ -170,7 +173,7 @@ pub enum FnTrait {
 }
 
 impl FnTrait {
-    const fn lang_item_name(self) -> &'static str {
+    fn lang_item_name(self) -> &'static str {
         match self {
             FnTrait::FnOnce => "fn_once",
             FnTrait::FnMut => "fn_mut",
@@ -179,7 +182,7 @@ impl FnTrait {
     }
 
     pub fn get_id(&self, db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> {
-        let target = db.lang_item(krate, SmolStr::new_inline(self.lang_item_name()))?;
+        let target = db.lang_item(krate, self.lang_item_name().into())?;
         match target {
             LangItemTarget::TraitId(t) => Some(t),
             _ => None,
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs
index f36a5f8987..0037849d1c 100644
--- a/crates/hir_ty/src/utils.rs
+++ b/crates/hir_ty/src/utils.rs
@@ -14,12 +14,10 @@ use hir_def::{
     path::Path,
     resolver::{HasResolver, TypeNs},
     type_ref::{TraitBoundModifier, TypeRef},
-    GenericDefId, ItemContainerId, Lookup, TraitId, TypeAliasId, TypeParamId,
+    AssocContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId,
 };
 use hir_expand::name::{name, Name};
 use rustc_hash::FxHashSet;
-use smallvec::{smallvec, SmallVec};
-use syntax::SmolStr;
 
 use crate::{
     db::HirDatabase, ChalkTraitId, Interner, Substitution, TraitRef, TraitRefExt, TyKind,
@@ -28,16 +26,16 @@ use crate::{
 
 pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: CrateId) -> impl Iterator<Item = TraitId> {
     [
-        db.lang_item(krate, SmolStr::new_inline("fn")),
-        db.lang_item(krate, SmolStr::new_inline("fn_mut")),
-        db.lang_item(krate, SmolStr::new_inline("fn_once")),
+        db.lang_item(krate, "fn".into()),
+        db.lang_item(krate, "fn_mut".into()),
+        db.lang_item(krate, "fn_once".into()),
     ]
     .into_iter()
     .flatten()
     .flat_map(|it| it.as_trait())
 }
 
-fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> {
+fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
     let resolver = trait_.resolver(db);
     // returning the iterator directly doesn't easily work because of
     // lifetime problems, but since there usually shouldn't be more than a
@@ -102,13 +100,13 @@ fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<Tr
 
 /// Returns an iterator over the whole super trait hierarchy (including the
 /// trait itself).
-pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> {
+pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
     // we need to take care a bit here to avoid infinite loops in case of cycles
     // (i.e. if we have `trait A: B; trait B: A;`)
-
-    let mut result = smallvec![trait_];
+    let mut result = vec![trait_];
     let mut i = 0;
-    while let Some(&t) = result.get(i) {
+    while i < result.len() {
+        let t = result[i];
         // yeah this is quadratic, but trait hierarchies should be flat
         // enough that this doesn't matter
         for tt in direct_super_traits(db, t) {
@@ -298,8 +296,8 @@ fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option<Generic
     };
 
     match container {
-        ItemContainerId::ImplId(it) => Some(it.into()),
-        ItemContainerId::TraitId(it) => Some(it.into()),
-        ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
+        AssocContainerId::ImplId(it) => Some(it.into()),
+        AssocContainerId::TraitId(it) => Some(it.into()),
+        AssocContainerId::ModuleId(_) => None,
     }
 }
diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs
index 55cdb3200e..031c4af0de 100644
--- a/crates/ide/src/goto_type_definition.rs
+++ b/crates/ide/src/goto_type_definition.rs
@@ -75,7 +75,7 @@ pub(crate) fn goto_type_definition(
                 } else if let Some(trait_) = t.as_dyn_trait() {
                     push(trait_.into());
                 } else if let Some(traits) = t.as_impl_traits(db) {
-                    traits.for_each(|it| push(it.into()));
+                    traits.into_iter().for_each(|it| push(it.into()));
                 } else if let Some(trait_) = t.as_associated_type_parent_trait(db) {
                     push(trait_.into());
                 }
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 7d5cfaa937..dd77dd3e4b 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -337,7 +337,7 @@ fn walk_and_push_ty(
         } else if let Some(trait_) = t.as_dyn_trait() {
             push_new_def(trait_.into());
         } else if let Some(traits) = t.as_impl_traits(db) {
-            traits.for_each(|it| push_new_def(it.into()));
+            traits.into_iter().for_each(|it| push_new_def(it.into()));
         } else if let Some(trait_) = t.as_associated_type_parent_trait(db) {
             push_new_def(trait_.into());
         }
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 5bd9f054dd..e7feb042b2 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -56,7 +56,6 @@ mod typing;
 mod view_crate_graph;
 mod view_hir;
 mod view_item_tree;
-mod shuffle_crate_graph;
 
 use std::sync::Arc;
 
@@ -178,10 +177,6 @@ impl AnalysisHost {
     pub fn raw_database_mut(&mut self) -> &mut RootDatabase {
         &mut self.db
     }
-
-    pub fn shuffle_crate_graph(&mut self) {
-        shuffle_crate_graph::shuffle_crate_graph(&mut self.db);
-    }
 }
 
 impl Default for AnalysisHost {
diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs
index 52e099513a..d97e52200d 100644
--- a/crates/ide/src/navigation_target.rs
+++ b/crates/ide/src/navigation_target.rs
@@ -9,6 +9,7 @@ use hir::{
 };
 use ide_db::{
     base_db::{FileId, FileRange},
+    symbol_index::FileSymbolKind,
     SymbolKind,
 };
 use ide_db::{defs::Definition, RootDatabase};
@@ -90,17 +91,18 @@ impl NavigationTarget {
 
     pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
         let name = module.name(db).map(|it| it.to_smol_str()).unwrap_or_default();
-        if let Some(src @ InFile { value, .. }) = &module.declaration_source(db) {
-            let FileRange { file_id, range: full_range } = src.syntax().original_file_range(db);
-            let focus_range = value
+        if let Some(src) = module.declaration_source(db) {
+            let node = src.syntax();
+            let full_range = node.original_file_range(db);
+            let focus_range = src
+                .value
                 .name()
-                .and_then(|name| src.with_value(name.syntax()).original_file_range_opt(db))
-                .map(|it| it.range);
+                .map(|name| src.with_value(name.syntax()).original_file_range(db).range);
             let mut res = NavigationTarget::from_syntax(
-                file_id,
+                full_range.file_id,
                 name,
                 focus_range,
-                full_range,
+                full_range.range,
                 SymbolKind::Module,
             );
             res.docs = module.attrs(db).docs();
@@ -140,9 +142,9 @@ impl NavigationTarget {
             .name()
             .and_then(|it| node.with_value(it.syntax()).original_file_range_opt(db))
             .map(|it| it.range);
-        let FileRange { file_id, range } = node.map(|it| it.syntax()).original_file_range(db);
+        let frange = node.map(|it| it.syntax()).original_file_range(db);
 
-        NavigationTarget::from_syntax(file_id, name, focus_range, range, kind)
+        NavigationTarget::from_syntax(frange.file_id, name, focus_range, frange.range, kind)
     }
 
     fn from_syntax(
@@ -173,7 +175,18 @@ impl TryToNav for FileSymbol {
         Some(NavigationTarget {
             file_id: full_range.file_id,
             name: self.name.clone(),
-            kind: Some(self.kind.into()),
+            kind: Some(match self.kind {
+                FileSymbolKind::Function => SymbolKind::Function,
+                FileSymbolKind::Struct => SymbolKind::Struct,
+                FileSymbolKind::Enum => SymbolKind::Enum,
+                FileSymbolKind::Trait => SymbolKind::Trait,
+                FileSymbolKind::Module => SymbolKind::Module,
+                FileSymbolKind::TypeAlias => SymbolKind::TypeAlias,
+                FileSymbolKind::Const => SymbolKind::Const,
+                FileSymbolKind::Static => SymbolKind::Static,
+                FileSymbolKind::Macro => SymbolKind::Macro,
+                FileSymbolKind::Union => SymbolKind::Union,
+            }),
             full_range: full_range.range,
             focus_range: Some(name_range.range),
             container_name: self.container_name.clone(),
@@ -274,49 +287,39 @@ where
 
 impl ToNav for hir::Module {
     fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
-        let InFile { file_id, value } = self.definition_source(db);
-
+        let src = self.definition_source(db);
         let name = self.name(db).map(|it| it.to_smol_str()).unwrap_or_default();
-        let (syntax, focus) = match &value {
+        let (syntax, focus) = match &src.value {
             ModuleSource::SourceFile(node) => (node.syntax(), None),
-            ModuleSource::Module(node) => (
-                node.syntax(),
-                node.name()
-                    .and_then(|it| InFile::new(file_id, it.syntax()).original_file_range_opt(db))
-                    .map(|it| it.range),
-            ),
+            ModuleSource::Module(node) => {
+                (node.syntax(), node.name().map(|it| it.syntax().text_range()))
+            }
             ModuleSource::BlockExpr(node) => (node.syntax(), None),
         };
-        let FileRange { file_id, range: full_range } =
-            InFile::new(file_id, syntax).original_file_range(db);
-        NavigationTarget::from_syntax(file_id, name, focus, full_range, SymbolKind::Module)
+        let frange = src.with_value(syntax).original_file_range(db);
+        NavigationTarget::from_syntax(frange.file_id, name, focus, frange.range, SymbolKind::Module)
     }
 }
 
 impl TryToNav for hir::Impl {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
-        let InFile { file_id, value } = self.source(db)?;
+        let src = self.source(db)?;
         let derive_attr = self.is_builtin_derive(db);
-
+        let frange = match &derive_attr {
+            Some(item) => item.syntax().original_file_range(db),
+            None => src.syntax().original_file_range(db),
+        };
         let focus_range = if derive_attr.is_some() {
             None
         } else {
-            value
-                .self_ty()
-                .and_then(|ty| InFile::new(file_id, ty.syntax()).original_file_range_opt(db))
-                .map(|it| it.range)
-        };
-
-        let FileRange { file_id, range: full_range } = match &derive_attr {
-            Some(attr) => attr.syntax().original_file_range(db),
-            None => InFile::new(file_id, value.syntax()).original_file_range(db),
+            src.value.self_ty().map(|ty| src.with_value(ty.syntax()).original_file_range(db).range)
         };
 
         Some(NavigationTarget::from_syntax(
-            file_id,
+            frange.file_id,
             "impl".into(),
             focus_range,
-            full_range,
+            frange.range,
             SymbolKind::Impl,
         ))
     }
@@ -335,9 +338,14 @@ impl TryToNav for hir::Field {
                 res
             }
             FieldSource::Pos(it) => {
-                let FileRange { file_id, range } =
-                    src.with_value(it.syntax()).original_file_range(db);
-                NavigationTarget::from_syntax(file_id, "".into(), None, range, SymbolKind::Field)
+                let frange = src.with_value(it.syntax()).original_file_range(db);
+                NavigationTarget::from_syntax(
+                    frange.file_id,
+                    "".into(),
+                    None,
+                    frange.range,
+                    SymbolKind::Field,
+                )
             }
         };
         Some(field_source)
@@ -355,7 +363,13 @@ impl TryToNav for hir::MacroDef {
         let mut res = NavigationTarget::from_named(
             db,
             src.as_ref().with_value(name_owner),
-            self.kind().into(),
+            match self.kind() {
+                hir::MacroKind::Declarative
+                | hir::MacroKind::BuiltIn
+                | hir::MacroKind::ProcMacro => SymbolKind::Macro,
+                hir::MacroKind::Derive => SymbolKind::Derive,
+                hir::MacroKind::Attr => SymbolKind::Attribute,
+            },
         );
         res.docs = self.docs(db);
         Some(res)
@@ -394,17 +408,15 @@ impl TryToNav for hir::GenericParam {
 
 impl ToNav for hir::Local {
     fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
-        let InFile { file_id, value } = self.source(db);
-        let (node, name) = match &value {
-            Either::Left(bind_pat) => (bind_pat.syntax(), bind_pat.name()),
-            Either::Right(it) => (it.syntax(), it.name()),
+        let src = self.source(db);
+        let (node, name) = match &src.value {
+            Either::Left(bind_pat) => (bind_pat.syntax().clone(), bind_pat.name()),
+            Either::Right(it) => (it.syntax().clone(), it.name()),
         };
-        let focus_range = name
-            .and_then(|it| InFile::new(file_id, it.syntax()).original_file_range_opt(db))
-            .map(|it| it.range);
-        let FileRange { file_id, range: full_range } =
-            InFile::new(file_id, node).original_file_range(db);
+        let focus_range =
+            name.map(|it| src.with_value(&it.syntax().clone()).original_file_range(db).range);
 
+        let full_range = src.with_value(&node).original_file_range(db);
         let name = match self.name(db) {
             Some(it) => it.to_smol_str(),
             None => "".into(),
@@ -417,10 +429,10 @@ impl ToNav for hir::Local {
             SymbolKind::Local
         };
         NavigationTarget {
-            file_id,
+            file_id: full_range.file_id,
             name,
             kind: Some(kind),
-            full_range,
+            full_range: full_range.range,
             focus_range,
             container_name: None,
             description: None,
@@ -431,18 +443,17 @@ impl ToNav for hir::Local {
 
 impl ToNav for hir::Label {
     fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
-        let InFile { file_id, value } = self.source(db);
+        let src = self.source(db);
+        let node = src.value.syntax();
+        let FileRange { file_id, range } = src.with_value(node).original_file_range(db);
+        let focus_range =
+            src.value.lifetime().and_then(|lt| lt.lifetime_ident_token()).map(|lt| lt.text_range());
         let name = self.name(db).to_smol_str();
-
-        let range = |syntax: &_| InFile::new(file_id, syntax).original_file_range(db);
-        let FileRange { file_id, range: full_range } = range(value.syntax());
-        let focus_range = value.lifetime().map(|lt| range(lt.syntax()).range);
-
         NavigationTarget {
             file_id,
             name,
             kind: Some(SymbolKind::Label),
-            full_range,
+            full_range: range,
             focus_range,
             container_name: None,
             description: None,
@@ -453,25 +464,21 @@ impl ToNav for hir::Label {
 
 impl TryToNav for hir::TypeParam {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
-        let InFile { file_id, value } = self.source(db)?;
-        let name = self.name(db).to_smol_str();
-
-        let range = |syntax: &_| InFile::new(file_id, syntax).original_file_range(db);
-        let focus_range = |syntax: &_| InFile::new(file_id, syntax).original_file_range_opt(db);
-        let FileRange { file_id, range: full_range } = match &value {
-            Either::Left(type_param) => range(type_param.syntax()),
+        let src = self.source(db)?;
+        let full_range = match &src.value {
+            Either::Left(type_param) => type_param.syntax().text_range(),
             Either::Right(trait_) => trait_
                 .name()
-                .and_then(|name| focus_range(name.syntax()))
-                .unwrap_or_else(|| range(trait_.syntax())),
+                .map_or_else(|| trait_.syntax().text_range(), |name| name.syntax().text_range()),
         };
-        let focus_range = value
-            .either(|it| it.name(), |it| it.name())
-            .and_then(|it| focus_range(it.syntax()))
-            .map(|it| it.range);
+        let focus_range = match &src.value {
+            Either::Left(it) => it.name(),
+            Either::Right(it) => it.name(),
+        }
+        .map(|it| it.syntax().text_range());
         Some(NavigationTarget {
-            file_id,
-            name,
+            file_id: src.file_id.original_file(db),
+            name: self.name(db).to_smol_str(),
             kind: Some(SymbolKind::TypeParam),
             full_range,
             focus_range,
@@ -484,14 +491,11 @@ impl TryToNav for hir::TypeParam {
 
 impl TryToNav for hir::LifetimeParam {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
-        let InFile { file_id, value } = self.source(db)?;
-        let name = self.name(db).to_smol_str();
-
-        let FileRange { file_id, range: full_range } =
-            InFile::new(file_id, value.syntax()).original_file_range(db);
+        let src = self.source(db)?;
+        let full_range = src.value.syntax().text_range();
         Some(NavigationTarget {
-            file_id,
-            name,
+            file_id: src.file_id.original_file(db),
+            name: self.name(db).to_smol_str(),
             kind: Some(SymbolKind::LifetimeParam),
             full_range,
             focus_range: Some(full_range),
@@ -504,21 +508,14 @@ impl TryToNav for hir::LifetimeParam {
 
 impl TryToNav for hir::ConstParam {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
-        let InFile { file_id, value } = self.source(db)?;
-        let name = self.name(db).to_smol_str();
-
-        let focus_range = value
-            .name()
-            .and_then(|it| InFile::new(file_id, it.syntax()).original_file_range_opt(db))
-            .map(|it| it.range);
-        let FileRange { file_id, range: full_range } =
-            InFile::new(file_id, value.syntax()).original_file_range(db);
+        let src = self.source(db)?;
+        let full_range = src.value.syntax().text_range();
         Some(NavigationTarget {
-            file_id,
-            name,
+            file_id: src.file_id.original_file(db),
+            name: self.name(db).to_smol_str(),
             kind: Some(SymbolKind::ConstParam),
             full_range,
-            focus_range,
+            focus_range: src.value.name().map(|n| n.syntax().text_range()),
             container_name: None,
             description: None,
             docs: None,
diff --git a/crates/ide/src/prime_caches.rs b/crates/ide/src/prime_caches.rs
index 5eba1d1e27..41e48c4ba5 100644
--- a/crates/ide/src/prime_caches.rs
+++ b/crates/ide/src/prime_caches.rs
@@ -4,7 +4,7 @@
 //! various caches, it's not really advanced at the moment.
 
 use hir::db::DefDatabase;
-use ide_db::base_db::{SourceDatabase, SourceDatabaseExt};
+use ide_db::base_db::{CrateGraph, CrateId, SourceDatabase, SourceDatabaseExt};
 use rustc_hash::FxHashSet;
 
 use crate::RootDatabase;
@@ -20,10 +20,7 @@ pub struct PrimeCachesProgress {
 pub(crate) fn prime_caches(db: &RootDatabase, cb: &(dyn Fn(PrimeCachesProgress) + Sync)) {
     let _p = profile::span("prime_caches");
     let graph = db.crate_graph();
-    // We're only interested in the workspace crates and the `ImportMap`s of their direct
-    // dependencies, though in practice the latter also compute the `DefMap`s.
-    // We don't prime transitive dependencies because they're generally not visible in
-    // the current workspace.
+    // We're only interested in the transitive dependencies of all workspace crates.
     let to_prime: FxHashSet<_> = graph
         .iter()
         .filter(|&id| {
@@ -31,18 +28,32 @@ pub(crate) fn prime_caches(db: &RootDatabase, cb: &(dyn Fn(PrimeCachesProgress)
             let root_id = db.file_source_root(file_id);
             !db.source_root(root_id).is_library
         })
-        .flat_map(|id| graph[id].dependencies.iter().map(|krate| krate.crate_id))
+        .flat_map(|id| graph.transitive_deps(id))
         .collect();
 
+    let topo = toposort(&graph, &to_prime);
+
     // FIXME: This would be easy to parallelize, since it's in the ideal ordering for that.
     // Unfortunately rayon prevents panics from propagation out of a `scope`, which breaks
     // cancellation, so we cannot use rayon.
-    let n_total = to_prime.len();
-    for (n_done, &crate_id) in to_prime.iter().enumerate() {
+    for (i, &crate_id) in topo.iter().enumerate() {
         let crate_name = graph[crate_id].display_name.as_deref().unwrap_or_default().to_string();
 
-        cb(PrimeCachesProgress { on_crate: crate_name, n_done, n_total });
-        // This also computes the DefMap
+        cb(PrimeCachesProgress { on_crate: crate_name, n_done: i, n_total: topo.len() });
+        db.crate_def_map(crate_id);
         db.import_map(crate_id);
     }
 }
+
+fn toposort(graph: &CrateGraph, crates: &FxHashSet<CrateId>) -> Vec<CrateId> {
+    // Just subset the full topologically sorted set for simplicity.
+
+    let all = graph.crates_in_topological_order();
+    let mut result = Vec::with_capacity(crates.len());
+    for krate in all {
+        if crates.contains(&krate) {
+            result.push(krate);
+        }
+    }
+    result
+}
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index 67062654d6..3078789d12 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -1437,6 +1437,7 @@ gen2!();
                                 0,
                             ),
                             full_range: 228..236,
+                            focus_range: 228..236,
                             name: "tests2",
                             kind: Module,
                             description: "mod tests2",
@@ -1521,6 +1522,7 @@ foo!();
                                 0,
                             ),
                             full_range: 210..217,
+                            focus_range: 210..217,
                             name: "foo_tests",
                             kind: Module,
                             description: "mod foo_tests",
diff --git a/crates/ide/src/shuffle_crate_graph.rs b/crates/ide/src/shuffle_crate_graph.rs
deleted file mode 100644
index 9c3cce5dfe..0000000000
--- a/crates/ide/src/shuffle_crate_graph.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-use std::sync::Arc;
-
-use ide_db::base_db::salsa::Durability;
-use ide_db::base_db::{CrateGraph, SourceDatabase};
-use ide_db::RootDatabase;
-use rustc_hash::FxHashMap;
-
-// Feature: Shuffle Crate Graph
-//
-// Randomizes all crate IDs in the crate graph, for debugging.
-//
-// |===
-// | Editor  | Action Name
-//
-// | VS Code | **Rust Analyzer: Shuffle Crate Graph**
-// |===
-pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) {
-    let crate_graph = db.crate_graph();
-
-    let mut shuffled_ids = crate_graph.iter().collect::<Vec<_>>();
-    shuffle(&mut shuffled_ids);
-
-    let mut new_graph = CrateGraph::default();
-
-    let mut map = FxHashMap::default();
-    for old_id in shuffled_ids.iter().copied() {
-        let data = &crate_graph[old_id];
-        let new_id = new_graph.add_crate_root(
-            data.root_file_id,
-            data.edition,
-            data.display_name.clone(),
-            data.version.clone(),
-            data.cfg_options.clone(),
-            data.potential_cfg_options.clone(),
-            data.env.clone(),
-            data.proc_macro.clone(),
-            data.origin.clone(),
-        );
-        map.insert(old_id, new_id);
-    }
-
-    for old_id in shuffled_ids.iter().copied() {
-        let data = &crate_graph[old_id];
-        for dep in &data.dependencies {
-            let mut new_dep = dep.clone();
-            new_dep.crate_id = map[&dep.crate_id];
-            new_graph.add_dep(map[&old_id], new_dep).unwrap();
-        }
-    }
-
-    db.set_crate_graph_with_durability(Arc::new(new_graph), Durability::HIGH);
-}
-
-fn shuffle<T>(slice: &mut [T]) {
-    let mut rng = oorandom::Rand32::new(seed());
-
-    let mut remaining = slice.len() - 1;
-    while remaining > 0 {
-        let index = rng.rand_range(0..remaining as u32);
-        slice.swap(remaining, index as usize);
-        remaining -= 1;
-    }
-}
-
-fn seed() -> u64 {
-    use std::collections::hash_map::RandomState;
-    use std::hash::{BuildHasher, Hasher};
-
-    RandomState::new().build_hasher().finish()
-}
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index 05d2732251..a52b2247c5 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -375,7 +375,13 @@ fn highlight_def(
 ) -> Highlight {
     let db = sema.db;
     let mut h = match def {
-        Definition::Macro(m) => Highlight::new(HlTag::Symbol(m.kind().into())),
+        Definition::Macro(m) => Highlight::new(HlTag::Symbol(match m.kind() {
+            hir::MacroKind::Declarative | hir::MacroKind::BuiltIn | hir::MacroKind::ProcMacro => {
+                SymbolKind::Macro
+            }
+            hir::MacroKind::Derive => SymbolKind::Derive,
+            hir::MacroKind::Attr => SymbolKind::Attribute,
+        })),
         Definition::Field(_) => Highlight::new(HlTag::Symbol(SymbolKind::Field)),
         Definition::Module(module) => {
             let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Module));
diff --git a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
index 46bf4d7b46..3e33c62144 100644
--- a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -65,7 +65,7 @@ pub(crate) fn replace_derive_with_manual_impl(
     let found_traits = items_locator::items_with_name(
         &ctx.sema,
         current_crate,
-        NameToImport::exact_case_sensitive(trait_path.segments().last()?.to_string()),
+        NameToImport::Exact(trait_path.segments().last()?.to_string()),
         items_locator::AssocItemSearch::Exclude,
         Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT.inner()),
     )
diff --git a/crates/ide_assists/src/utils/suggest_name.rs b/crates/ide_assists/src/utils/suggest_name.rs
index 2021db3aba..74523234b0 100644
--- a/crates/ide_assists/src/utils/suggest_name.rs
+++ b/crates/ide_assists/src/utils/suggest_name.rs
@@ -243,7 +243,7 @@ fn name_of_type(ty: &hir::Type, db: &RootDatabase) -> Option<String> {
     } else if let Some(trait_) = ty.as_dyn_trait() {
         trait_name(&trait_, db)?
     } else if let Some(traits) = ty.as_impl_traits(db) {
-        let mut iter = traits.filter_map(|t| trait_name(&t, db));
+        let mut iter = traits.into_iter().filter_map(|t| trait_name(&t, db));
         let name = iter.next()?;
         if iter.next().is_some() {
             return None;
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs
index 8994c25475..784a1a0637 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -1,14 +1,13 @@
 //! See [`import_on_the_fly`].
-use hir::ItemInNs;
 use ide_db::helpers::{
-    import_assets::{ImportAssets, ImportCandidate, LocatedImport},
+    import_assets::{ImportAssets, ImportCandidate},
     insert_use::ImportScope,
 };
 use itertools::Itertools;
 use syntax::{AstNode, SyntaxNode, T};
 
 use crate::{
-    context::{CompletionContext, PathKind},
+    context::CompletionContext,
     render::{render_resolution_with_import, RenderContext},
     ImportEdit,
 };
@@ -110,7 +109,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
     if !ctx.config.enable_imports_on_the_fly {
         return None;
     }
-    if matches!(ctx.path_kind(), Some(PathKind::Vis { .. } | PathKind::Use))
+    if ctx.in_use_tree()
         || ctx.is_path_disallowed()
         || ctx.expects_item()
         || ctx.expects_assoc_item()
@@ -118,11 +117,6 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
     {
         return None;
     }
-    // FIXME: This should be encoded in a different way
-    if ctx.pattern_ctx.is_none() && ctx.path_context.is_none() && !ctx.has_dot_receiver() {
-        // completion inside `ast::Name` of a item declaration
-        return None;
-    }
     let potential_import_name = {
         let token_kind = ctx.token.kind();
         if matches!(token_kind, T![.] | T![::]) {
@@ -141,46 +135,10 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
         &ctx.sema,
     )?;
 
-    let ns_filter = |import: &LocatedImport| {
-        let kind = match ctx.path_kind() {
-            Some(kind) => kind,
-            None => {
-                return match import.original_item {
-                    ItemInNs::Macros(mac) => mac.is_fn_like(),
-                    _ => true,
-                }
-            }
-        };
-        match (kind, import.original_item) {
-            // Aren't handled in flyimport
-            (PathKind::Vis { .. } | PathKind::Use, _) => false,
-            // modules are always fair game
-            (_, ItemInNs::Types(hir::ModuleDef::Module(_))) => true,
-            // and so are macros(except for attributes)
-            (
-                PathKind::Expr | PathKind::Type | PathKind::Mac | PathKind::Pat,
-                ItemInNs::Macros(mac),
-            ) => mac.is_fn_like(),
-            (PathKind::Mac, _) => true,
-
-            (PathKind::Expr, ItemInNs::Types(_) | ItemInNs::Values(_)) => true,
-
-            (PathKind::Pat, ItemInNs::Types(_)) => true,
-            (PathKind::Pat, ItemInNs::Values(def)) => matches!(def, hir::ModuleDef::Const(_)),
-
-            (PathKind::Type, ItemInNs::Types(_)) => true,
-            (PathKind::Type, ItemInNs::Values(_)) => false,
-
-            (PathKind::Attr, ItemInNs::Macros(mac)) => mac.is_attr(),
-            (PathKind::Attr, _) => false,
-        }
-    };
-
     acc.add_all(
         import_assets
             .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
             .into_iter()
-            .filter(ns_filter)
             .filter(|import| {
                 !ctx.is_item_hidden(&import.item_to_import)
                     && !ctx.is_item_hidden(&import.original_item)
@@ -227,18 +185,22 @@ fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAs
         )
     } else {
         let fuzzy_name_length = fuzzy_name.len();
-        let mut assets_for_path = ImportAssets::for_fuzzy_path(
+        let assets_for_path = ImportAssets::for_fuzzy_path(
             current_module,
             ctx.path_qual().cloned(),
             fuzzy_name,
             &ctx.sema,
             ctx.token.parent()?,
         )?;
-        if fuzzy_name_length < 3 {
-            cov_mark::hit!(flyimport_exact_on_short_path);
-            assets_for_path.path_fuzzy_name_to_exact(false);
+
+        if matches!(assets_for_path.import_candidate(), ImportCandidate::Path(_))
+            && fuzzy_name_length < 2
+        {
+            cov_mark::hit!(ignore_short_input_for_path);
+            None
+        } else {
+            Some(assets_for_path)
         }
-        Some(assets_for_path)
     }
 }
 
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs
index 1c686dc0a6..36d25d5d02 100644
--- a/crates/ide_completion/src/completions/keyword.rs
+++ b/crates/ide_completion/src/completions/keyword.rs
@@ -5,9 +5,8 @@
 use syntax::{SyntaxKind, T};
 
 use crate::{
-    context::{PathCompletionContext, PathKind},
-    patterns::ImmediateLocation,
-    CompletionContext, CompletionItem, CompletionItemKind, Completions,
+    context::PathCompletionContext, patterns::ImmediateLocation, CompletionContext, CompletionItem,
+    CompletionItemKind, Completions,
 };
 
 pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
@@ -34,8 +33,8 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
     let has_block_expr_parent = ctx.has_block_expr_parent();
     let expects_item = ctx.expects_item();
 
-    if let Some(PathKind::Vis { has_in_token }) = ctx.path_kind() {
-        if !has_in_token {
+    if let Some(ImmediateLocation::Visibility(vis)) = &ctx.completion_location {
+        if vis.in_token().is_none() {
             cov_mark::hit!(kw_completion_in);
             add_keyword("in", "in");
         }
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs
index b3b27f251f..c63c274151 100644
--- a/crates/ide_completion/src/completions/pattern.rs
+++ b/crates/ide_completion/src/completions/pattern.rs
@@ -1,26 +1,21 @@
-//! Completes constants and paths in unqualified patterns.
-
-use hir::db::DefDatabase;
+//! Completes constants and paths in patterns.
 
 use crate::{
     context::{PatternContext, PatternRefutability},
     CompletionContext, Completions,
 };
 
-/// Completes constants and paths in unqualified patterns.
+/// Completes constants and paths in patterns.
 pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
     let refutable = match ctx.pattern_ctx {
-        Some(PatternContext { refutability, .. }) if ctx.path_context.is_none() => {
-            refutability == PatternRefutability::Refutable
-        }
-        _ => return,
+        Some(PatternContext { refutability, .. }) => refutability == PatternRefutability::Refutable,
+        None => return,
     };
-    let single_variant_enum = |enum_: hir::Enum| ctx.db.enum_data(enum_.into()).variants.len() == 1;
 
-    if let Some(hir::Adt::Enum(e)) =
-        ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt())
-    {
-        if refutable || single_variant_enum(e) {
+    if refutable {
+        if let Some(hir::Adt::Enum(e)) =
+            ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt())
+        {
             super::enum_variants_with_paths(acc, ctx, e, |acc, ctx, variant, path| {
                 acc.add_qualified_variant_pat(ctx, variant, path.clone());
                 acc.add_qualified_enum_variant(ctx, variant, path);
@@ -31,20 +26,20 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
     // FIXME: ideally, we should look at the type we are matching against and
     // suggest variants + auto-imports
     ctx.process_all_names(&mut |name, res| {
-        let add_resolution = match res {
+        let add_resolution = match &res {
             hir::ScopeDef::ModuleDef(def) => match def {
                 hir::ModuleDef::Adt(hir::Adt::Struct(strukt)) => {
-                    acc.add_struct_pat(ctx, strukt, Some(name.clone()));
+                    acc.add_struct_pat(ctx, *strukt, Some(name.clone()));
                     true
                 }
-                hir::ModuleDef::Variant(variant)
-                    if refutable || single_variant_enum(variant.parent_enum(ctx.db)) =>
-                {
-                    acc.add_variant_pat(ctx, variant, Some(name.clone()));
+                hir::ModuleDef::Variant(variant) if refutable => {
+                    acc.add_variant_pat(ctx, *variant, Some(name.clone()));
                     true
                 }
-                hir::ModuleDef::Adt(hir::Adt::Enum(e)) => refutable || single_variant_enum(e),
-                hir::ModuleDef::Const(..) | hir::ModuleDef::Module(..) => refutable,
+                hir::ModuleDef::Adt(hir::Adt::Enum(..))
+                | hir::ModuleDef::Variant(..)
+                | hir::ModuleDef::Const(..)
+                | hir::ModuleDef::Module(..) => refutable,
                 _ => false,
             },
             hir::ScopeDef::MacroDef(mac) => mac.is_fn_like(),
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs
index b5c3d83c16..a2662d2932 100644
--- a/crates/ide_completion/src/completions/qualified_path.rs
+++ b/crates/ide_completion/src/completions/qualified_path.rs
@@ -2,28 +2,21 @@
 
 use std::iter;
 
-use hir::ScopeDef;
 use rustc_hash::FxHashSet;
 use syntax::{ast, AstNode};
 
 use crate::{
-    context::{PathCompletionContext, PathKind},
-    patterns::ImmediateLocation,
-    CompletionContext, Completions,
+    context::PathCompletionContext, patterns::ImmediateLocation, CompletionContext, Completions,
 };
 
 pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) {
     if ctx.is_path_disallowed() || ctx.has_impl_or_trait_prev_sibling() {
         return;
     }
-    let (path, use_tree_parent, kind) = match ctx.path_context {
-        // let ... else, syntax would come in really handy here right now
-        Some(PathCompletionContext {
-            qualifier: Some(ref qualifier),
-            use_tree_parent,
-            kind,
-            ..
-        }) => (qualifier, use_tree_parent, kind),
+    let (path, use_tree_parent) = match &ctx.path_context {
+        Some(PathCompletionContext { qualifier: Some(qualifier), use_tree_parent, .. }) => {
+            (qualifier, *use_tree_parent)
+        }
         _ => return,
     };
 
@@ -38,87 +31,67 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
         Some(ImmediateLocation::ItemList | ImmediateLocation::Trait | ImmediateLocation::Impl) => {
             if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution {
                 for (name, def) in module.scope(ctx.db, context_module) {
-                    if let ScopeDef::MacroDef(macro_def) = def {
+                    if let hir::ScopeDef::MacroDef(macro_def) = def {
                         if macro_def.is_fn_like() {
                             acc.add_macro(ctx, Some(name.clone()), macro_def);
                         }
                     }
-                    if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def {
+                    if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def {
                         acc.add_resolution(ctx, name, &def);
                     }
                 }
             }
             return;
         }
-        _ => (),
-    }
-
-    match kind {
-        Some(PathKind::Vis { .. }) => {
-            if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution {
+        Some(ImmediateLocation::Visibility(_)) => {
+            if let hir::PathResolution::Def(hir::ModuleDef::Module(resolved)) = resolution {
                 if let Some(current_module) = ctx.scope.module() {
                     if let Some(next) = current_module
                         .path_to_root(ctx.db)
                         .into_iter()
-                        .take_while(|&it| it != module)
+                        .take_while(|&it| it != resolved)
                         .next()
                     {
                         if let Some(name) = next.name(ctx.db) {
-                            acc.add_resolution(ctx, name, &ScopeDef::ModuleDef(next.into()));
+                            acc.add_resolution(ctx, name, &hir::ScopeDef::ModuleDef(next.into()));
                         }
                     }
                 }
             }
             return;
         }
-        Some(PathKind::Attr) => {
-            if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution {
-                for (name, def) in module.scope(ctx.db, context_module) {
-                    let add_resolution = match def {
-                        ScopeDef::MacroDef(mac) => mac.is_attr(),
-                        ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => true,
-                        _ => false,
-                    };
-                    if add_resolution {
-                        acc.add_resolution(ctx, name, &def);
-                    }
-                }
-            }
-            return;
-        }
-        Some(PathKind::Use) => {
-            if iter::successors(Some(path.clone()), |p| p.qualifier())
-                .all(|p| p.segment().and_then(|s| s.super_token()).is_some())
-            {
-                acc.add_keyword(ctx, "super::");
-            }
-            // only show `self` in a new use-tree when the qualifier doesn't end in self
-            if use_tree_parent
-                && !matches!(
-                    path.segment().and_then(|it| it.kind()),
-                    Some(ast::PathSegmentKind::SelfKw)
-                )
-            {
-                acc.add_keyword(ctx, "self");
-            }
-        }
         _ => (),
     }
 
-    if !matches!(kind, Some(PathKind::Pat)) {
-        // Add associated types on type parameters and `Self`.
-        resolution.assoc_type_shorthand_candidates(ctx.db, |_, alias| {
-            acc.add_type_alias(ctx, alias);
-            None::<()>
-        });
+    if ctx.in_use_tree() {
+        if iter::successors(Some(path.clone()), |p| p.qualifier())
+            .all(|p| p.segment().and_then(|s| s.super_token()).is_some())
+        {
+            acc.add_keyword(ctx, "super::");
+        }
+        // only show `self` in a new use-tree when the qualifier doesn't end in self
+        if use_tree_parent
+            && !matches!(
+                path.segment().and_then(|it| it.kind()),
+                Some(ast::PathSegmentKind::SelfKw)
+            )
+        {
+            acc.add_keyword(ctx, "self");
+        }
     }
 
+    // Add associated types on type parameters and `Self`.
+    resolution.assoc_type_shorthand_candidates(ctx.db, |_, alias| {
+        acc.add_type_alias(ctx, alias);
+        None::<()>
+    });
+
     match resolution {
         hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
             let module_scope = module.scope(ctx.db, context_module);
             for (name, def) in module_scope {
-                if let Some(PathKind::Use) = kind {
-                    if let ScopeDef::Unknown = def {
+                if ctx.in_use_tree() {
+                    if let hir::ScopeDef::Unknown = def {
                         if let Some(ast::NameLike::NameRef(name_ref)) = ctx.name_syntax.as_ref() {
                             if name_ref.syntax().text() == name.to_smol_str().as_str() {
                                 // for `use self::foo$0`, don't suggest `foo` as a completion
@@ -131,16 +104,16 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
 
                 let add_resolution = match def {
                     // Don't suggest attribute macros and derives.
-                    ScopeDef::MacroDef(mac) => mac.is_fn_like(),
+                    hir::ScopeDef::MacroDef(mac) => mac.is_fn_like(),
                     // no values in type places
-                    ScopeDef::ModuleDef(
+                    hir::ScopeDef::ModuleDef(
                         hir::ModuleDef::Function(_)
                         | hir::ModuleDef::Variant(_)
                         | hir::ModuleDef::Static(_),
                     )
-                    | ScopeDef::Local(_) => !ctx.expects_type(),
+                    | hir::ScopeDef::Local(_) => !ctx.expects_type(),
                     // unless its a constant in a generic arg list position
-                    ScopeDef::ModuleDef(hir::ModuleDef::Const(_)) => {
+                    hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(_)) => {
                         !ctx.expects_type() || ctx.expects_generic_arg()
                     }
                     _ => true,
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs
index ac1ba2da7c..a84f0b334b 100644
--- a/crates/ide_completion/src/completions/unqualified_path.rs
+++ b/crates/ide_completion/src/completions/unqualified_path.rs
@@ -3,23 +3,15 @@
 use hir::ScopeDef;
 use syntax::{ast, AstNode};
 
-use crate::{
-    context::{PathCompletionContext, PathKind},
-    patterns::ImmediateLocation,
-    CompletionContext, Completions,
-};
+use crate::{patterns::ImmediateLocation, CompletionContext, Completions};
 
 pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
     let _p = profile::span("complete_unqualified_path");
-    if ctx.is_path_disallowed() || ctx.has_impl_or_trait_prev_sibling() {
+    if ctx.is_path_disallowed() || !ctx.is_trivial_path() || ctx.has_impl_or_trait_prev_sibling() {
         return;
     }
-    let kind = match ctx.path_context {
-        Some(PathCompletionContext { is_trivial_path: true, kind, .. }) => kind,
-        _ => return,
-    };
 
-    if let Some(PathKind::Use) = kind {
+    if ctx.in_use_tree() {
         // only show modules in a fresh UseTree
         cov_mark::hit!(unqualified_path_only_modules_in_import);
         ctx.process_all_names(&mut |name, res| {
@@ -33,25 +25,8 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
     }
     ["self", "super", "crate"].into_iter().for_each(|kw| acc.add_keyword(ctx, kw));
 
-    match kind {
-        Some(PathKind::Vis { .. }) => return,
-        Some(PathKind::Attr) => {
-            ctx.process_all_names(&mut |name, res| {
-                let add_resolution = match res {
-                    ScopeDef::MacroDef(mac) => mac.is_attr(),
-                    ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => true,
-                    _ => false,
-                };
-                if add_resolution {
-                    acc.add_resolution(ctx, name, &res);
-                }
-            });
-            return;
-        }
-        _ => (),
-    }
-
     match &ctx.completion_location {
+        Some(ImmediateLocation::Visibility(_)) => return,
         Some(ImmediateLocation::ItemList | ImmediateLocation::Trait | ImmediateLocation::Impl) => {
             // only show macros in {Assoc}ItemList
             ctx.process_all_names(&mut |name, res| {
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index e8566b80b6..d9ddd9f2ae 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -30,28 +30,20 @@ pub(crate) enum PatternRefutability {
     Irrefutable,
 }
 
-#[derive(Copy, Clone, Debug)]
+#[derive(Debug)]
 pub(super) enum PathKind {
     Expr,
     Type,
-    Attr,
-    Mac,
-    Pat,
-    Vis { has_in_token: bool },
-    Use,
 }
 
 #[derive(Debug)]
 pub(crate) struct PathCompletionContext {
     /// If this is a call with () already there
-    has_call_parens: bool,
+    call_kind: Option<CallKind>,
     /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path.
     pub(super) is_trivial_path: bool,
     /// If not a trivial path, the prefix (qualifier).
     pub(super) qualifier: Option<ast::Path>,
-    #[allow(dead_code)]
-    /// If not a trivial path, the suffix (parent).
-    pub(super) parent: Option<ast::Path>,
     /// Whether the qualifier comes from a use tree parent or not
     pub(super) use_tree_parent: bool,
     pub(super) kind: Option<PathKind>,
@@ -77,6 +69,13 @@ pub(super) enum LifetimeContext {
     LabelDef,
 }
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub(crate) enum CallKind {
+    Pat,
+    Mac,
+    Expr,
+}
+
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub(crate) enum ParamKind {
     Function,
@@ -206,6 +205,13 @@ impl<'a> CompletionContext<'a> {
         )
     }
 
+    pub(crate) fn in_use_tree(&self) -> bool {
+        matches!(
+            self.completion_location,
+            Some(ImmediateLocation::Use | ImmediateLocation::UseTree)
+        )
+    }
+
     pub(crate) fn has_impl_or_trait_prev_sibling(&self) -> bool {
         matches!(
             self.prev_sibling,
@@ -226,7 +232,8 @@ impl<'a> CompletionContext<'a> {
     }
 
     pub(crate) fn is_path_disallowed(&self) -> bool {
-        self.previous_token_is(T![unsafe])
+        self.attribute_under_caret.is_some()
+            || self.previous_token_is(T![unsafe])
             || matches!(
                 self.prev_sibling,
                 Some(ImmediatePrevSibling::Attribute | ImmediatePrevSibling::Visibility)
@@ -234,7 +241,8 @@ impl<'a> CompletionContext<'a> {
             || matches!(
                 self.completion_location,
                 Some(
-                    ImmediateLocation::ModDeclaration(_)
+                    ImmediateLocation::Attribute(_)
+                        | ImmediateLocation::ModDeclaration(_)
                         | ImmediateLocation::RecordPat(_)
                         | ImmediateLocation::RecordExpr(_)
                         | ImmediateLocation::Rename
@@ -250,8 +258,8 @@ impl<'a> CompletionContext<'a> {
         matches!(self.path_context, Some(PathCompletionContext { kind: Some(PathKind::Type), .. }))
     }
 
-    pub(crate) fn path_is_call(&self) -> bool {
-        self.path_context.as_ref().map_or(false, |it| it.has_call_parens)
+    pub(crate) fn path_call_kind(&self) -> Option<CallKind> {
+        self.path_context.as_ref().and_then(|it| it.call_kind)
     }
 
     pub(crate) fn is_trivial_path(&self) -> bool {
@@ -266,10 +274,6 @@ impl<'a> CompletionContext<'a> {
         self.path_context.as_ref().and_then(|it| it.qualifier.as_ref())
     }
 
-    pub(crate) fn path_kind(&self) -> Option<PathKind> {
-        self.path_context.as_ref().and_then(|it| it.kind)
-    }
-
     /// Checks if an item is visible and not `doc(hidden)` at the completion site.
     pub(crate) fn is_visible<I>(&self, item: &I) -> bool
     where
@@ -666,12 +670,7 @@ impl<'a> CompletionContext<'a> {
                     Self::classify_lifetime(&self.sema, original_file, lifetime, offset);
             }
             ast::NameLike::NameRef(name_ref) => {
-                if let Some((path_ctx, pat_ctx)) =
-                    Self::classify_name_ref(&self.sema, original_file, name_ref)
-                {
-                    self.path_context = Some(path_ctx);
-                    self.pattern_ctx = pat_ctx;
-                }
+                self.path_context = Self::classify_name_ref(&self.sema, original_file, name_ref);
             }
             ast::NameLike::Name(name) => {
                 self.pattern_ctx = Self::classify_name(&self.sema, name);
@@ -714,61 +713,82 @@ impl<'a> CompletionContext<'a> {
         if !bind_pat.is_simple_ident() {
             return None;
         }
-        Some(pattern_context_for(bind_pat.into()))
+        let mut is_param = None;
+        let (refutability, has_type_ascription) = bind_pat
+            .syntax()
+            .ancestors()
+            .skip_while(|it| ast::Pat::can_cast(it.kind()))
+            .next()
+            .map_or((PatternRefutability::Irrefutable, false), |node| {
+                let refutability = match_ast! {
+                    match node {
+                        ast::LetStmt(let_) => return (PatternRefutability::Irrefutable, let_.ty().is_some()),
+                        ast::Param(param) => {
+                            let is_closure_param = param
+                                .syntax()
+                                .ancestors()
+                                .nth(2)
+                                .and_then(ast::ClosureExpr::cast)
+                                .is_some();
+                            is_param = Some(if is_closure_param {
+                                ParamKind::Closure
+                            } else {
+                                ParamKind::Function
+                            });
+                            return (PatternRefutability::Irrefutable, param.ty().is_some())
+                        },
+                        ast::MatchArm(__) => PatternRefutability::Refutable,
+                        ast::Condition(__) => PatternRefutability::Refutable,
+                        ast::ForExpr(__) => PatternRefutability::Irrefutable,
+                        _ => PatternRefutability::Irrefutable,
+                    }
+                };
+                (refutability, false)
+            });
+        Some(PatternContext { refutability, is_param, has_type_ascription })
     }
 
     fn classify_name_ref(
         _sema: &Semantics<RootDatabase>,
         original_file: &SyntaxNode,
         name_ref: ast::NameRef,
-    ) -> Option<(PathCompletionContext, Option<PatternContext>)> {
+    ) -> Option<PathCompletionContext> {
         let parent = name_ref.syntax().parent()?;
         let segment = ast::PathSegment::cast(parent)?;
-        let path = segment.parent_path();
 
         let mut path_ctx = PathCompletionContext {
-            has_call_parens: false,
+            call_kind: None,
             is_trivial_path: false,
             qualifier: None,
-            parent: None,
             has_type_args: false,
             can_be_stmt: false,
             in_loop_body: false,
             use_tree_parent: false,
             kind: None,
         };
-        let mut pat_ctx = None;
         path_ctx.in_loop_body = is_in_loop_body(name_ref.syntax());
+        let path = segment.parent_path();
 
-        path_ctx.kind  = path.syntax().ancestors().find_map(|it| {
-            match_ast! {
-                match it {
+        if let Some(p) = path.syntax().parent() {
+            path_ctx.call_kind = match_ast! {
+                match p {
+                    ast::PathExpr(it) => it.syntax().parent().and_then(ast::CallExpr::cast).map(|_| CallKind::Expr),
+                    ast::MacroCall(it) => it.excl_token().and(Some(CallKind::Mac)),
+                    ast::TupleStructPat(_it) => Some(CallKind::Pat),
+                    _ => None
+                }
+            };
+        }
+
+        if let Some(parent) = path.syntax().parent() {
+            path_ctx.kind = match_ast! {
+                match parent {
                     ast::PathType(_it) => Some(PathKind::Type),
-                    ast::PathExpr(it) => {
-                        path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
-                        Some(PathKind::Expr)
-                    },
-                    ast::TupleStructPat(it) => {
-                        path_ctx.has_call_parens = true;
-                        pat_ctx = Some(pattern_context_for(it.into()));
-                        Some(PathKind::Pat)
-                    },
-                    ast::RecordPat(it) => {
-                        pat_ctx = Some(pattern_context_for(it.into()));
-                        Some(PathKind::Pat)
-                    },
-                    ast::PathPat(it) => {
-                        pat_ctx = Some(pattern_context_for(it.into()));
-                        Some(PathKind::Pat)
-                    },
-                    ast::MacroCall(it) => it.excl_token().and(Some(PathKind::Mac)),
-                    ast::Meta(_it) => Some(PathKind::Attr),
-                    ast::Visibility(it) => Some(PathKind::Vis { has_in_token: it.in_token().is_some() }),
-                    ast::UseTree(_it) => Some(PathKind::Use),
+                    ast::PathExpr(_it) => Some(PathKind::Expr),
                     _ => None,
                 }
-            }
-        });
+            };
+        }
         path_ctx.has_type_args = segment.generic_arg_list().is_some();
 
         if let Some((path, use_tree_parent)) = path_or_use_tree_qualifier(&path) {
@@ -782,12 +802,12 @@ impl<'a> CompletionContext<'a> {
                     )
                 })
                 .map(|it| it.parent_path());
-            return Some((path_ctx, pat_ctx));
+            return Some(path_ctx);
         }
 
         if let Some(segment) = path.segment() {
             if segment.coloncolon_token().is_some() {
-                return Some((path_ctx, pat_ctx));
+                return Some(path_ctx);
             }
         }
 
@@ -811,46 +831,10 @@ impl<'a> CompletionContext<'a> {
                 None
             })
             .unwrap_or(false);
-        Some((path_ctx, pat_ctx))
+        Some(path_ctx)
     }
 }
 
-fn pattern_context_for(pat: ast::Pat) -> PatternContext {
-    let mut is_param = None;
-    let (refutability, has_type_ascription) =
-    pat
-        .syntax()
-        .ancestors()
-        .skip_while(|it| ast::Pat::can_cast(it.kind()))
-        .next()
-        .map_or((PatternRefutability::Irrefutable, false), |node| {
-            let refutability = match_ast! {
-                match node {
-                    ast::LetStmt(let_) => return (PatternRefutability::Irrefutable, let_.ty().is_some()),
-                    ast::Param(param) => {
-                        let is_closure_param = param
-                            .syntax()
-                            .ancestors()
-                            .nth(2)
-                            .and_then(ast::ClosureExpr::cast)
-                            .is_some();
-                        is_param = Some(if is_closure_param {
-                            ParamKind::Closure
-                        } else {
-                            ParamKind::Function
-                        });
-                        return (PatternRefutability::Irrefutable, param.ty().is_some())
-                    },
-                    ast::MatchArm(__) => PatternRefutability::Refutable,
-                    ast::Condition(__) => PatternRefutability::Refutable,
-                    ast::ForExpr(__) => PatternRefutability::Irrefutable,
-                    _ => PatternRefutability::Irrefutable,
-                }
-            };
-            (refutability, false)
-        });
-    PatternContext { refutability, is_param, has_type_ascription }
-}
 fn find_node_with_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<N> {
     syntax.covering_element(range).ancestors().find_map(N::cast)
 }
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs
index 6a087edc4f..d9618642c4 100644
--- a/crates/ide_completion/src/lib.rs
+++ b/crates/ide_completion/src/lib.rs
@@ -195,7 +195,7 @@ pub fn resolve_completion_edits(
         let items_with_name = items_locator::items_with_name(
             &ctx.sema,
             current_crate,
-            NameToImport::exact_case_sensitive(imported_name),
+            NameToImport::Exact(imported_name),
             items_locator::AssocItemSearch::Include,
             Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT.inner()),
         );
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs
index b50f76b911..13c739325c 100644
--- a/crates/ide_completion/src/patterns.rs
+++ b/crates/ide_completion/src/patterns.rs
@@ -33,6 +33,8 @@ pub(crate) enum ImmediatePrevSibling {
 /// from which file the nodes are.
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub(crate) enum ImmediateLocation {
+    Use,
+    UseTree,
     Rename,
     Impl,
     Trait,
@@ -45,7 +47,10 @@ pub(crate) enum ImmediateLocation {
     TypeBound,
     Variant,
     /// Fake file ast node
+    Attribute(ast::Attr),
+    /// Fake file ast node
     ModDeclaration(ast::Module),
+    Visibility(ast::Visibility),
     /// Original file ast node
     MethodCall {
         receiver: Option<ast::Expr>,
@@ -201,6 +206,9 @@ pub(crate) fn determine_location(
     let res = match_ast! {
         match parent {
             ast::IdentPat(_it) => ImmediateLocation::IdentPat,
+            ast::Use(_it) => ImmediateLocation::Use,
+            ast::UseTree(_it) => ImmediateLocation::UseTree,
+            ast::UseTreeList(_it) => ImmediateLocation::UseTree,
             ast::Rename(_it) => ImmediateLocation::Rename,
             ast::StmtList(_it) => ImmediateLocation::StmtList,
             ast::SourceFile(_it) => ImmediateLocation::ItemList,
@@ -234,6 +242,7 @@ pub(crate) fn determine_location(
                     return None;
                 }
             },
+            ast::Attr(it) => ImmediateLocation::Attribute(it),
             ast::FieldExpr(it) => {
                 let receiver = it
                     .expr()
@@ -259,6 +268,8 @@ pub(crate) fn determine_location(
                     .and_then(|r| find_node_with_range(original_file, r)),
                 has_parens: it.arg_list().map_or(false, |it| it.l_paren_token().is_some())
             },
+            ast::Visibility(it) => it.pub_token()
+                .and_then(|t| (t.text_range().end() < offset).then(|| ImmediateLocation::Visibility(it)))?,
             _ => return None,
         }
     };
@@ -406,6 +417,14 @@ mod tests {
         check_location(r"impl A { fn f$0 }", None);
     }
 
+    #[test]
+    fn test_use_loc() {
+        check_location(r"use f$0", ImmediateLocation::Use);
+        check_location(r"use f$0;", ImmediateLocation::Use);
+        check_location(r"use f::{f$0}", ImmediateLocation::UseTree);
+        check_location(r"use {f$0}", ImmediateLocation::UseTree);
+    }
+
     #[test]
     fn test_record_field_loc() {
         check_location(r"struct Foo { f$0 }", ImmediateLocation::RecordField);
diff --git a/crates/ide_completion/src/render/builder_ext.rs b/crates/ide_completion/src/render/builder_ext.rs
index 4d04054445..ea8222f76a 100644
--- a/crates/ide_completion/src/render/builder_ext.rs
+++ b/crates/ide_completion/src/render/builder_ext.rs
@@ -4,7 +4,7 @@ use either::Either;
 use itertools::Itertools;
 use syntax::ast::{self, HasName};
 
-use crate::{context::PathKind, item::Builder, patterns::ImmediateLocation, CompletionContext};
+use crate::{context::CallKind, item::Builder, patterns::ImmediateLocation, CompletionContext};
 
 #[derive(Debug)]
 pub(super) enum Params {
@@ -30,11 +30,11 @@ impl Builder {
         if !ctx.config.add_call_parenthesis {
             return false;
         }
-        if let Some(PathKind::Use) = ctx.path_kind() {
+        if ctx.in_use_tree() {
             cov_mark::hit!(no_parens_in_use_item);
             return false;
         }
-        if matches!(ctx.path_kind(), Some(PathKind::Expr | PathKind::Pat) if ctx.path_is_call())
+        if matches!(ctx.path_call_kind(), Some(CallKind::Expr | CallKind::Pat))
             | matches!(
                 ctx.completion_location,
                 Some(ImmediateLocation::MethodCall { has_parens: true, .. })
diff --git a/crates/ide_completion/src/render/macro_.rs b/crates/ide_completion/src/render/macro_.rs
index ac1f152aea..090bb5a715 100644
--- a/crates/ide_completion/src/render/macro_.rs
+++ b/crates/ide_completion/src/render/macro_.rs
@@ -1,15 +1,11 @@
 //! Renderer for macro invocations.
 
-use either::Either;
 use hir::HasSource;
 use ide_db::SymbolKind;
-use syntax::{
-    display::{fn_as_proc_macro_label, macro_label},
-    SmolStr,
-};
+use syntax::{display::macro_label, SmolStr};
 
 use crate::{
-    context::PathKind,
+    context::CallKind,
     item::{CompletionItem, ImportEdit},
     render::RenderContext,
 };
@@ -39,8 +35,7 @@ impl<'a> MacroRender<'a> {
         let name = name.to_smol_str();
         let docs = ctx.docs(macro_);
         let docs_str = docs.as_ref().map_or("", |s| s.as_str());
-        let (bra, ket) =
-            if macro_.is_fn_like() { guess_macro_braces(&name, docs_str) } else { ("", "") };
+        let (bra, ket) = guess_macro_braces(&name, docs_str);
 
         MacroRender { ctx, name, macro_, docs, bra, ket }
     }
@@ -52,17 +47,16 @@ impl<'a> MacroRender<'a> {
         } else {
             Some(self.ctx.source_range())
         }?;
-        let mut item =
-            CompletionItem::new(SymbolKind::from(self.macro_.kind()), source_range, self.label());
+        let mut item = CompletionItem::new(SymbolKind::Macro, source_range, self.label());
         item.set_deprecated(self.ctx.is_deprecated(self.macro_)).set_detail(self.detail());
 
         if let Some(import_to_add) = import_to_add {
             item.add_import(import_to_add);
         }
 
-        let needs_bang = self.macro_.is_fn_like()
-            && !matches!(self.ctx.completion.path_kind(), Some(PathKind::Mac | PathKind::Use));
-        let has_parens = self.ctx.completion.path_is_call();
+        let needs_bang = !(self.ctx.completion.in_use_tree()
+            || matches!(self.ctx.completion.path_call_kind(), Some(CallKind::Mac)));
+        let has_parens = self.ctx.completion.path_call_kind().is_some();
 
         match self.ctx.snippet_cap() {
             Some(cap) if needs_bang && !has_parens => {
@@ -85,14 +79,15 @@ impl<'a> MacroRender<'a> {
     }
 
     fn needs_bang(&self) -> bool {
-        !matches!(self.ctx.completion.path_kind(), Some(PathKind::Mac | PathKind::Use))
+        !self.ctx.completion.in_use_tree()
+            && !matches!(self.ctx.completion.path_call_kind(), Some(CallKind::Mac))
     }
 
     fn label(&self) -> SmolStr {
-        if !self.macro_.is_fn_like() {
-            self.name.clone()
-        } else if self.needs_bang() && self.ctx.snippet_cap().is_some() {
+        if self.needs_bang() && self.ctx.snippet_cap().is_some() {
             SmolStr::from_iter([&*self.name, "!", self.bra, "…", self.ket])
+        } else if self.macro_.kind() == hir::MacroKind::Derive {
+            self.name.clone()
         } else {
             self.banged_name()
         }
@@ -103,11 +98,8 @@ impl<'a> MacroRender<'a> {
     }
 
     fn detail(&self) -> Option<String> {
-        let detail = match self.macro_.source(self.ctx.db())?.value {
-            Either::Left(node) => macro_label(&node),
-            Either::Right(node) => fn_as_proc_macro_label(&node),
-        };
-        Some(detail)
+        let ast_node = self.macro_.source(self.ctx.db())?.value.left()?;
+        Some(macro_label(&ast_node))
     }
 }
 
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs
index d4bc7c7cf8..9a8adf167c 100644
--- a/crates/ide_db/src/helpers/import_assets.rs
+++ b/crates/ide_db/src/helpers/import_assets.rs
@@ -68,23 +68,17 @@ pub struct FirstSegmentUnresolved {
 /// A name that will be used during item lookups.
 #[derive(Debug, Clone)]
 pub enum NameToImport {
-    /// Requires items with names that exactly match the given string, bool indicatse case-sensitivity.
-    Exact(String, bool),
+    /// Requires items with names that exactly match the given string, case-sensitive.
+    Exact(String),
     /// Requires items with names that case-insensitively contain all letters from the string,
     /// in the same order, but not necessary adjacent.
     Fuzzy(String),
 }
 
-impl NameToImport {
-    pub fn exact_case_sensitive(s: String) -> NameToImport {
-        NameToImport::Exact(s, true)
-    }
-}
-
 impl NameToImport {
     pub fn text(&self) -> &str {
         match self {
-            NameToImport::Exact(text, _) => text.as_str(),
+            NameToImport::Exact(text) => text.as_str(),
             NameToImport::Fuzzy(text) => text.as_str(),
         }
     }
@@ -146,7 +140,7 @@ impl ImportAssets {
         if let Some(_) = path.qualifier() {
             return None;
         }
-        let name = NameToImport::exact_case_sensitive(path.segment()?.name_ref()?.to_string());
+        let name = NameToImport::Exact(path.segment()?.name_ref()?.to_string());
         let candidate_node = attr.syntax().clone();
         Some(Self {
             import_candidate: ImportCandidate::Path(PathImportCandidate { qualifier: None, name }),
@@ -236,18 +230,6 @@ impl ImportAssets {
         self.search_for(sema, None)
     }
 
-    pub fn path_fuzzy_name_to_exact(&mut self, case_sensitive: bool) {
-        if let ImportCandidate::Path(PathImportCandidate { name: to_import, .. }) =
-            &mut self.import_candidate
-        {
-            let name = match to_import {
-                NameToImport::Fuzzy(name) => std::mem::take(name),
-                _ => return,
-            };
-            *to_import = NameToImport::Exact(name, case_sensitive);
-        }
-    }
-
     fn search_for(
         &self,
         sema: &Semantics<RootDatabase>,
@@ -280,7 +262,7 @@ impl ImportAssets {
         .into_iter()
         .filter(|import| import.import_path.len() > 1)
         .filter(|import| !scope_definitions.contains(&ScopeDef::from(import.item_to_import)))
-        .sorted_by(|a, b| a.import_path.cmp(&b.import_path))
+        .sorted_by_key(|import| import.import_path.clone())
         .collect()
     }
 
@@ -309,9 +291,9 @@ fn path_applicable_imports(
                 current_crate,
                 path_candidate.name.clone(),
                 // FIXME: we could look up assoc items by the input and propose those in completion,
-                // but that requires more preparation first:
+                // but that requries more preparation first:
                 // * store non-trait assoc items in import_map to fully enable this lookup
-                // * ensure that does not degrade the performance (benchmark it)
+                // * ensure that does not degrade the performance (bencmark it)
                 // * write more logic to check for corresponding trait presence requirement (we're unable to flyimport multiple item right now)
                 // * improve the associated completion item matching and/or scoring to ensure no noisy completions appear
                 //
@@ -472,10 +454,8 @@ fn trait_applicable_items(
 
     let db = sema.db;
 
-    let inherent_traits = trait_candidate.receiver_ty.applicable_inherent_traits(db);
-    let env_traits = trait_candidate.receiver_ty.env_traits(db);
-    let related_traits = inherent_traits.chain(env_traits).collect::<FxHashSet<_>>();
-
+    let related_dyn_traits =
+        trait_candidate.receiver_ty.applicable_inherent_traits(db).collect::<FxHashSet<_>>();
     let mut required_assoc_items = FxHashSet::default();
     let trait_candidates = items_locator::items_with_name(
         sema,
@@ -487,7 +467,7 @@ fn trait_applicable_items(
     .filter_map(|input| item_as_assoc(db, input))
     .filter_map(|assoc| {
         let assoc_item_trait = assoc.containing_trait(db)?;
-        if related_traits.contains(&assoc_item_trait) {
+        if related_dyn_traits.contains(&assoc_item_trait) {
             None
         } else {
             required_assoc_items.insert(assoc);
@@ -581,9 +561,7 @@ impl ImportCandidate {
             Some(_) => None,
             None => Some(Self::TraitMethod(TraitImportCandidate {
                 receiver_ty: sema.type_of_expr(&method_call.receiver()?)?.adjusted(),
-                assoc_item_name: NameToImport::exact_case_sensitive(
-                    method_call.name_ref()?.to_string(),
-                ),
+                assoc_item_name: NameToImport::Exact(method_call.name_ref()?.to_string()),
             })),
         }
     }
@@ -595,7 +573,7 @@ impl ImportCandidate {
         path_import_candidate(
             sema,
             path.qualifier(),
-            NameToImport::exact_case_sensitive(path.segment()?.name_ref()?.to_string()),
+            NameToImport::Exact(path.segment()?.name_ref()?.to_string()),
         )
     }
 
@@ -609,7 +587,7 @@ impl ImportCandidate {
         }
         Some(ImportCandidate::Path(PathImportCandidate {
             qualifier: None,
-            name: NameToImport::exact_case_sensitive(name.to_string()),
+            name: NameToImport::Exact(name.to_string()),
         }))
     }
 
diff --git a/crates/ide_db/src/items_locator.rs b/crates/ide_db/src/items_locator.rs
index ca8266b6d2..e0dbe6caf0 100644
--- a/crates/ide_db/src/items_locator.rs
+++ b/crates/ide_db/src/items_locator.rs
@@ -50,18 +50,16 @@ pub fn items_with_name<'a>(
     });
 
     let (mut local_query, mut external_query) = match name {
-        NameToImport::Exact(exact_name, case_sensitive) => {
+        NameToImport::Exact(exact_name) => {
             let mut local_query = symbol_index::Query::new(exact_name.clone());
             local_query.exact();
 
             let external_query = import_map::Query::new(exact_name)
                 .name_only()
-                .search_mode(import_map::SearchMode::Equals);
+                .search_mode(import_map::SearchMode::Equals)
+                .case_sensitive();
 
-            (
-                local_query,
-                if case_sensitive { external_query.case_sensitive() } else { external_query },
-            )
+            (local_query, external_query)
         }
         NameToImport::Fuzzy(fuzzy_search_string) => {
             let mut local_query = symbol_index::Query::new(fuzzy_search_string.clone());
diff --git a/crates/ide_db/src/lib.rs b/crates/ide_db/src/lib.rs
index bcbb09e31b..0d14c176b5 100644
--- a/crates/ide_db/src/lib.rs
+++ b/crates/ide_db/src/lib.rs
@@ -171,18 +171,6 @@ pub enum SymbolKind {
     Variant,
 }
 
-impl From<hir::MacroKind> for SymbolKind {
-    fn from(it: hir::MacroKind) -> Self {
-        match it {
-            hir::MacroKind::Declarative | hir::MacroKind::BuiltIn | hir::MacroKind::ProcMacro => {
-                SymbolKind::Macro
-            }
-            hir::MacroKind::Derive => SymbolKind::Derive,
-            hir::MacroKind::Attr => SymbolKind::Attribute,
-        }
-    }
-}
-
 #[cfg(test)]
 mod tests {
     mod sourcegen_lints;
diff --git a/crates/ide_db/src/symbol_index.rs b/crates/ide_db/src/symbol_index.rs
index 62f4a81910..cc2b2bbb7b 100644
--- a/crates/ide_db/src/symbol_index.rs
+++ b/crates/ide_db/src/symbol_index.rs
@@ -36,15 +36,15 @@ use either::Either;
 use fst::{self, Streamer};
 use hir::{
     db::{DefDatabase, HirDatabase},
-    AdtId, AssocItemId, AssocItemLoc, DefHasSource, DefWithBodyId, HasSource, HirFileId, ImplId,
-    InFile, ItemContainerId, ItemLoc, ItemTreeNode, Lookup, MacroDef, Module, ModuleDefId,
+    AdtId, AssocContainerId, AssocItemId, AssocItemLoc, DefHasSource, DefWithBodyId, HasSource,
+    HirFileId, ImplId, InFile, ItemLoc, ItemTreeNode, Lookup, MacroDef, Module, ModuleDefId,
     ModuleId, Semantics, TraitId,
 };
 use rayon::prelude::*;
 use rustc_hash::FxHashSet;
 use syntax::{ast::HasName, AstNode, SmolStr, SyntaxNode, SyntaxNodePtr};
 
-use crate::{RootDatabase, SymbolKind};
+use crate::RootDatabase;
 
 #[derive(Debug)]
 pub struct Query {
@@ -430,23 +430,6 @@ impl FileSymbolKind {
     }
 }
 
-impl From<FileSymbolKind> for SymbolKind {
-    fn from(it: FileSymbolKind) -> Self {
-        match it {
-            FileSymbolKind::Const => SymbolKind::Const,
-            FileSymbolKind::Enum => SymbolKind::Enum,
-            FileSymbolKind::Function => SymbolKind::Function,
-            FileSymbolKind::Macro => SymbolKind::Macro,
-            FileSymbolKind::Module => SymbolKind::Module,
-            FileSymbolKind::Static => SymbolKind::Static,
-            FileSymbolKind::Struct => SymbolKind::Struct,
-            FileSymbolKind::Trait => SymbolKind::Trait,
-            FileSymbolKind::TypeAlias => SymbolKind::TypeAlias,
-            FileSymbolKind::Union => SymbolKind::Union,
-        }
-    }
-}
-
 /// Represents an outstanding module that the symbol collector must collect symbols from.
 struct SymbolCollectorWork {
     module_id: ModuleId,
@@ -508,7 +491,7 @@ impl<'a> SymbolCollector<'a> {
                     self.collect_from_body(id);
                 }
                 ModuleDefId::StaticId(id) => {
-                    self.push_decl_assoc(id, FileSymbolKind::Static);
+                    self.push_decl(id, FileSymbolKind::Static);
                     self.collect_from_body(id);
                 }
                 ModuleDefId::TraitId(id) => {
@@ -610,17 +593,17 @@ impl<'a> SymbolCollector<'a> {
         T: ItemTreeNode,
         <T as ItemTreeNode>::Source: HasName,
     {
-        fn container_name(db: &dyn HirDatabase, container: ItemContainerId) -> Option<SmolStr> {
+        fn container_name(db: &dyn HirDatabase, container: AssocContainerId) -> Option<SmolStr> {
             match container {
-                ItemContainerId::ModuleId(module_id) => {
+                AssocContainerId::ModuleId(module_id) => {
                     let module = Module::from(module_id);
                     module.name(db).and_then(|name| name.as_text())
                 }
-                ItemContainerId::TraitId(trait_id) => {
+                AssocContainerId::TraitId(trait_id) => {
                     let trait_data = db.trait_data(trait_id);
                     trait_data.name.as_text()
                 }
-                ItemContainerId::ImplId(_) | ItemContainerId::ExternBlockId(_) => None,
+                AssocContainerId::ImplId(_) => None,
             }
         }
 
diff --git a/crates/ide_diagnostics/src/handlers/incorrect_case.rs b/crates/ide_diagnostics/src/handlers/incorrect_case.rs
index 3206a63a90..6990b19cf3 100644
--- a/crates/ide_diagnostics/src/handlers/incorrect_case.rs
+++ b/crates/ide_diagnostics/src/handlers/incorrect_case.rs
@@ -397,24 +397,6 @@ extern {
         );
     }
 
-    #[test]
-    fn ignores_extern_items_from_macro() {
-        check_diagnostics(
-            r#"
-macro_rules! m {
-    () => {
-        fn NonSnakeCaseName(SOME_VAR: u8) -> u8;
-        pub static SomeStatic: u8 = 10;
-    }
-}
-
-extern {
-    m!();
-}
-            "#,
-        );
-    }
-
     #[test]
     fn bug_traits_arent_checked() {
         // FIXME: Traits and functions in traits aren't currently checked by
diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml
index d830ea93c8..c31cfaafc7 100644
--- a/crates/parser/Cargo.toml
+++ b/crates/parser/Cargo.toml
@@ -11,5 +11,3 @@ doctest = false
 
 [dependencies]
 drop_bomb = "0.1.4"
-
-limit = { path = "../limit", version = "0.0.0" }
diff --git a/crates/parser/src/parser.rs b/crates/parser/src/parser.rs
index 44c5f8e12f..5820ffd77d 100644
--- a/crates/parser/src/parser.rs
+++ b/crates/parser/src/parser.rs
@@ -3,7 +3,6 @@
 use std::cell::Cell;
 
 use drop_bomb::DropBomb;
-use limit::Limit;
 
 use crate::{
     event::Event,
@@ -27,8 +26,6 @@ pub(crate) struct Parser<'t> {
     steps: Cell<u32>,
 }
 
-static PARSER_STEP_LIMIT: Limit = Limit::new(15_000_000);
-
 impl<'t> Parser<'t> {
     pub(super) fn new(token_source: &'t mut dyn TokenSource) -> Parser<'t> {
         Parser { token_source, events: Vec::new(), steps: Cell::new(0) }
@@ -51,7 +48,7 @@ impl<'t> Parser<'t> {
         assert!(n <= 3);
 
         let steps = self.steps.get();
-        assert!(PARSER_STEP_LIMIT.check(steps as usize).is_ok(), "the parser seems stuck");
+        assert!(steps <= 10_000_000, "the parser seems stuck");
         self.steps.set(steps + 1);
 
         self.token_source.lookahead_nth(n).kind
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs
index 60f99f368b..0335f8b174 100644
--- a/crates/project_model/src/workspace.rs
+++ b/crates/project_model/src/workspace.rs
@@ -595,9 +595,6 @@ fn cargo_to_crate_graph(
 
         // Set deps to the core, std and to the lib target of the current package
         for (from, kind) in pkg_crates.get(&pkg).into_iter().flatten() {
-            // Add sysroot deps first so that a lib target named `core` etc. can overwrite them.
-            public_deps.add(*from, &mut crate_graph);
-
             if let Some((to, name)) = lib_tgt.clone() {
                 if to != *from && *kind != TargetKind::BuildScript {
                     // (build script can not depend on its library target)
@@ -609,6 +606,7 @@ fn cargo_to_crate_graph(
                     add_dep(&mut crate_graph, *from, name, to);
                 }
             }
+            public_deps.add(*from, &mut crate_graph);
         }
     }
 
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 6d2f042ccb..0863c40716 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -34,14 +34,14 @@ rayon = "1.5"
 mimalloc = { version = "0.1.19", default-features = false, optional = true }
 lsp-server = "0.5.1"
 tracing = "0.1"
-tracing-subscriber = { version = "0.3", default-features = false, features = [
+tracing-subscriber = { version = "0.2", default-features = false, features = [
     "env-filter",
     "registry",
     "fmt",
     "tracing-log",
 ] }
 tracing-log = "0.1.2"
-tracing-tree = "0.2"
+tracing-tree = { version = "0.1.10" }
 always-assert = "0.1"
 
 stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/crates/rust-analyzer/src/bin/logger.rs b/crates/rust-analyzer/src/bin/logger.rs
index db00029da2..083ab69587 100644
--- a/crates/rust-analyzer/src/bin/logger.rs
+++ b/crates/rust-analyzer/src/bin/logger.rs
@@ -2,9 +2,9 @@
 //! filter syntax and `tracing_appender` for non blocking output.
 
 use std::{
-    fmt,
+    fmt::{self, Write},
     fs::File,
-    io::{self, Stderr},
+    io,
     sync::Arc,
 };
 
@@ -12,10 +12,7 @@ use rust_analyzer::Result;
 use tracing::{level_filters::LevelFilter, Event, Subscriber};
 use tracing_log::NormalizeEvent;
 use tracing_subscriber::{
-    fmt::{
-        format::Writer, writer::BoxMakeWriter, FmtContext, FormatEvent, FormatFields,
-        FormattedFields, MakeWriter,
-    },
+    fmt::{writer::BoxMakeWriter, FmtContext, FormatEvent, FormatFields, FormattedFields},
     layer::SubscriberExt,
     registry::LookupSpan,
     util::SubscriberInitExt,
@@ -28,16 +25,6 @@ pub(crate) struct Logger {
     file: Option<File>,
 }
 
-struct MakeWriterStderr;
-
-impl<'a> MakeWriter<'a> for MakeWriterStderr {
-    type Writer = Stderr;
-
-    fn make_writer(&'a self) -> Self::Writer {
-        io::stderr()
-    }
-}
-
 impl Logger {
     pub(crate) fn new(file: Option<File>, filter: Option<&str>) -> Logger {
         let filter = filter.map_or(EnvFilter::default(), EnvFilter::new);
@@ -67,7 +54,7 @@ impl Logger {
             .with_indent_lines(true)
             .with_ansi(false)
             .with_indent_amount(2)
-            .with_writer(io::stderr);
+            .with_writer(std::io::stderr);
 
         let writer = match self.file {
             Some(file) => BoxMakeWriter::new(Arc::new(file)),
@@ -109,7 +96,7 @@ where
     fn format_event(
         &self,
         ctx: &FmtContext<'_, S, N>,
-        mut writer: Writer,
+        writer: &mut dyn Write,
         event: &Event<'_>,
     ) -> fmt::Result {
         // Write level and target
@@ -148,7 +135,7 @@ where
         })?;
 
         // Write fields on the event
-        ctx.field_format().format_fields(writer.by_ref(), event)?;
+        ctx.field_format().format_fields(writer, event)?;
 
         writeln!(writer)
     }
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index ab3c9e8227..bf153012d9 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -97,11 +97,6 @@ pub(crate) fn handle_memory_usage(state: &mut GlobalState, _: ()) -> Result<Stri
     Ok(out)
 }
 
-pub(crate) fn handle_shuffle_crate_graph(state: &mut GlobalState, _: ()) -> Result<()> {
-    state.analysis_host.shuffle_crate_graph();
-    Ok(())
-}
-
 pub(crate) fn handle_syntax_tree(
     snap: GlobalStateSnapshot,
     params: lsp_ext::SyntaxTreeParams,
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs
index 0e23094199..19137b942e 100644
--- a/crates/rust-analyzer/src/lsp_ext.rs
+++ b/crates/rust-analyzer/src/lsp_ext.rs
@@ -31,14 +31,6 @@ impl Request for MemoryUsage {
     const METHOD: &'static str = "rust-analyzer/memoryUsage";
 }
 
-pub enum ShuffleCrateGraph {}
-
-impl Request for ShuffleCrateGraph {
-    type Params = ();
-    type Result = ();
-    const METHOD: &'static str = "rust-analyzer/shuffleCrateGraph";
-}
-
 pub enum ReloadWorkspace {}
 
 impl Request for ReloadWorkspace {
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 65f9c87367..2d83cbee66 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -567,7 +567,6 @@ impl GlobalState {
                 Ok(())
             })?
             .on_sync_mut::<lsp_ext::MemoryUsage>(handlers::handle_memory_usage)?
-            .on_sync_mut::<lsp_ext::ShuffleCrateGraph>(handlers::handle_shuffle_crate_graph)?
             .on_sync::<lsp_ext::JoinLines>(handlers::handle_join_lines)?
             .on_sync::<lsp_ext::OnEnter>(handlers::handle_on_enter)?
             .on_sync::<lsp_types::request::SelectionRangeRequest>(handlers::handle_selection_range)?
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs
index e33b45cc8e..ee23f57934 100644
--- a/crates/stdx/src/lib.rs
+++ b/crates/stdx/src/lib.rs
@@ -193,11 +193,6 @@ where
     }
 }
 
-/// Returns all final segments of the argument, longest first.
-pub fn slice_tails<T>(this: &[T]) -> impl Iterator<Item = &[T]> {
-    (0..this.len()).map(|i| &this[i..])
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md
index c92395553c..b925f146a7 100644
--- a/docs/dev/lsp-extensions.md
+++ b/docs/dev/lsp-extensions.md
@@ -1,5 +1,5 @@
 <!---
-lsp_ext.rs hash: 49ffd619919ed74
+lsp_ext.rs hash: c6568e4035333f3a
 
 If you need to change the above hash to make the test pass, please check if you
 need to adjust this doc as well and ping this issue:
@@ -526,14 +526,6 @@ Renders rust-analyzer's crate graph as an SVG image.
 
 If `full` is `true`, the graph includes non-workspace crates (crates.io dependencies as well as sysroot crates).
 
-## Shuffle Crate Graph
-
-**Method:** `rust-analyzer/shuffleCrateGraph`
-
-**Request:** `null`
-
-Shuffles the crate IDs in the crate graph, for debugging purposes.
-
 ## Expand Macro
 
 **Method:** `rust-analyzer/expandMacro`
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index 038a07c75a..686844132c 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -17,7 +17,7 @@
             },
             "devDependencies": {
                 "@types/node": "~14.17.5",
-                "@types/vscode": "~1.62.0",
+                "@types/vscode": "^1.61.0",
                 "@typescript-eslint/eslint-plugin": "^5.5.0",
                 "@typescript-eslint/parser": "^5.5.0",
                 "@vscode/test-electron": "^1.6.2",
@@ -29,7 +29,7 @@
                 "vsce": "^2.5.1"
             },
             "engines": {
-                "vscode": "^1.62.0"
+                "vscode": "^1.61.0"
             }
         },
         "node_modules/@eslint/eslintrc": {
@@ -149,13 +149,13 @@
             "dev": true
         },
         "node_modules/@typescript-eslint/eslint-plugin": {
-            "version": "5.6.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.6.0.tgz",
-            "integrity": "sha512-MIbeMy5qfLqtgs1hWd088k1hOuRsN9JrHUPwVVKCD99EOUqScd7SrwoZl4Gso05EAP9w1kvLWUVGJOVpRPkDPA==",
+            "version": "5.5.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.5.0.tgz",
+            "integrity": "sha512-4bV6fulqbuaO9UMXU0Ia0o6z6if+kmMRW8rMRyfqXj/eGrZZRGedS4n0adeGNnjr8LKAM495hrQ7Tea52UWmQA==",
             "dev": true,
             "dependencies": {
-                "@typescript-eslint/experimental-utils": "5.6.0",
-                "@typescript-eslint/scope-manager": "5.6.0",
+                "@typescript-eslint/experimental-utils": "5.5.0",
+                "@typescript-eslint/scope-manager": "5.5.0",
                 "debug": "^4.3.2",
                 "functional-red-black-tree": "^1.0.1",
                 "ignore": "^5.1.8",
@@ -181,15 +181,15 @@
             }
         },
         "node_modules/@typescript-eslint/experimental-utils": {
-            "version": "5.6.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.6.0.tgz",
-            "integrity": "sha512-VDoRf3Qj7+W3sS/ZBXZh3LBzp0snDLEgvp6qj0vOAIiAPM07bd5ojQ3CTzF/QFl5AKh7Bh1ycgj6lFBJHUt/DA==",
+            "version": "5.5.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.5.0.tgz",
+            "integrity": "sha512-kjWeeVU+4lQ1SLYErRKV5yDXbWDPkpbzTUUlfAUifPYvpX0qZlrcCZ96/6oWxt3QxtK5WVhXz+KsnwW9cIW+3A==",
             "dev": true,
             "dependencies": {
                 "@types/json-schema": "^7.0.9",
-                "@typescript-eslint/scope-manager": "5.6.0",
-                "@typescript-eslint/types": "5.6.0",
-                "@typescript-eslint/typescript-estree": "5.6.0",
+                "@typescript-eslint/scope-manager": "5.5.0",
+                "@typescript-eslint/types": "5.5.0",
+                "@typescript-eslint/typescript-estree": "5.5.0",
                 "eslint-scope": "^5.1.1",
                 "eslint-utils": "^3.0.0"
             },
@@ -205,14 +205,14 @@
             }
         },
         "node_modules/@typescript-eslint/parser": {
-            "version": "5.6.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.6.0.tgz",
-            "integrity": "sha512-YVK49NgdUPQ8SpCZaOpiq1kLkYRPMv9U5gcMrywzI8brtwZjr/tG3sZpuHyODt76W/A0SufNjYt9ZOgrC4tLIQ==",
+            "version": "5.5.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.5.0.tgz",
+            "integrity": "sha512-JsXBU+kgQOAgzUn2jPrLA+Rd0Y1dswOlX3hp8MuRO1hQDs6xgHtbCXEiAu7bz5hyVURxbXcA2draasMbNqrhmg==",
             "dev": true,
             "dependencies": {
-                "@typescript-eslint/scope-manager": "5.6.0",
-                "@typescript-eslint/types": "5.6.0",
-                "@typescript-eslint/typescript-estree": "5.6.0",
+                "@typescript-eslint/scope-manager": "5.5.0",
+                "@typescript-eslint/types": "5.5.0",
+                "@typescript-eslint/typescript-estree": "5.5.0",
                 "debug": "^4.3.2"
             },
             "engines": {
@@ -232,13 +232,13 @@
             }
         },
         "node_modules/@typescript-eslint/scope-manager": {
-            "version": "5.6.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.6.0.tgz",
-            "integrity": "sha512-1U1G77Hw2jsGWVsO2w6eVCbOg0HZ5WxL/cozVSTfqnL/eB9muhb8THsP0G3w+BB5xAHv9KptwdfYFAUfzcIh4A==",
+            "version": "5.5.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.5.0.tgz",
+            "integrity": "sha512-0/r656RmRLo7CbN4Mdd+xZyPJ/fPCKhYdU6mnZx+8msAD8nJSP8EyCFkzbd6vNVZzZvWlMYrSNekqGrCBqFQhg==",
             "dev": true,
             "dependencies": {
-                "@typescript-eslint/types": "5.6.0",
-                "@typescript-eslint/visitor-keys": "5.6.0"
+                "@typescript-eslint/types": "5.5.0",
+                "@typescript-eslint/visitor-keys": "5.5.0"
             },
             "engines": {
                 "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -249,9 +249,9 @@
             }
         },
         "node_modules/@typescript-eslint/types": {
-            "version": "5.6.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.6.0.tgz",
-            "integrity": "sha512-OIZffked7mXv4mXzWU5MgAEbCf9ecNJBKi+Si6/I9PpTaj+cf2x58h2oHW5/P/yTnPkKaayfjhLvx+crnl5ubA==",
+            "version": "5.5.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.5.0.tgz",
+            "integrity": "sha512-OaYTqkW3GnuHxqsxxJ6KypIKd5Uw7bFiQJZRyNi1jbMJnK3Hc/DR4KwB6KJj6PBRkJJoaNwzMNv9vtTk87JhOg==",
             "dev": true,
             "engines": {
                 "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -262,13 +262,13 @@
             }
         },
         "node_modules/@typescript-eslint/typescript-estree": {
-            "version": "5.6.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.6.0.tgz",
-            "integrity": "sha512-92vK5tQaE81rK7fOmuWMrSQtK1IMonESR+RJR2Tlc7w4o0MeEdjgidY/uO2Gobh7z4Q1hhS94Cr7r021fMVEeA==",
+            "version": "5.5.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.5.0.tgz",
+            "integrity": "sha512-pVn8btYUiYrjonhMAO0yG8lm7RApzy2L4RC7Td/mC/qFkyf6vRbGyZozoA94+w6D2Y2GRqpMoCWcwx/EUOzyoQ==",
             "dev": true,
             "dependencies": {
-                "@typescript-eslint/types": "5.6.0",
-                "@typescript-eslint/visitor-keys": "5.6.0",
+                "@typescript-eslint/types": "5.5.0",
+                "@typescript-eslint/visitor-keys": "5.5.0",
                 "debug": "^4.3.2",
                 "globby": "^11.0.4",
                 "is-glob": "^4.0.3",
@@ -289,12 +289,12 @@
             }
         },
         "node_modules/@typescript-eslint/visitor-keys": {
-            "version": "5.6.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.6.0.tgz",
-            "integrity": "sha512-1p7hDp5cpRFUyE3+lvA74egs+RWSgumrBpzBCDzfTFv0aQ7lIeay80yU0hIxgAhwQ6PcasW35kaOCyDOv6O/Ng==",
+            "version": "5.5.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.5.0.tgz",
+            "integrity": "sha512-4GzJ1kRtsWzHhdM40tv0ZKHNSbkDhF0Woi/TDwVJX6UICwJItvP7ZTXbjTkCdrors7ww0sYe0t+cIKDAJwZ7Kw==",
             "dev": true,
             "dependencies": {
-                "@typescript-eslint/types": "5.6.0",
+                "@typescript-eslint/types": "5.5.0",
                 "eslint-visitor-keys": "^3.0.0"
             },
             "engines": {
@@ -999,9 +999,9 @@
             }
         },
         "node_modules/d3-format": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
-            "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==",
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.0.1.tgz",
+            "integrity": "sha512-hdL7+HBIohpgfolhBxr1KX47VMD6+vVD/oEFrxk5yhmzV2prk99EkFKYpXuhVkFpTgHdJ6/4bYcjdLPPXV4tIA==",
             "engines": {
                 "node": ">=12"
             }
@@ -1110,9 +1110,9 @@
             }
         },
         "node_modules/d3-hierarchy": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.0.tgz",
-            "integrity": "sha512-RZWnhsvcrf81F+khYxu2IOfoSwfCGla9je0JQaRIEuPOgJd+3cKdvAYyMXvTt0MDbluiHThYBQzIb0xxXfnqmA==",
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.0.1.tgz",
+            "integrity": "sha512-RlLTaofEoOrMK1JoXYIGhKTkJFI/6rFrYPgxy6QlZo2BcVc4HGTqEU0rPpzuMq5T/5XcMtAzv1XiLA3zRTfygw==",
             "engines": {
                 "node": ">=12"
             }
@@ -1215,9 +1215,9 @@
             }
         },
         "node_modules/d3-time-format": {
-            "version": "4.1.0",
-            "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
-            "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.0.0.tgz",
+            "integrity": "sha512-nzaCwlj+ZVBIlFuVOT1RmU+6xb/7D5IcnhHzHQcBgS/aTa5K9fWZNN5LCXA27LgF5WxoSNJqKBbLcGMtM6Ca6A==",
             "dependencies": {
                 "d3-time": "1 - 3"
             },
@@ -1778,9 +1778,9 @@
             }
         },
         "node_modules/eslint": {
-            "version": "8.4.1",
-            "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.4.1.tgz",
-            "integrity": "sha512-TxU/p7LB1KxQ6+7aztTnO7K0i+h0tDi81YRY9VzB6Id71kNz+fFYnf5HD5UOQmxkzcoa0TlVZf9dpMtUv0GpWg==",
+            "version": "8.4.0",
+            "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.4.0.tgz",
+            "integrity": "sha512-kv0XQcAQJL/VD9THQKhTQZVqkJKA+tIj/v2ZKNaIHRAADcJWFb+B/BAewUYuF6UVg1s2xC5qXVoDk0G8sKGeTA==",
             "dev": true,
             "dependencies": {
                 "@eslint/eslintrc": "^1.0.5",
@@ -2874,9 +2874,9 @@
             }
         },
         "node_modules/object-inspect": {
-            "version": "1.11.1",
-            "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.1.tgz",
-            "integrity": "sha512-If7BjFlpkzzBeV1cqgT3OSWT3azyoxDGajR+iGnFBfVV2EWyDyWaZZW2ERDjUaY2QM8i5jI3Sj7mhsM4DDAqWA==",
+            "version": "1.11.0",
+            "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz",
+            "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==",
             "dev": true,
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
@@ -3075,9 +3075,9 @@
             }
         },
         "node_modules/qs": {
-            "version": "6.10.2",
-            "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.2.tgz",
-            "integrity": "sha512-mSIdjzqznWgfd4pMii7sHtaYF8rx8861hBO80SraY5GT0XQibWZWJSid0avzHGkDIZLImux2S5mXO0Hfct2QCw==",
+            "version": "6.10.1",
+            "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz",
+            "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==",
             "dev": true,
             "dependencies": {
                 "side-channel": "^1.0.4"
@@ -4059,13 +4059,13 @@
             "dev": true
         },
         "@typescript-eslint/eslint-plugin": {
-            "version": "5.6.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.6.0.tgz",
-            "integrity": "sha512-MIbeMy5qfLqtgs1hWd088k1hOuRsN9JrHUPwVVKCD99EOUqScd7SrwoZl4Gso05EAP9w1kvLWUVGJOVpRPkDPA==",
+            "version": "5.5.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.5.0.tgz",
+            "integrity": "sha512-4bV6fulqbuaO9UMXU0Ia0o6z6if+kmMRW8rMRyfqXj/eGrZZRGedS4n0adeGNnjr8LKAM495hrQ7Tea52UWmQA==",
             "dev": true,
             "requires": {
-                "@typescript-eslint/experimental-utils": "5.6.0",
-                "@typescript-eslint/scope-manager": "5.6.0",
+                "@typescript-eslint/experimental-utils": "5.5.0",
+                "@typescript-eslint/scope-manager": "5.5.0",
                 "debug": "^4.3.2",
                 "functional-red-black-tree": "^1.0.1",
                 "ignore": "^5.1.8",
@@ -4075,55 +4075,55 @@
             }
         },
         "@typescript-eslint/experimental-utils": {
-            "version": "5.6.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.6.0.tgz",
-            "integrity": "sha512-VDoRf3Qj7+W3sS/ZBXZh3LBzp0snDLEgvp6qj0vOAIiAPM07bd5ojQ3CTzF/QFl5AKh7Bh1ycgj6lFBJHUt/DA==",
+            "version": "5.5.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.5.0.tgz",
+            "integrity": "sha512-kjWeeVU+4lQ1SLYErRKV5yDXbWDPkpbzTUUlfAUifPYvpX0qZlrcCZ96/6oWxt3QxtK5WVhXz+KsnwW9cIW+3A==",
             "dev": true,
             "requires": {
                 "@types/json-schema": "^7.0.9",
-                "@typescript-eslint/scope-manager": "5.6.0",
-                "@typescript-eslint/types": "5.6.0",
-                "@typescript-eslint/typescript-estree": "5.6.0",
+                "@typescript-eslint/scope-manager": "5.5.0",
+                "@typescript-eslint/types": "5.5.0",
+                "@typescript-eslint/typescript-estree": "5.5.0",
                 "eslint-scope": "^5.1.1",
                 "eslint-utils": "^3.0.0"
             }
         },
         "@typescript-eslint/parser": {
-            "version": "5.6.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.6.0.tgz",
-            "integrity": "sha512-YVK49NgdUPQ8SpCZaOpiq1kLkYRPMv9U5gcMrywzI8brtwZjr/tG3sZpuHyODt76W/A0SufNjYt9ZOgrC4tLIQ==",
+            "version": "5.5.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.5.0.tgz",
+            "integrity": "sha512-JsXBU+kgQOAgzUn2jPrLA+Rd0Y1dswOlX3hp8MuRO1hQDs6xgHtbCXEiAu7bz5hyVURxbXcA2draasMbNqrhmg==",
             "dev": true,
             "requires": {
-                "@typescript-eslint/scope-manager": "5.6.0",
-                "@typescript-eslint/types": "5.6.0",
-                "@typescript-eslint/typescript-estree": "5.6.0",
+                "@typescript-eslint/scope-manager": "5.5.0",
+                "@typescript-eslint/types": "5.5.0",
+                "@typescript-eslint/typescript-estree": "5.5.0",
                 "debug": "^4.3.2"
             }
         },
         "@typescript-eslint/scope-manager": {
-            "version": "5.6.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.6.0.tgz",
-            "integrity": "sha512-1U1G77Hw2jsGWVsO2w6eVCbOg0HZ5WxL/cozVSTfqnL/eB9muhb8THsP0G3w+BB5xAHv9KptwdfYFAUfzcIh4A==",
+            "version": "5.5.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.5.0.tgz",
+            "integrity": "sha512-0/r656RmRLo7CbN4Mdd+xZyPJ/fPCKhYdU6mnZx+8msAD8nJSP8EyCFkzbd6vNVZzZvWlMYrSNekqGrCBqFQhg==",
             "dev": true,
             "requires": {
-                "@typescript-eslint/types": "5.6.0",
-                "@typescript-eslint/visitor-keys": "5.6.0"
+                "@typescript-eslint/types": "5.5.0",
+                "@typescript-eslint/visitor-keys": "5.5.0"
             }
         },
         "@typescript-eslint/types": {
-            "version": "5.6.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.6.0.tgz",
-            "integrity": "sha512-OIZffked7mXv4mXzWU5MgAEbCf9ecNJBKi+Si6/I9PpTaj+cf2x58h2oHW5/P/yTnPkKaayfjhLvx+crnl5ubA==",
+            "version": "5.5.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.5.0.tgz",
+            "integrity": "sha512-OaYTqkW3GnuHxqsxxJ6KypIKd5Uw7bFiQJZRyNi1jbMJnK3Hc/DR4KwB6KJj6PBRkJJoaNwzMNv9vtTk87JhOg==",
             "dev": true
         },
         "@typescript-eslint/typescript-estree": {
-            "version": "5.6.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.6.0.tgz",
-            "integrity": "sha512-92vK5tQaE81rK7fOmuWMrSQtK1IMonESR+RJR2Tlc7w4o0MeEdjgidY/uO2Gobh7z4Q1hhS94Cr7r021fMVEeA==",
+            "version": "5.5.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.5.0.tgz",
+            "integrity": "sha512-pVn8btYUiYrjonhMAO0yG8lm7RApzy2L4RC7Td/mC/qFkyf6vRbGyZozoA94+w6D2Y2GRqpMoCWcwx/EUOzyoQ==",
             "dev": true,
             "requires": {
-                "@typescript-eslint/types": "5.6.0",
-                "@typescript-eslint/visitor-keys": "5.6.0",
+                "@typescript-eslint/types": "5.5.0",
+                "@typescript-eslint/visitor-keys": "5.5.0",
                 "debug": "^4.3.2",
                 "globby": "^11.0.4",
                 "is-glob": "^4.0.3",
@@ -4132,12 +4132,12 @@
             }
         },
         "@typescript-eslint/visitor-keys": {
-            "version": "5.6.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.6.0.tgz",
-            "integrity": "sha512-1p7hDp5cpRFUyE3+lvA74egs+RWSgumrBpzBCDzfTFv0aQ7lIeay80yU0hIxgAhwQ6PcasW35kaOCyDOv6O/Ng==",
+            "version": "5.5.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.5.0.tgz",
+            "integrity": "sha512-4GzJ1kRtsWzHhdM40tv0ZKHNSbkDhF0Woi/TDwVJX6UICwJItvP7ZTXbjTkCdrors7ww0sYe0t+cIKDAJwZ7Kw==",
             "dev": true,
             "requires": {
-                "@typescript-eslint/types": "5.6.0",
+                "@typescript-eslint/types": "5.5.0",
                 "eslint-visitor-keys": "^3.0.0"
             }
         },
@@ -4662,9 +4662,9 @@
             }
         },
         "d3-format": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
-            "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA=="
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.0.1.tgz",
+            "integrity": "sha512-hdL7+HBIohpgfolhBxr1KX47VMD6+vVD/oEFrxk5yhmzV2prk99EkFKYpXuhVkFpTgHdJ6/4bYcjdLPPXV4tIA=="
         },
         "d3-geo": {
             "version": "3.0.1",
@@ -4763,9 +4763,9 @@
             }
         },
         "d3-hierarchy": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.0.tgz",
-            "integrity": "sha512-RZWnhsvcrf81F+khYxu2IOfoSwfCGla9je0JQaRIEuPOgJd+3cKdvAYyMXvTt0MDbluiHThYBQzIb0xxXfnqmA=="
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.0.1.tgz",
+            "integrity": "sha512-RlLTaofEoOrMK1JoXYIGhKTkJFI/6rFrYPgxy6QlZo2BcVc4HGTqEU0rPpzuMq5T/5XcMtAzv1XiLA3zRTfygw=="
         },
         "d3-interpolate": {
             "version": "3.0.1",
@@ -4838,9 +4838,9 @@
             }
         },
         "d3-time-format": {
-            "version": "4.1.0",
-            "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
-            "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.0.0.tgz",
+            "integrity": "sha512-nzaCwlj+ZVBIlFuVOT1RmU+6xb/7D5IcnhHzHQcBgS/aTa5K9fWZNN5LCXA27LgF5WxoSNJqKBbLcGMtM6Ca6A==",
             "requires": {
                 "d3-time": "1 - 3"
             }
@@ -5209,9 +5209,9 @@
             "dev": true
         },
         "eslint": {
-            "version": "8.4.1",
-            "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.4.1.tgz",
-            "integrity": "sha512-TxU/p7LB1KxQ6+7aztTnO7K0i+h0tDi81YRY9VzB6Id71kNz+fFYnf5HD5UOQmxkzcoa0TlVZf9dpMtUv0GpWg==",
+            "version": "8.4.0",
+            "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.4.0.tgz",
+            "integrity": "sha512-kv0XQcAQJL/VD9THQKhTQZVqkJKA+tIj/v2ZKNaIHRAADcJWFb+B/BAewUYuF6UVg1s2xC5qXVoDk0G8sKGeTA==",
             "dev": true,
             "requires": {
                 "@eslint/eslintrc": "^1.0.5",
@@ -6065,9 +6065,9 @@
             "dev": true
         },
         "object-inspect": {
-            "version": "1.11.1",
-            "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.1.tgz",
-            "integrity": "sha512-If7BjFlpkzzBeV1cqgT3OSWT3azyoxDGajR+iGnFBfVV2EWyDyWaZZW2ERDjUaY2QM8i5jI3Sj7mhsM4DDAqWA==",
+            "version": "1.11.0",
+            "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz",
+            "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==",
             "dev": true
         },
         "once": {
@@ -6226,9 +6226,9 @@
             "dev": true
         },
         "qs": {
-            "version": "6.10.2",
-            "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.2.tgz",
-            "integrity": "sha512-mSIdjzqznWgfd4pMii7sHtaYF8rx8861hBO80SraY5GT0XQibWZWJSid0avzHGkDIZLImux2S5mXO0Hfct2QCw==",
+            "version": "6.10.1",
+            "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz",
+            "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==",
             "dev": true,
             "requires": {
                 "side-channel": "^1.0.4"
diff --git a/editors/code/package.json b/editors/code/package.json
index 2460308820..da4fa15b02 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -21,7 +21,7 @@
         "Programming Languages"
     ],
     "engines": {
-        "vscode": "^1.62.0"
+        "vscode": "^1.61.0"
     },
     "enableProposedApi": true,
     "scripts": {
@@ -44,7 +44,7 @@
     },
     "devDependencies": {
         "@types/node": "~14.17.5",
-        "@types/vscode": "~1.62.0",
+        "@types/vscode": "^1.61.0",
         "@typescript-eslint/eslint-plugin": "^5.5.0",
         "@typescript-eslint/parser": "^5.5.0",
         "@vscode/test-electron": "^1.6.2",
@@ -171,11 +171,6 @@
                 "title": "Memory Usage (Clears Database)",
                 "category": "Rust Analyzer"
             },
-            {
-                "command": "rust-analyzer.shuffleCrateGraph",
-                "title": "Shuffle Crate Graph",
-                "category": "Rust Analyzer"
-            },
             {
                 "command": "rust-analyzer.reloadWorkspace",
                 "title": "Reload workspace",
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index fe006a63e2..c9385361f8 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -85,15 +85,6 @@ export function memoryUsage(ctx: Ctx): Cmd {
     };
 }
 
-export function shuffleCrateGraph(ctx: Ctx): Cmd {
-    return async () => {
-        const client = ctx.client;
-        if (!client) return;
-
-        await client.sendRequest(ra.shuffleCrateGraph);
-    };
-}
-
 export function matchingBrace(ctx: Ctx): Cmd {
     return async () => {
         const editor = ctx.activeRustEditor;
diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts
index a21a742a57..90796e611e 100644
--- a/editors/code/src/lsp_ext.ts
+++ b/editors/code/src/lsp_ext.ts
@@ -9,7 +9,6 @@ export interface AnalyzerStatusParams {
 }
 export const analyzerStatus = new lc.RequestType<AnalyzerStatusParams, string, void>("rust-analyzer/analyzerStatus");
 export const memoryUsage = new lc.RequestType0<string, void>("rust-analyzer/memoryUsage");
-export const shuffleCrateGraph = new lc.RequestType0<null, void>("rust-analyzer/shuffleCrateGraph");
 
 export interface ServerStatusParams {
     health: "ok" | "warning" | "error";
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index a06fc09fc8..734f224503 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -117,7 +117,6 @@ async function initCommonContext(context: vscode.ExtensionContext, ctx: Ctx) {
 
     ctx.registerCommand('analyzerStatus', commands.analyzerStatus);
     ctx.registerCommand('memoryUsage', commands.memoryUsage);
-    ctx.registerCommand('shuffleCrateGraph', commands.shuffleCrateGraph);
     ctx.registerCommand('reloadWorkspace', commands.reloadWorkspace);
     ctx.registerCommand('matchingBrace', commands.matchingBrace);
     ctx.registerCommand('joinLines', commands.joinLines);


Test patch:
diff --git a/crates/hir_def/src/item_tree/tests.rs b/crates/hir_def/src/item_tree/tests.rs
index 1969913bf9..7671ccefd1 100644
--- a/crates/hir_def/src/item_tree/tests.rs
+++ b/crates/hir_def/src/item_tree/tests.rs
@@ -70,13 +70,13 @@ extern "C" {
             #[on_extern_block]  // AttrId { is_doc_comment: false, ast_index: 0 }
             extern "C" {
                 #[on_extern_type]  // AttrId { is_doc_comment: false, ast_index: 0 }
-                pub(self) type ExType;
+                pub(self) type ExType;  // extern
 
                 #[on_extern_static]  // AttrId { is_doc_comment: false, ast_index: 0 }
-                pub(self) static EX_STATIC: u8 = _;
+                pub(self) static EX_STATIC: u8 = _;  // extern
 
                 #[on_extern_fn]  // AttrId { is_doc_comment: false, ast_index: 0 }
-                // flags = 0x20
+                // flags = 0x60
                 pub(self) fn ex_fn() -> ();
             }
         "##]],
diff --git a/crates/hir_def/src/macro_expansion_tests/builtin_fn_macro.rs b/crates/hir_def/src/macro_expansion_tests/builtin_fn_macro.rs
index 6e91301ecd..06039e95c5 100644
--- a/crates/hir_def/src/macro_expansion_tests/builtin_fn_macro.rs
+++ b/crates/hir_def/src/macro_expansion_tests/builtin_fn_macro.rs
@@ -313,40 +313,6 @@ fn main() { "foor0bar\nfalse"; }
     );
 }
 
-#[test]
-fn test_concat_with_captured_expr() {
-    check(
-        r##"
-#[rustc_builtin_macro]
-macro_rules! concat {}
-
-macro_rules! surprise {
-    () => { "s" };
-}
-
-macro_rules! stuff {
-    ($string:expr) => { concat!($string) };
-}
-
-fn main() { concat!(surprise!()); }
-"##,
-        expect![[r##"
-#[rustc_builtin_macro]
-macro_rules! concat {}
-
-macro_rules! surprise {
-    () => { "s" };
-}
-
-macro_rules! stuff {
-    ($string:expr) => { concat!($string) };
-}
-
-fn main() { "s"; }
-"##]],
-    );
-}
-
 #[test]
 fn test_concat_idents_expand() {
     check(
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs
index 731605ced1..9b1f682b61 100644
--- a/crates/hir_ty/src/tests/method_resolution.rs
+++ b/crates/hir_ty/src/tests/method_resolution.rs
@@ -1248,28 +1248,6 @@ fn f() {
     );
 }
 
-#[test]
-fn trait_impl_in_synstructure_const() {
-    check_types(
-        r#"
-struct S;
-
-trait Tr {
-    fn method(&self) -> u16;
-}
-
-const _DERIVE_Tr_: () = {
-    impl Tr for S {}
-};
-
-fn f() {
-    S.method();
-  //^^^^^^^^^^ u16
-}
-    "#,
-    );
-}
-
 #[test]
 fn inherent_impl_in_unnamed_const() {
     check_types(
diff --git a/crates/ide_completion/src/tests/attribute.rs b/crates/ide_completion/src/tests/attribute.rs
index c3dce61e7d..8141fab299 100644
--- a/crates/ide_completion/src/tests/attribute.rs
+++ b/crates/ide_completion/src/tests/attribute.rs
@@ -9,12 +9,12 @@ fn check(ra_fixture: &str, expect: Expect) {
 }
 
 #[test]
-fn proc_macros() {
+fn doesnt_complete_items() {
     check(
         r#"
-//- proc_macros: identity
-#[$0]
 struct Foo;
+#[$0]
+use self as this;
 "#,
         expect![[r#"
             at allow(…)
@@ -29,29 +29,19 @@ struct Foo;
             at doc(alias = "…")
             at must_use
             at no_mangle
-            at derive(…)
-            at repr(…)
-            at non_exhaustive
-            kw self
-            kw super
-            kw crate
-            md proc_macros
         "#]],
     )
 }
 
 #[test]
-fn proc_macros_qualified() {
+fn doesnt_complete_qualified() {
     check(
         r#"
-//- proc_macros: identity
-#[proc_macros::$0]
 struct Foo;
+#[foo::$0]
+use self as this;
 "#,
-        expect![[r#"
-            at input_replace pub macro input_replace
-            at identity      pub macro identity
-        "#]],
+        expect![[r#""#]],
     )
 }
 
@@ -71,9 +61,6 @@ fn with_existing_attr() {
             at deny(…)
             at forbid(…)
             at warn(…)
-            kw self
-            kw super
-            kw crate
         "#]],
     )
 }
@@ -103,9 +90,6 @@ fn attr_on_source_file() {
             at recursion_limit = "…"
             at type_length_limit = …
             at windows_subsystem = "…"
-            kw self
-            kw super
-            kw crate
         "#]],
     );
 }
@@ -129,9 +113,6 @@ fn attr_on_module() {
             at no_mangle
             at macro_use
             at path = "…"
-            kw self
-            kw super
-            kw crate
         "#]],
     );
     check(
@@ -150,9 +131,6 @@ fn attr_on_module() {
             at must_use
             at no_mangle
             at no_implicit_prelude
-            kw self
-            kw super
-            kw crate
         "#]],
     );
 }
@@ -176,9 +154,6 @@ fn attr_on_macro_rules() {
             at no_mangle
             at macro_export
             at macro_use
-            kw self
-            kw super
-            kw crate
         "#]],
     );
 }
@@ -200,9 +175,6 @@ fn attr_on_macro_def() {
             at doc(alias = "…")
             at must_use
             at no_mangle
-            kw self
-            kw super
-            kw crate
         "#]],
     );
 }
@@ -225,9 +197,6 @@ fn attr_on_extern_crate() {
             at must_use
             at no_mangle
             at macro_use
-            kw self
-            kw super
-            kw crate
         "#]],
     );
 }
@@ -249,9 +218,6 @@ fn attr_on_use() {
             at doc(alias = "…")
             at must_use
             at no_mangle
-            kw self
-            kw super
-            kw crate
         "#]],
     );
 }
@@ -273,9 +239,6 @@ fn attr_on_type_alias() {
             at doc(alias = "…")
             at must_use
             at no_mangle
-            kw self
-            kw super
-            kw crate
         "#]],
     );
 }
@@ -300,9 +263,6 @@ fn attr_on_struct() {
             at derive(…)
             at repr(…)
             at non_exhaustive
-            kw self
-            kw super
-            kw crate
         "#]],
     );
 }
@@ -327,9 +287,6 @@ fn attr_on_enum() {
             at derive(…)
             at repr(…)
             at non_exhaustive
-            kw self
-            kw super
-            kw crate
         "#]],
     );
 }
@@ -351,9 +308,6 @@ fn attr_on_const() {
             at doc(alias = "…")
             at must_use
             at no_mangle
-            kw self
-            kw super
-            kw crate
         "#]],
     );
 }
@@ -380,9 +334,6 @@ fn attr_on_static() {
             at link_section = "…"
             at global_allocator
             at used
-            kw self
-            kw super
-            kw crate
         "#]],
     );
 }
@@ -405,9 +356,6 @@ fn attr_on_trait() {
             at must_use
             at no_mangle
             at must_use
-            kw self
-            kw super
-            kw crate
         "#]],
     );
 }
@@ -430,9 +378,6 @@ fn attr_on_impl() {
             at must_use
             at no_mangle
             at automatically_derived
-            kw self
-            kw super
-            kw crate
         "#]],
     );
     check(
@@ -450,9 +395,6 @@ fn attr_on_impl() {
             at doc(alias = "…")
             at must_use
             at no_mangle
-            kw self
-            kw super
-            kw crate
         "#]],
     );
 }
@@ -475,9 +417,6 @@ fn attr_on_extern_block() {
             at must_use
             at no_mangle
             at link
-            kw self
-            kw super
-            kw crate
         "#]],
     );
     check(
@@ -496,9 +435,6 @@ fn attr_on_extern_block() {
             at must_use
             at no_mangle
             at link
-            kw self
-            kw super
-            kw crate
         "#]],
     );
 }
@@ -515,9 +451,6 @@ fn attr_on_variant() {
             at forbid(…)
             at warn(…)
             at non_exhaustive
-            kw self
-            kw super
-            kw crate
         "#]],
     );
 }
@@ -554,9 +487,6 @@ fn attr_on_fn() {
             at target_feature = "…"
             at test
             at track_caller
-            kw self
-            kw super
-            kw crate
         "#]],
     );
 }
@@ -573,9 +503,6 @@ fn attr_on_expr() {
             at deny(…)
             at forbid(…)
             at warn(…)
-            kw self
-            kw super
-            kw crate
         "#]],
     );
 }
@@ -621,9 +548,6 @@ fn attr_in_source_file_end() {
             at track_caller
             at used
             at warn(…)
-            kw self
-            kw super
-            kw crate
         "#]],
     );
 }
diff --git a/crates/ide_completion/src/tests/flyimport.rs b/crates/ide_completion/src/tests/flyimport.rs
index fbef6d9937..18880a67aa 100644
--- a/crates/ide_completion/src/tests/flyimport.rs
+++ b/crates/ide_completion/src/tests/flyimport.rs
@@ -96,29 +96,25 @@ fn main() {
 
 #[test]
 fn short_paths_are_ignored() {
-    cov_mark::check!(flyimport_exact_on_short_path);
+    cov_mark::check!(ignore_short_input_for_path);
 
     check(
         r#"
 //- /lib.rs crate:dep
-pub struct Bar;
-pub struct Rcar;
-pub struct Rc;
+pub struct FirstStruct;
 pub mod some_module {
-    pub struct Bar;
-    pub struct Rcar;
-    pub struct Rc;
+    pub struct SecondStruct;
+    pub struct ThirdStruct;
 }
 
 //- /main.rs crate:main deps:dep
+use dep::{FirstStruct, some_module::SecondStruct};
+
 fn main() {
-    rc$0
+    t$0
 }
 "#,
-        expect![[r#"
-            st Rc (use dep::Rc)
-            st Rc (use dep::some_module::Rc)
-        "#]],
+        expect![[r#""#]],
     );
 }
 
@@ -776,7 +772,7 @@ mod foo {
 }
 
 fn main() {
-    TES$0
+    TE$0
 }"#,
         expect![[r#"
         ct TEST_CONST (use foo::TEST_CONST)
@@ -793,7 +789,7 @@ mod foo {
 }
 
 fn main() {
-    tes$0
+    te$0
 }"#,
         expect![[r#"
         ct TEST_CONST (use foo::TEST_CONST)
@@ -850,7 +846,7 @@ struct Foo {
     some_field: i32,
 }
 fn main() {
-    let _ = Foo { some_field: som$0 };
+    let _ = Foo { some_field: so$0 };
 }
 "#,
         expect![[r#"
@@ -928,44 +924,6 @@ mod bar {
             "#,
         expect![[r#""#]],
     );
-    check(
-        r#"
-mod baz {
-    pub trait DefDatabase {
-        fn method1(&self);
-    }
-    pub trait HirDatabase: DefDatabase {
-        fn method2(&self);
-    }
-}
-
-mod bar {
-    fn test(db: &impl crate::baz::HirDatabase) {
-        db.metho$0
-    }
-}
-"#,
-        expect![[r#""#]],
-    );
-    check(
-        r#"
-mod baz {
-    pub trait DefDatabase {
-        fn method1(&self);
-    }
-    pub trait HirDatabase: DefDatabase {
-        fn method2(&self);
-    }
-}
-
-mod bar {
-    fn test<T: crate::baz::HirDatabase>(db: T) {
-        db.metho$0
-    }
-}
-"#,
-        expect![[r#""#]],
-    );
 }
 
 #[test]
@@ -1042,19 +1000,6 @@ fn function() {
     );
 }
 
-#[test]
-fn flyimport_item_name() {
-    check(
-        r#"
-mod module {
-    pub struct Struct;
-}
-struct Str$0
-    "#,
-        expect![[r#""#]],
-    );
-}
-
 #[test]
 fn flyimport_rename() {
     check(
@@ -1098,31 +1043,3 @@ enum Foo {
         "#]],
     )
 }
-
-#[test]
-fn flyimport_attribute() {
-    check(
-        r#"
-//- proc_macros:identity
-#[ide$0]
-struct Foo;
-"#,
-        expect![[r#"
-            at identity (use proc_macros::identity) pub macro identity
-        "#]],
-    );
-    check_edit(
-        "identity",
-        r#"
-//- proc_macros:identity
-#[ide$0]
-struct Foo;
-"#,
-        r#"
-use proc_macros::identity;
-
-#[identity]
-struct Foo;
-"#,
-    );
-}
diff --git a/crates/ide_completion/src/tests/pattern.rs b/crates/ide_completion/src/tests/pattern.rs
index 99e20b6ed0..81c45c64cc 100644
--- a/crates/ide_completion/src/tests/pattern.rs
+++ b/crates/ide_completion/src/tests/pattern.rs
@@ -130,24 +130,18 @@ fn foo() {
 fn irrefutable() {
     check(
         r#"
-enum SingleVariantEnum {
-    Variant
-}
-use SingleVariantEnum::Variant;
 fn foo() {
    let a$0
 }
 "#,
         expect![[r##"
             kw mut
-            bn Record            Record { field$1 }$0
+            bn Record    Record { field$1 }$0
             st Record
-            bn Tuple             Tuple($1)$0
+            bn Tuple     Tuple($1)$0
             st Tuple
-            ev Variant
-            en SingleVariantEnum
             st Unit
-            ma makro!(…)         #[macro_export] macro_rules! makro
+            ma makro!(…) #[macro_export] macro_rules! makro
         "##]],
     );
 }