about summary refs log tree commit diff
path: root/src/tools/rust-analyzer/crates/hir-def
diff options
context:
space:
mode:
authorLaurențiu Nicola <lnicola@dend.ro>2023-07-17 16:49:15 +0300
committerLaurențiu Nicola <lnicola@dend.ro>2023-07-17 16:49:15 +0300
commitd35f6c6c11a01ee0ffb7cf762c6d20e910a7bf0e (patch)
tree70252db1d53254b399a23613cf790fafc06d21fd /src/tools/rust-analyzer/crates/hir-def
parent6f65ef57177ce0095171f70d0b010567c35e68cc (diff)
parent37f84c101bca43b11027f30ab0c2852f9325bc3d (diff)
downloadrust-d35f6c6c11a01ee0ffb7cf762c6d20e910a7bf0e.tar.gz
rust-d35f6c6c11a01ee0ffb7cf762c6d20e910a7bf0e.zip
Merge commit '37f84c101bca43b11027f30ab0c2852f9325bc3d' into sync-from-ra
Diffstat (limited to 'src/tools/rust-analyzer/crates/hir-def')
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/Cargo.toml8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/attr.rs40
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs32
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs77
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data.rs34
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs131
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/db.rs26
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expander.rs57
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/find_path.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/generics.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/import_map.rs645
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lib.rs127
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lower.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs76
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs22
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs36
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs53
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres.rs21
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs73
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs11
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs124
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/path.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/pretty.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/resolver.rs62
34 files changed, 968 insertions, 786 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
index 83c7051646e..30307deb79b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
@@ -21,14 +21,14 @@ dashmap = { version = "=5.4.0", features = ["raw-api"] }
 drop_bomb = "0.1.5"
 either = "1.7.0"
 fst = { version = "0.4.7", default-features = false }
-hashbrown = { version = "0.12.1", default-features = false }
-indexmap = "1.9.1"
+indexmap = "2.0.0"
 itertools = "0.10.5"
-la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
+la-arena.workspace = true
 once_cell = "1.17.0"
 rustc-hash = "1.1.0"
-smallvec.workspace = true
 tracing = "0.1.35"
+smallvec.workspace = true
+hashbrown.workspace = true
 triomphe.workspace = true
 
 rustc_abi = { version = "0.0.20221221", package = "hkalbasi-rustc-ap-rustc_abi", default-features = false }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
index bab3bbc2329..c29446d8235 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
@@ -137,13 +137,16 @@ impl Attrs {
 
                 let cfg_options = &crate_graph[krate].cfg_options;
 
-                let Some(variant) = enum_.variants.clone().filter(|variant| {
-                    let attrs = item_tree.attrs(db, krate, (*variant).into());
-                    attrs.is_cfg_enabled(cfg_options)
-                })
-                .zip(0u32..)
-                .find(|(_variant, idx)| it.local_id == Idx::from_raw(RawIdx::from(*idx)))
-                .map(|(variant, _idx)| variant)
+                let Some(variant) = enum_
+                    .variants
+                    .clone()
+                    .filter(|variant| {
+                        let attrs = item_tree.attrs(db, krate, (*variant).into());
+                        attrs.is_cfg_enabled(cfg_options)
+                    })
+                    .zip(0u32..)
+                    .find(|(_variant, idx)| it.local_id == Idx::from_raw(RawIdx::from(*idx)))
+                    .map(|(variant, _idx)| variant)
                 else {
                     return Arc::new(res);
                 };
@@ -272,6 +275,25 @@ impl Attrs {
         self.by_key("proc_macro_derive").exists()
     }
 
+    pub fn is_test(&self) -> bool {
+        self.iter().any(|it| {
+            it.path()
+                .segments()
+                .iter()
+                .rev()
+                .zip(["core", "prelude", "v1", "test"].iter().rev())
+                .all(|it| it.0.as_str() == Some(it.1))
+        })
+    }
+
+    pub fn is_ignore(&self) -> bool {
+        self.by_key("ignore").exists()
+    }
+
+    pub fn is_bench(&self) -> bool {
+        self.by_key("bench").exists()
+    }
+
     pub fn is_unstable(&self) -> bool {
         self.by_key("unstable").exists()
     }
@@ -282,7 +304,7 @@ use std::slice::Iter as SliceIter;
 pub enum DocAtom {
     /// eg. `#[doc(hidden)]`
     Flag(SmolStr),
-    /// eg. `#[doc(alias = "x")]`
+    /// eg. `#[doc(alias = "it")]`
     ///
     /// Note that a key can have multiple values that are all considered "active" at the same time.
     /// For example, `#[doc(alias = "x")]` and `#[doc(alias = "y")]`.
@@ -462,6 +484,7 @@ impl AttrsWithOwner {
                 }
             },
             AttrDefId::ExternBlockId(it) => attrs_from_item_tree_loc(db, it),
+            AttrDefId::ExternCrateId(it) => attrs_from_item_tree_loc(db, it),
         };
 
         let attrs = raw_attrs.filter(db.upcast(), def.krate(db));
@@ -546,6 +569,7 @@ impl AttrsWithOwner {
                     .map(|source| ast::AnyHasAttrs::new(source[id.local_id].clone())),
             },
             AttrDefId::ExternBlockId(id) => any_has_attrs(db, id),
+            AttrDefId::ExternCrateId(id) => any_has_attrs(db, id),
         };
 
         AttrSourceMap::new(owner.as_ref().map(|node| node as &dyn HasAttrs))
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
index 94dc39b1175..f8d492d0e52 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
@@ -273,10 +273,10 @@ impl Body {
 
     pub fn is_binding_upvar(&self, binding: BindingId, relative_to: ExprId) -> bool {
         match self.binding_owners.get(&binding) {
-            Some(x) => {
+            Some(it) => {
                 // We assign expression ids in a way that outer closures will receive
                 // a lower id
-                x.into_raw() < relative_to.into_raw()
+                it.into_raw() < relative_to.into_raw()
             }
             None => true,
         }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
index b375ec63a67..152c02743f7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
@@ -297,11 +297,11 @@ impl ExprCollector<'_> {
                         let (result_expr_id, prev_binding_owner) =
                             this.initialize_binding_owner(syntax_ptr);
                         let inner_expr = this.collect_block(e);
-                        let x = this.db.intern_anonymous_const(ConstBlockLoc {
+                        let it = this.db.intern_anonymous_const(ConstBlockLoc {
                             parent: this.owner,
                             root: inner_expr,
                         });
-                        this.body.exprs[result_expr_id] = Expr::Const(x);
+                        this.body.exprs[result_expr_id] = Expr::Const(it);
                         this.current_binding_owner = prev_binding_owner;
                         result_expr_id
                     })
@@ -324,10 +324,10 @@ impl ExprCollector<'_> {
             ast::Expr::CallExpr(e) => {
                 let is_rustc_box = {
                     let attrs = e.attrs();
-                    attrs.filter_map(|x| x.as_simple_atom()).any(|x| x == "rustc_box")
+                    attrs.filter_map(|it| it.as_simple_atom()).any(|it| it == "rustc_box")
                 };
                 if is_rustc_box {
-                    let expr = self.collect_expr_opt(e.arg_list().and_then(|x| x.args().next()));
+                    let expr = self.collect_expr_opt(e.arg_list().and_then(|it| it.args().next()));
                     self.alloc_expr(Expr::Box { expr }, syntax_ptr)
                 } else {
                     let callee = self.collect_expr_opt(e.expr());
@@ -781,7 +781,7 @@ impl ExprCollector<'_> {
             pat: self.alloc_pat_desugared(some_pat),
             guard: None,
             expr: self.with_opt_labeled_rib(label, |this| {
-                this.collect_expr_opt(e.loop_body().map(|x| x.into()))
+                this.collect_expr_opt(e.loop_body().map(|it| it.into()))
             }),
         };
         let iter_name = Name::generate_new_name();
@@ -874,10 +874,10 @@ impl ExprCollector<'_> {
             }),
             guard: None,
             expr: {
-                let x = self.alloc_expr(Expr::Path(Path::from(break_name)), syntax_ptr.clone());
+                let it = self.alloc_expr(Expr::Path(Path::from(break_name)), syntax_ptr.clone());
                 let callee = self.alloc_expr(Expr::Path(try_from_residual), syntax_ptr.clone());
                 let result = self.alloc_expr(
-                    Expr::Call { callee, args: Box::new([x]), is_assignee_expr: false },
+                    Expr::Call { callee, args: Box::new([it]), is_assignee_expr: false },
                     syntax_ptr.clone(),
                 );
                 self.alloc_expr(
@@ -1240,12 +1240,12 @@ impl ExprCollector<'_> {
                 pats.push(self.collect_pat(first, binding_list));
                 binding_list.reject_new = true;
                 for rest in it {
-                    for (_, x) in binding_list.is_used.iter_mut() {
-                        *x = false;
+                    for (_, it) in binding_list.is_used.iter_mut() {
+                        *it = false;
                     }
                     pats.push(self.collect_pat(rest, binding_list));
-                    for (&id, &x) in binding_list.is_used.iter() {
-                        if !x {
+                    for (&id, &is_used) in binding_list.is_used.iter() {
+                        if !is_used {
                             self.body.bindings[id].problems =
                                 Some(BindingProblems::NotBoundAcrossAll);
                         }
@@ -1352,9 +1352,9 @@ impl ExprCollector<'_> {
             // FIXME: implement in a way that also builds source map and calculates assoc resolutions in type inference.
             ast::Pat::RangePat(p) => {
                 let mut range_part_lower = |p: Option<ast::Pat>| {
-                    p.and_then(|x| match &x {
-                        ast::Pat::LiteralPat(x) => {
-                            Some(Box::new(LiteralOrConst::Literal(pat_literal_to_hir(x)?.0)))
+                    p.and_then(|it| match &it {
+                        ast::Pat::LiteralPat(it) => {
+                            Some(Box::new(LiteralOrConst::Literal(pat_literal_to_hir(it)?.0)))
                         }
                         ast::Pat::IdentPat(p) => {
                             let name =
@@ -1451,9 +1451,7 @@ impl ExprCollector<'_> {
         &self,
         lifetime: Option<ast::Lifetime>,
     ) -> Result<Option<LabelId>, BodyDiagnostic> {
-        let Some(lifetime) = lifetime else {
-            return Ok(None)
-        };
+        let Some(lifetime) = lifetime else { return Ok(None) };
         let name = Name::new_lifetime(&lifetime);
 
         for (rib_idx, rib) in self.label_ribs.iter().enumerate().rev() {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
index cd6df0e6325..0c6cf0b49a2 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
@@ -105,7 +105,7 @@ struct Printer<'a> {
     needs_indent: bool,
 }
 
-impl<'a> Write for Printer<'a> {
+impl Write for Printer<'_> {
     fn write_str(&mut self, s: &str) -> fmt::Result {
         for line in s.split_inclusive('\n') {
             if self.needs_indent {
@@ -125,7 +125,7 @@ impl<'a> Write for Printer<'a> {
     }
 }
 
-impl<'a> Printer<'a> {
+impl Printer<'_> {
     fn indented(&mut self, f: impl FnOnce(&mut Self)) {
         self.indent_level += 1;
         wln!(self);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
index edee2c7ff96..d5582011645 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
@@ -3,12 +3,12 @@ mod block;
 use base_db::{fixture::WithFixture, SourceDatabase};
 use expect_test::Expect;
 
-use crate::ModuleDefId;
+use crate::{test_db::TestDB, ModuleDefId};
 
 use super::*;
 
 fn lower(ra_fixture: &str) -> Arc<Body> {
-    let db = crate::test_db::TestDB::with_files(ra_fixture);
+    let db = TestDB::with_files(ra_fixture);
 
     let krate = db.crate_graph().iter().next().unwrap();
     let def_map = db.crate_def_map(krate);
@@ -25,15 +25,15 @@ fn lower(ra_fixture: &str) -> Arc<Body> {
     db.body(fn_def.unwrap().into())
 }
 
-fn block_def_map_at(ra_fixture: &str) -> String {
-    let (db, position) = crate::test_db::TestDB::with_position(ra_fixture);
+fn def_map_at(ra_fixture: &str) -> String {
+    let (db, position) = TestDB::with_position(ra_fixture);
 
     let module = db.module_at_position(position);
     module.def_map(&db).dump(&db)
 }
 
 fn check_block_scopes_at(ra_fixture: &str, expect: Expect) {
-    let (db, position) = crate::test_db::TestDB::with_position(ra_fixture);
+    let (db, position) = TestDB::with_position(ra_fixture);
 
     let module = db.module_at_position(position);
     let actual = module.def_map(&db).dump_block_scopes(&db);
@@ -41,7 +41,7 @@ fn check_block_scopes_at(ra_fixture: &str, expect: Expect) {
 }
 
 fn check_at(ra_fixture: &str, expect: Expect) {
-    let actual = block_def_map_at(ra_fixture);
+    let actual = def_map_at(ra_fixture);
     expect.assert_eq(&actual);
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs
index 6e77744f215..4e015a7fbbb 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs
@@ -134,6 +134,47 @@ struct Struct {}
 }
 
 #[test]
+fn super_imports_2() {
+    check_at(
+        r#"
+fn outer() {
+    mod m {
+        struct ResolveMe {}
+        fn middle() {
+            mod m2 {
+                fn inner() {
+                    use super::ResolveMe;
+                    $0
+                }
+            }
+        }
+    }
+}
+"#,
+        expect![[r#"
+            block scope
+            ResolveMe: t
+
+            block scope
+            m2: t
+
+            block scope::m2
+            inner: v
+
+            block scope
+            m: t
+
+            block scope::m
+            ResolveMe: t
+            middle: v
+
+            crate
+            outer: v
+        "#]],
+    );
+}
+
+#[test]
 fn nested_module_scoping() {
     check_block_scopes_at(
         r#"
@@ -156,6 +197,42 @@ fn f() {
 }
 
 #[test]
+fn self_imports() {
+    check_at(
+        r#"
+fn f() {
+    mod m {
+        struct ResolveMe {}
+        fn g() {
+            fn h() {
+                use self::ResolveMe;
+                $0
+            }
+        }
+    }
+}
+"#,
+        expect![[r#"
+            block scope
+            ResolveMe: t
+
+            block scope
+            h: v
+
+            block scope
+            m: t
+
+            block scope::m
+            ResolveMe: t
+            g: v
+
+            crate
+            f: v
+        "#]],
+    );
+}
+
+#[test]
 fn legacy_macro_items() {
     // Checks that legacy-scoped `macro_rules!` from parent namespaces are resolved and expanded
     // correctly.
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
index 40e6a430878..54fe9a2e844 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
@@ -24,11 +24,12 @@ use crate::{
         proc_macro::{parse_macro_name_and_helper_attrs, ProcMacroKind},
         DefMap, MacroSubNs,
     },
+    path::ImportAlias,
     type_ref::{TraitRef, TypeBound, TypeRef},
     visibility::RawVisibility,
-    AssocItemId, AstIdWithPath, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId,
-    Intern, ItemContainerId, ItemLoc, Lookup, Macro2Id, MacroRulesId, ModuleId, ProcMacroId,
-    StaticId, TraitAliasId, TraitId, TypeAliasId, TypeAliasLoc,
+    AssocItemId, AstIdWithPath, ConstId, ConstLoc, ExternCrateId, FunctionId, FunctionLoc,
+    HasModule, ImplId, Intern, ItemContainerId, ItemLoc, Lookup, Macro2Id, MacroRulesId, ModuleId,
+    ProcMacroId, StaticId, TraitAliasId, TraitId, TypeAliasId, TypeAliasLoc,
 };
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -424,6 +425,7 @@ impl MacroRulesData {
         Arc::new(MacroRulesData { name: makro.name.clone(), macro_export })
     }
 }
+
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct ProcMacroData {
     pub name: Name,
@@ -461,6 +463,30 @@ impl ProcMacroData {
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
+pub struct ExternCrateDeclData {
+    pub name: Name,
+    pub alias: Option<ImportAlias>,
+    pub visibility: RawVisibility,
+}
+
+impl ExternCrateDeclData {
+    pub(crate) fn extern_crate_decl_data_query(
+        db: &dyn DefDatabase,
+        extern_crate: ExternCrateId,
+    ) -> Arc<ExternCrateDeclData> {
+        let loc = extern_crate.lookup(db);
+        let item_tree = loc.id.item_tree(db);
+        let extern_crate = &item_tree[loc.id.value];
+
+        Arc::new(Self {
+            name: extern_crate.name.clone(),
+            visibility: item_tree[extern_crate.visibility].clone(),
+            alias: extern_crate.alias.clone(),
+        })
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
 pub struct ConstData {
     /// `None` for `const _: () = ();`
     pub name: Option<Name>,
@@ -573,7 +599,7 @@ impl<'a> AssocItemCollector<'a> {
             if !attrs.is_cfg_enabled(self.expander.cfg_options()) {
                 self.diagnostics.push(DefDiagnostic::unconfigured_code(
                     self.module_id.local_id,
-                    InFile::new(self.expander.current_file_id(), item.ast_id(item_tree).upcast()),
+                    InFile::new(self.expander.current_file_id(), item.ast_id(item_tree).erase()),
                     attrs.cfg().unwrap(),
                     self.expander.cfg_options().clone(),
                 ));
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
index 6db5abccc92..c8df3f3f96a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
@@ -18,7 +18,6 @@ use triomphe::Arc;
 use crate::{
     builtin_type::{BuiltinInt, BuiltinUint},
     db::DefDatabase,
-    expander::CfgExpander,
     item_tree::{AttrOwner, Field, FieldAstId, Fields, ItemTree, ModItem, RawVisibilityId},
     lang_item::LangItem,
     lower::LowerCtx,
@@ -29,8 +28,8 @@ use crate::{
     tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree},
     type_ref::TypeRef,
     visibility::RawVisibility,
-    EnumId, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StructId, UnionId,
-    VariantId,
+    EnumId, EnumLoc, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StructId,
+    UnionId, VariantId,
 };
 
 /// Note that we use `StructData` for unions as well!
@@ -76,6 +75,7 @@ pub struct EnumData {
 pub struct EnumVariantData {
     pub name: Name,
     pub variant_data: Arc<VariantData>,
+    pub tree_id: la_arena::Idx<crate::item_tree::Variant>,
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -147,6 +147,7 @@ fn parse_repr_tt(tt: &Subtree) -> Option<ReprOptions> {
                 }
                 "C" => ReprFlags::IS_C,
                 "transparent" => ReprFlags::IS_TRANSPARENT,
+                "simd" => ReprFlags::IS_SIMD,
                 repr => {
                     if let Some(builtin) = BuiltinInt::from_suffix(repr)
                         .map(Either::Left)
@@ -325,11 +326,12 @@ impl EnumData {
                 variants.alloc(EnumVariantData {
                     name: var.name.clone(),
                     variant_data: Arc::new(var_data),
+                    tree_id,
                 });
             } else {
                 diagnostics.push(DefDiagnostic::unconfigured_code(
                     loc.container.local_id,
-                    InFile::new(loc.id.file_id(), var.ast_id.upcast()),
+                    InFile::new(loc.id.file_id(), var.ast_id.erase()),
                     attrs.cfg().unwrap(),
                     cfg_options.clone(),
                 ))
@@ -367,9 +369,10 @@ impl HasChildSource<LocalEnumVariantId> for EnumId {
         &self,
         db: &dyn DefDatabase,
     ) -> InFile<ArenaMap<LocalEnumVariantId, Self::Value>> {
-        let src = self.lookup(db).source(db);
+        let loc = &self.lookup(db);
+        let src = loc.source(db);
         let mut trace = Trace::new_for_map();
-        lower_enum(db, &mut trace, &src, self.lookup(db).container);
+        lower_enum(db, &mut trace, &src, loc);
         src.with_value(trace.into_map())
     }
 }
@@ -378,31 +381,58 @@ fn lower_enum(
     db: &dyn DefDatabase,
     trace: &mut Trace<EnumVariantData, ast::Variant>,
     ast: &InFile<ast::Enum>,
-    module_id: ModuleId,
+    loc: &EnumLoc,
 ) {
-    let expander = CfgExpander::new(db, ast.file_id, module_id.krate);
+    let item_tree = loc.id.item_tree(db);
+    let krate = loc.container.krate;
+
+    let item_tree_variants = item_tree[loc.id.value].variants.clone();
+
+    let cfg_options = &db.crate_graph()[krate].cfg_options;
     let variants = ast
         .value
         .variant_list()
         .into_iter()
         .flat_map(|it| it.variants())
-        .filter(|var| expander.is_cfg_enabled(db, var));
-    for var in variants {
+        .zip(item_tree_variants)
+        .filter(|&(_, item_tree_id)| {
+            item_tree.attrs(db, krate, item_tree_id.into()).is_cfg_enabled(cfg_options)
+        });
+    for (var, item_tree_id) in variants {
         trace.alloc(
             || var.clone(),
             || EnumVariantData {
                 name: var.name().map_or_else(Name::missing, |it| it.as_name()),
-                variant_data: Arc::new(VariantData::new(db, ast.with_value(var.kind()), module_id)),
+                variant_data: Arc::new(VariantData::new(
+                    db,
+                    ast.with_value(var.kind()),
+                    loc.container,
+                    &item_tree,
+                    item_tree_id,
+                )),
+                tree_id: item_tree_id,
             },
         );
     }
 }
 
 impl VariantData {
-    fn new(db: &dyn DefDatabase, flavor: InFile<ast::StructKind>, module_id: ModuleId) -> Self {
-        let mut expander = CfgExpander::new(db, flavor.file_id, module_id.krate);
+    fn new(
+        db: &dyn DefDatabase,
+        flavor: InFile<ast::StructKind>,
+        module_id: ModuleId,
+        item_tree: &ItemTree,
+        variant: la_arena::Idx<crate::item_tree::Variant>,
+    ) -> Self {
         let mut trace = Trace::new_for_arena();
-        match lower_struct(db, &mut expander, &mut trace, &flavor) {
+        match lower_struct(
+            db,
+            &mut trace,
+            &flavor,
+            module_id.krate,
+            item_tree,
+            &item_tree[variant].fields,
+        ) {
             StructKind::Tuple => VariantData::Tuple(trace.into_arena()),
             StructKind::Record => VariantData::Record(trace.into_arena()),
             StructKind::Unit => VariantData::Unit,
@@ -434,28 +464,43 @@ impl HasChildSource<LocalFieldId> for VariantId {
     type Value = Either<ast::TupleField, ast::RecordField>;
 
     fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<LocalFieldId, Self::Value>> {
-        let (src, module_id) = match self {
+        let item_tree;
+        let (src, fields, container) = match *self {
             VariantId::EnumVariantId(it) => {
                 // I don't really like the fact that we call into parent source
                 // here, this might add to more queries then necessary.
+                let lookup = it.parent.lookup(db);
+                item_tree = lookup.id.item_tree(db);
                 let src = it.parent.child_source(db);
-                (src.map(|map| map[it.local_id].kind()), it.parent.lookup(db).container)
+                let tree_id = db.enum_data(it.parent).variants[it.local_id].tree_id;
+                let fields = &item_tree[tree_id].fields;
+                (src.map(|map| map[it.local_id].kind()), fields, lookup.container)
             }
             VariantId::StructId(it) => {
-                (it.lookup(db).source(db).map(|it| it.kind()), it.lookup(db).container)
+                let lookup = it.lookup(db);
+                item_tree = lookup.id.item_tree(db);
+                (
+                    lookup.source(db).map(|it| it.kind()),
+                    &item_tree[lookup.id.value].fields,
+                    lookup.container,
+                )
+            }
+            VariantId::UnionId(it) => {
+                let lookup = it.lookup(db);
+                item_tree = lookup.id.item_tree(db);
+                (
+                    lookup.source(db).map(|it| {
+                        it.record_field_list()
+                            .map(ast::StructKind::Record)
+                            .unwrap_or(ast::StructKind::Unit)
+                    }),
+                    &item_tree[lookup.id.value].fields,
+                    lookup.container,
+                )
             }
-            VariantId::UnionId(it) => (
-                it.lookup(db).source(db).map(|it| {
-                    it.record_field_list()
-                        .map(ast::StructKind::Record)
-                        .unwrap_or(ast::StructKind::Unit)
-                }),
-                it.lookup(db).container,
-            ),
         };
-        let mut expander = CfgExpander::new(db, src.file_id, module_id.krate);
         let mut trace = Trace::new_for_map();
-        lower_struct(db, &mut expander, &mut trace, &src);
+        lower_struct(db, &mut trace, &src, container.krate, &item_tree, fields);
         src.with_value(trace.into_map())
     }
 }
@@ -469,16 +514,19 @@ pub enum StructKind {
 
 fn lower_struct(
     db: &dyn DefDatabase,
-    expander: &mut CfgExpander,
     trace: &mut Trace<FieldData, Either<ast::TupleField, ast::RecordField>>,
     ast: &InFile<ast::StructKind>,
+    krate: CrateId,
+    item_tree: &ItemTree,
+    fields: &Fields,
 ) -> StructKind {
-    let ctx = LowerCtx::new(db, &expander.hygiene(), ast.file_id);
+    let ctx = LowerCtx::with_file_id(db, ast.file_id);
 
-    match &ast.value {
-        ast::StructKind::Tuple(fl) => {
-            for (i, fd) in fl.fields().enumerate() {
-                if !expander.is_cfg_enabled(db, &fd) {
+    match (&ast.value, fields) {
+        (ast::StructKind::Tuple(fl), Fields::Tuple(fields)) => {
+            let cfg_options = &db.crate_graph()[krate].cfg_options;
+            for ((i, fd), item_tree_id) in fl.fields().enumerate().zip(fields.clone()) {
+                if !item_tree.attrs(db, krate, item_tree_id.into()).is_cfg_enabled(cfg_options) {
                     continue;
                 }
 
@@ -493,9 +541,10 @@ fn lower_struct(
             }
             StructKind::Tuple
         }
-        ast::StructKind::Record(fl) => {
-            for fd in fl.fields() {
-                if !expander.is_cfg_enabled(db, &fd) {
+        (ast::StructKind::Record(fl), Fields::Record(fields)) => {
+            let cfg_options = &db.crate_graph()[krate].cfg_options;
+            for (fd, item_tree_id) in fl.fields().zip(fields.clone()) {
+                if !item_tree.attrs(db, krate, item_tree_id.into()).is_cfg_enabled(cfg_options) {
                     continue;
                 }
 
@@ -510,7 +559,7 @@ fn lower_struct(
             }
             StructKind::Record
         }
-        ast::StructKind::Unit => StructKind::Unit,
+        _ => StructKind::Unit,
     }
 }
 
@@ -539,8 +588,8 @@ fn lower_fields(
                         InFile::new(
                             current_file_id,
                             match field.ast_id {
-                                FieldAstId::Record(it) => it.upcast(),
-                                FieldAstId::Tuple(it) => it.upcast(),
+                                FieldAstId::Record(it) => it.erase(),
+                                FieldAstId::Tuple(it) => it.erase(),
                             },
                         ),
                         attrs.cfg().unwrap(),
@@ -563,8 +612,8 @@ fn lower_fields(
                         InFile::new(
                             current_file_id,
                             match field.ast_id {
-                                FieldAstId::Record(it) => it.upcast(),
-                                FieldAstId::Tuple(it) => it.upcast(),
+                                FieldAstId::Record(it) => it.erase(),
+                                FieldAstId::Tuple(it) => it.erase(),
                             },
                         ),
                         attrs.cfg().unwrap(),
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
index 04ec47f84ca..82e6dfb30c8 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
@@ -12,27 +12,31 @@ use crate::{
     body::{scope::ExprScopes, Body, BodySourceMap},
     data::{
         adt::{EnumData, StructData},
-        ConstData, FunctionData, ImplData, Macro2Data, MacroRulesData, ProcMacroData, StaticData,
-        TraitAliasData, TraitData, TypeAliasData,
+        ConstData, ExternCrateDeclData, FunctionData, ImplData, Macro2Data, MacroRulesData,
+        ProcMacroData, StaticData, TraitAliasData, TraitData, TypeAliasData,
     },
     generics::GenericParams,
     import_map::ImportMap,
     item_tree::{AttrOwner, ItemTree},
-    lang_item::{LangItem, LangItemTarget, LangItems},
+    lang_item::{self, LangItem, LangItemTarget, LangItems},
     nameres::{diagnostics::DefDiagnostic, DefMap},
     visibility::{self, Visibility},
     AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstBlockLoc, ConstId, ConstLoc, DefWithBodyId,
-    EnumId, EnumLoc, ExternBlockId, ExternBlockLoc, FunctionId, FunctionLoc, GenericDefId, ImplId,
-    ImplLoc, InTypeConstId, InTypeConstLoc, LocalEnumVariantId, LocalFieldId, Macro2Id, Macro2Loc,
-    MacroRulesId, MacroRulesLoc, ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId,
-    StructLoc, TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId,
-    UnionLoc, VariantId,
+    EnumId, EnumLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId,
+    FunctionLoc, GenericDefId, ImplId, ImplLoc, ImportId, ImportLoc, InTypeConstId, InTypeConstLoc,
+    LocalEnumVariantId, LocalFieldId, Macro2Id, Macro2Loc, MacroRulesId, MacroRulesLoc,
+    ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitAliasId,
+    TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, VariantId,
 };
 
 #[salsa::query_group(InternDatabaseStorage)]
 pub trait InternDatabase: SourceDatabase {
     // region: items
     #[salsa::interned]
+    fn intern_import(&self, loc: ImportLoc) -> ImportId;
+    #[salsa::interned]
+    fn intern_extern_crate(&self, loc: ExternCrateLoc) -> ExternCrateId;
+    #[salsa::interned]
     fn intern_function(&self, loc: FunctionLoc) -> FunctionId;
     #[salsa::interned]
     fn intern_struct(&self, loc: StructLoc) -> StructId;
@@ -160,6 +164,9 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
     #[salsa::invoke(ProcMacroData::proc_macro_data_query)]
     fn proc_macro_data(&self, makro: ProcMacroId) -> Arc<ProcMacroData>;
 
+    #[salsa::invoke(ExternCrateDeclData::extern_crate_decl_data_query)]
+    fn extern_crate_decl_data(&self, extern_crate: ExternCrateId) -> Arc<ExternCrateDeclData>;
+
     // endregion:data
 
     #[salsa::invoke(Body::body_with_source_map_query)]
@@ -197,6 +204,9 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
     #[salsa::invoke(AttrsWithOwner::attrs_query)]
     fn attrs(&self, def: AttrDefId) -> Attrs;
 
+    #[salsa::invoke(lang_item::lang_attr_query)]
+    fn lang_attr(&self, def: AttrDefId) -> Option<LangItem>;
+
     #[salsa::transparent]
     #[salsa::invoke(AttrsWithOwner::attrs_with_owner)]
     fn attrs_with_owner(&self, def: AttrDefId) -> AttrsWithOwner;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs b/src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs
index f30be6b64e3..4197d010608 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs
@@ -8,8 +8,8 @@ use syntax::{ast, AstNode, AstPtr};
 
 use crate::{
     dyn_map::{DynMap, Policy},
-    ConstId, EnumId, EnumVariantId, FieldId, FunctionId, ImplId, LifetimeParamId, Macro2Id,
-    MacroRulesId, ProcMacroId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId,
+    ConstId, EnumId, EnumVariantId, ExternCrateId, FieldId, FunctionId, ImplId, LifetimeParamId,
+    Macro2Id, MacroRulesId, ProcMacroId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId,
     TypeOrConstParamId, UnionId,
 };
 
@@ -25,6 +25,7 @@ pub const TRAIT_ALIAS: Key<ast::TraitAlias, TraitAliasId> = Key::new();
 pub const STRUCT: Key<ast::Struct, StructId> = Key::new();
 pub const UNION: Key<ast::Union, UnionId> = Key::new();
 pub const ENUM: Key<ast::Enum, EnumId> = Key::new();
+pub const EXTERN_CRATE: Key<ast::ExternCrate, ExternCrateId> = Key::new();
 
 pub const VARIANT: Key<ast::Variant, EnumVariantId> = Key::new();
 pub const TUPLE_FIELD: Key<ast::TupleField, FieldId> = Key::new();
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
index a588827c8d3..cc85bd893ac 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
@@ -15,18 +15,11 @@ use crate::{
     MacroId, ModuleId,
 };
 
-/// A subset of Expander that only deals with cfg attributes. We only need it to
-/// avoid cyclic queries in crate def map during enum processing.
 #[derive(Debug)]
-pub(crate) struct CfgExpander {
+pub struct Expander {
     cfg_options: CfgOptions,
     hygiene: Hygiene,
     krate: CrateId,
-}
-
-#[derive(Debug)]
-pub struct Expander {
-    cfg_expander: CfgExpander,
     pub(crate) current_file_id: HirFileId,
     pub(crate) module: ModuleId,
     /// `recursion_depth == usize::MAX` indicates that the recursion limit has been reached.
@@ -34,41 +27,23 @@ pub struct Expander {
     recursion_limit: Limit,
 }
 
-impl CfgExpander {
-    pub(crate) fn new(
-        db: &dyn DefDatabase,
-        current_file_id: HirFileId,
-        krate: CrateId,
-    ) -> CfgExpander {
-        let hygiene = Hygiene::new(db.upcast(), current_file_id);
-        let cfg_options = db.crate_graph()[krate].cfg_options.clone();
-        CfgExpander { cfg_options, hygiene, krate }
-    }
-
-    pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs {
-        Attrs::filter(db, self.krate, RawAttrs::new(db.upcast(), owner, &self.hygiene))
-    }
-
-    pub(crate) fn is_cfg_enabled(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> bool {
-        let attrs = self.parse_attrs(db, owner);
-        attrs.is_cfg_enabled(&self.cfg_options)
-    }
-
-    pub(crate) fn hygiene(&self) -> &Hygiene {
-        &self.hygiene
-    }
-}
-
 impl Expander {
     pub fn new(db: &dyn DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander {
-        let cfg_expander = CfgExpander::new(db, current_file_id, module.krate);
         let recursion_limit = db.recursion_limit(module.krate);
         #[cfg(not(test))]
         let recursion_limit = Limit::new(recursion_limit as usize);
         // Without this, `body::tests::your_stack_belongs_to_me` stack-overflows in debug
         #[cfg(test)]
         let recursion_limit = Limit::new(std::cmp::min(32, recursion_limit as usize));
-        Expander { cfg_expander, current_file_id, module, recursion_depth: 0, recursion_limit }
+        Expander {
+            current_file_id,
+            module,
+            recursion_depth: 0,
+            recursion_limit,
+            cfg_options: db.crate_graph()[module.krate].cfg_options.clone(),
+            hygiene: Hygiene::new(db.upcast(), current_file_id),
+            krate: module.krate,
+        }
     }
 
     pub fn enter_expand<T: ast::AstNode>(
@@ -120,7 +95,7 @@ impl Expander {
     }
 
     pub fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) {
-        self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id);
+        self.hygiene = Hygiene::new(db.upcast(), mark.file_id);
         self.current_file_id = mark.file_id;
         if self.recursion_depth == u32::MAX {
             // Recursion limit has been reached somewhere in the macro expansion tree. Reset the
@@ -135,7 +110,7 @@ impl Expander {
     }
 
     pub fn ctx<'a>(&self, db: &'a dyn DefDatabase) -> LowerCtx<'a> {
-        LowerCtx::new(db, &self.cfg_expander.hygiene, self.current_file_id)
+        LowerCtx::new(db, &self.hygiene, self.current_file_id)
     }
 
     pub(crate) fn to_source<T>(&self, value: T) -> InFile<T> {
@@ -143,11 +118,11 @@ impl Expander {
     }
 
     pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs {
-        self.cfg_expander.parse_attrs(db, owner)
+        Attrs::filter(db, self.krate, RawAttrs::new(db.upcast(), owner, &self.hygiene))
     }
 
     pub(crate) fn cfg_options(&self) -> &CfgOptions {
-        &self.cfg_expander.cfg_options
+        &self.cfg_options
     }
 
     pub fn current_file_id(&self) -> HirFileId {
@@ -155,7 +130,7 @@ impl Expander {
     }
 
     pub(crate) fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option<Path> {
-        let ctx = LowerCtx::new(db, &self.cfg_expander.hygiene, self.current_file_id);
+        let ctx = LowerCtx::new(db, &self.hygiene, self.current_file_id);
         Path::from_src(path, &ctx)
     }
 
@@ -194,7 +169,7 @@ impl Expander {
                 let parse = value.cast::<T>()?;
 
                 self.recursion_depth += 1;
-                self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id);
+                self.hygiene = Hygiene::new(db.upcast(), file_id);
                 let old_file_id = std::mem::replace(&mut self.current_file_id, file_id);
                 let mark =
                     Mark { file_id: old_file_id, bomb: DropBomb::new("expansion mark dropped") };
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
index 8c49ae1c4af..df2af4c89b0 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
@@ -360,7 +360,7 @@ fn calculate_best_path(
                     prefer_no_std,
                 )?;
                 cov_mark::hit!(partially_imported);
-                path.push_segment(info.path.segments.last()?.clone());
+                path.push_segment(info.name.clone());
                 Some(path)
             })
         });
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
index f19c3f028f4..d7d44e41388 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
@@ -67,21 +67,21 @@ pub enum TypeOrConstParamData {
 impl TypeOrConstParamData {
     pub fn name(&self) -> Option<&Name> {
         match self {
-            TypeOrConstParamData::TypeParamData(x) => x.name.as_ref(),
-            TypeOrConstParamData::ConstParamData(x) => Some(&x.name),
+            TypeOrConstParamData::TypeParamData(it) => it.name.as_ref(),
+            TypeOrConstParamData::ConstParamData(it) => Some(&it.name),
         }
     }
 
     pub fn has_default(&self) -> bool {
         match self {
-            TypeOrConstParamData::TypeParamData(x) => x.default.is_some(),
-            TypeOrConstParamData::ConstParamData(x) => x.has_default,
+            TypeOrConstParamData::TypeParamData(it) => it.default.is_some(),
+            TypeOrConstParamData::ConstParamData(it) => it.has_default,
         }
     }
 
     pub fn type_param(&self) -> Option<&TypeParamData> {
         match self {
-            TypeOrConstParamData::TypeParamData(x) => Some(x),
+            TypeOrConstParamData::TypeParamData(it) => Some(it),
             TypeOrConstParamData::ConstParamData(_) => None,
         }
     }
@@ -89,14 +89,14 @@ impl TypeOrConstParamData {
     pub fn const_param(&self) -> Option<&ConstParamData> {
         match self {
             TypeOrConstParamData::TypeParamData(_) => None,
-            TypeOrConstParamData::ConstParamData(x) => Some(x),
+            TypeOrConstParamData::ConstParamData(it) => Some(it),
         }
     }
 
     pub fn is_trait_self(&self) -> bool {
         match self {
-            TypeOrConstParamData::TypeParamData(x) => {
-                x.provenance == TypeParamProvenance::TraitSelf
+            TypeOrConstParamData::TypeParamData(it) => {
+                it.provenance == TypeParamProvenance::TraitSelf
             }
             TypeOrConstParamData::ConstParamData(_) => false,
         }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
index fa1f4933a26..57f023ef35d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
@@ -425,8 +425,8 @@ impl ConstRef {
         }
         match expr {
             ast::Expr::PathExpr(p) if is_path_ident(&p) => {
-                match p.path().and_then(|x| x.segment()).and_then(|x| x.name_ref()) {
-                    Some(x) => Self::Path(x.as_name()),
+                match p.path().and_then(|it| it.segment()).and_then(|it| it.name_ref()) {
+                    Some(it) => Self::Path(it.as_name()),
                     None => Self::Scalar(LiteralConstRef::Unknown),
                 }
             }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
index 48532655e04..4b2e5041a12 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
@@ -1,13 +1,14 @@
 //! A map of all publicly exported items in a crate.
 
+use std::collections::hash_map::Entry;
 use std::{fmt, hash::BuildHasherDefault};
 
 use base_db::CrateId;
 use fst::{self, Streamer};
 use hir_expand::name::Name;
-use indexmap::{map::Entry, IndexMap};
+use indexmap::IndexMap;
 use itertools::Itertools;
-use rustc_hash::{FxHashSet, FxHasher};
+use rustc_hash::{FxHashMap, FxHashSet, FxHasher};
 use triomphe::Arc;
 
 use crate::{
@@ -17,52 +18,23 @@ use crate::{
 
 type FxIndexMap<K, V> = IndexMap<K, V, BuildHasherDefault<FxHasher>>;
 
+// FIXME: Support aliases: an item may be exported under multiple names, so `ImportInfo` should
+// have `Vec<(Name, ModuleId)>` instead of `(Name, ModuleId)`.
 /// Item import details stored in the `ImportMap`.
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct ImportInfo {
-    /// A path that can be used to import the item, relative to the crate's root.
-    pub path: ImportPath,
+    /// A name that can be used to import the item, relative to the crate's root.
+    pub name: Name,
     /// The module containing this item.
     pub container: ModuleId,
     /// Whether the import is a trait associated item or not.
     pub is_trait_assoc_item: bool,
 }
 
-#[derive(Debug, Clone, Eq, PartialEq)]
-pub struct ImportPath {
-    pub segments: Vec<Name>,
-}
-
-impl ImportPath {
-    pub fn display<'a>(&'a self, db: &'a dyn DefDatabase) -> impl fmt::Display + 'a {
-        struct Display<'a> {
-            db: &'a dyn DefDatabase,
-            path: &'a ImportPath,
-        }
-        impl fmt::Display for Display<'_> {
-            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                fmt::Display::fmt(
-                    &self.path.segments.iter().map(|it| it.display(self.db.upcast())).format("::"),
-                    f,
-                )
-            }
-        }
-        Display { db, path: self }
-    }
-
-    fn len(&self) -> usize {
-        self.segments.len()
-    }
-}
-
-/// A map from publicly exported items to the path needed to import/name them from a downstream
-/// crate.
+/// A map from publicly exported items to its name.
 ///
 /// Reexports of items are taken into account, ie. if something is exported under multiple
 /// names, the one with the shortest import path will be used.
-///
-/// Note that all paths are relative to the containing crate's root, so the crate name still needs
-/// to be prepended to the `ModPath` before the path is valid.
 #[derive(Default)]
 pub struct ImportMap {
     map: FxIndexMap<ItemInNs, ImportInfo>,
@@ -70,122 +42,58 @@ pub struct ImportMap {
     /// List of keys stored in `map`, sorted lexicographically by their `ModPath`. Indexed by the
     /// values returned by running `fst`.
     ///
-    /// Since a path can refer to multiple items due to namespacing, we store all items with the
-    /// same path right after each other. This allows us to find all items after the FST gives us
+    /// Since a name can refer to multiple items due to namespacing, we store all items with the
+    /// same name right after each other. This allows us to find all items after the FST gives us
     /// the index of the first one.
     importables: Vec<ItemInNs>,
     fst: fst::Map<Vec<u8>>,
 }
 
 impl ImportMap {
-    pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> {
+    pub(crate) fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> {
         let _p = profile::span("import_map_query");
 
-        let mut import_map = collect_import_map(db, krate);
+        let map = collect_import_map(db, krate);
 
-        let mut importables = import_map
-            .map
+        let mut importables: Vec<_> = map
             .iter()
-            .map(|(item, info)| (item, fst_path(db, &info.path)))
-            .collect::<Vec<_>>();
-        importables.sort_by(|(_, fst_path), (_, fst_path2)| fst_path.cmp(fst_path2));
+            // We've only collected items, whose name cannot be tuple field.
+            .map(|(&item, info)| (item, info.name.as_str().unwrap().to_ascii_lowercase()))
+            .collect();
+        importables.sort_by(|(_, lhs_name), (_, rhs_name)| lhs_name.cmp(rhs_name));
 
         // Build the FST, taking care not to insert duplicate values.
-
         let mut builder = fst::MapBuilder::memory();
-        let mut last_batch_start = 0;
-
-        for idx in 0..importables.len() {
-            let key = &importables[last_batch_start].1;
-            if let Some((_, fst_path)) = importables.get(idx + 1) {
-                if key == fst_path {
-                    continue;
-                }
-            }
-
-            let _ = builder.insert(key, last_batch_start as u64);
-
-            last_batch_start = idx + 1;
+        let iter = importables.iter().enumerate().dedup_by(|lhs, rhs| lhs.1 .1 == rhs.1 .1);
+        for (start_idx, (_, name)) in iter {
+            let _ = builder.insert(name, start_idx as u64);
         }
 
-        import_map.fst = builder.into_map();
-        import_map.importables = importables.iter().map(|&(&item, _)| item).collect();
-
-        Arc::new(import_map)
-    }
-
-    /// Returns the `ModPath` needed to import/mention `item`, relative to this crate's root.
-    pub fn path_of(&self, item: ItemInNs) -> Option<&ImportPath> {
-        self.import_info_for(item).map(|it| &it.path)
+        Arc::new(ImportMap {
+            map,
+            fst: builder.into_map(),
+            importables: importables.into_iter().map(|(item, _)| item).collect(),
+        })
     }
 
     pub fn import_info_for(&self, item: ItemInNs) -> Option<&ImportInfo> {
         self.map.get(&item)
     }
-
-    #[cfg(test)]
-    fn fmt_for_test(&self, db: &dyn DefDatabase) -> String {
-        let mut importable_paths: Vec<_> = self
-            .map
-            .iter()
-            .map(|(item, info)| {
-                let ns = match item {
-                    ItemInNs::Types(_) => "t",
-                    ItemInNs::Values(_) => "v",
-                    ItemInNs::Macros(_) => "m",
-                };
-                format!("- {} ({ns})", info.path.display(db))
-            })
-            .collect();
-
-        importable_paths.sort();
-        importable_paths.join("\n")
-    }
-
-    fn collect_trait_assoc_items(
-        &mut self,
-        db: &dyn DefDatabase,
-        tr: TraitId,
-        is_type_in_ns: bool,
-        original_import_info: &ImportInfo,
-    ) {
-        let _p = profile::span("collect_trait_assoc_items");
-        for (assoc_item_name, item) in &db.trait_data(tr).items {
-            let module_def_id = match item {
-                AssocItemId::FunctionId(f) => ModuleDefId::from(*f),
-                AssocItemId::ConstId(c) => ModuleDefId::from(*c),
-                // cannot use associated type aliases directly: need a `<Struct as Trait>::TypeAlias`
-                // qualifier, ergo no need to store it for imports in import_map
-                AssocItemId::TypeAliasId(_) => {
-                    cov_mark::hit!(type_aliases_ignored);
-                    continue;
-                }
-            };
-            let assoc_item = if is_type_in_ns {
-                ItemInNs::Types(module_def_id)
-            } else {
-                ItemInNs::Values(module_def_id)
-            };
-
-            let mut assoc_item_info = original_import_info.clone();
-            assoc_item_info.path.segments.push(assoc_item_name.to_owned());
-            assoc_item_info.is_trait_assoc_item = true;
-            self.map.insert(assoc_item, assoc_item_info);
-        }
-    }
 }
 
-fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> ImportMap {
+fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> FxIndexMap<ItemInNs, ImportInfo> {
     let _p = profile::span("collect_import_map");
 
     let def_map = db.crate_def_map(krate);
-    let mut import_map = ImportMap::default();
+    let mut map = FxIndexMap::default();
 
     // We look only into modules that are public(ly reexported), starting with the crate root.
-    let empty = ImportPath { segments: vec![] };
     let root = def_map.module_id(DefMap::ROOT);
-    let mut worklist = vec![(root, empty)];
-    while let Some((module, mod_path)) = worklist.pop() {
+    let mut worklist = vec![(root, 0)];
+    // Records items' minimum module depth.
+    let mut depth_map = FxHashMap::default();
+
+    while let Some((module, depth)) = worklist.pop() {
         let ext_def_map;
         let mod_data = if module.krate == krate {
             &def_map[module.local_id]
@@ -201,52 +109,83 @@ fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> ImportMap {
         });
 
         for (name, per_ns) in visible_items {
-            let mk_path = || {
-                let mut path = mod_path.clone();
-                path.segments.push(name.clone());
-                path
-            };
-
             for item in per_ns.iter_items() {
-                let path = mk_path();
-                let path_len = path.len();
-                let import_info =
-                    ImportInfo { path, container: module, is_trait_assoc_item: false };
-
-                if let Some(ModuleDefId::TraitId(tr)) = item.as_module_def_id() {
-                    import_map.collect_trait_assoc_items(
-                        db,
-                        tr,
-                        matches!(item, ItemInNs::Types(_)),
-                        &import_info,
-                    );
-                }
+                let import_info = ImportInfo {
+                    name: name.clone(),
+                    container: module,
+                    is_trait_assoc_item: false,
+                };
 
-                match import_map.map.entry(item) {
+                match depth_map.entry(item) {
                     Entry::Vacant(entry) => {
-                        entry.insert(import_info);
+                        entry.insert(depth);
                     }
                     Entry::Occupied(mut entry) => {
-                        // If the new path is shorter, prefer that one.
-                        if path_len < entry.get().path.len() {
-                            *entry.get_mut() = import_info;
+                        if depth < *entry.get() {
+                            entry.insert(depth);
                         } else {
                             continue;
                         }
                     }
                 }
 
-                // If we've just added a path to a module, descend into it. We might traverse
-                // modules multiple times, but only if the new path to it is shorter than the
-                // first (else we `continue` above).
+                if let Some(ModuleDefId::TraitId(tr)) = item.as_module_def_id() {
+                    collect_trait_assoc_items(
+                        db,
+                        &mut map,
+                        tr,
+                        matches!(item, ItemInNs::Types(_)),
+                        &import_info,
+                    );
+                }
+
+                map.insert(item, import_info);
+
+                // If we've just added a module, descend into it. We might traverse modules
+                // multiple times, but only if the module depth is smaller (else we `continue`
+                // above).
                 if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() {
-                    worklist.push((mod_id, mk_path()));
+                    worklist.push((mod_id, depth + 1));
                 }
             }
         }
     }
 
-    import_map
+    map
+}
+
+fn collect_trait_assoc_items(
+    db: &dyn DefDatabase,
+    map: &mut FxIndexMap<ItemInNs, ImportInfo>,
+    tr: TraitId,
+    is_type_in_ns: bool,
+    trait_import_info: &ImportInfo,
+) {
+    let _p = profile::span("collect_trait_assoc_items");
+    for (assoc_item_name, item) in &db.trait_data(tr).items {
+        let module_def_id = match item {
+            AssocItemId::FunctionId(f) => ModuleDefId::from(*f),
+            AssocItemId::ConstId(c) => ModuleDefId::from(*c),
+            // cannot use associated type aliases directly: need a `<Struct as Trait>::TypeAlias`
+            // qualifier, ergo no need to store it for imports in import_map
+            AssocItemId::TypeAliasId(_) => {
+                cov_mark::hit!(type_aliases_ignored);
+                continue;
+            }
+        };
+        let assoc_item = if is_type_in_ns {
+            ItemInNs::Types(module_def_id)
+        } else {
+            ItemInNs::Values(module_def_id)
+        };
+
+        let assoc_item_info = ImportInfo {
+            container: trait_import_info.container,
+            name: assoc_item_name.clone(),
+            is_trait_assoc_item: true,
+        };
+        map.insert(assoc_item, assoc_item_info);
+    }
 }
 
 impl PartialEq for ImportMap {
@@ -260,7 +199,7 @@ impl Eq for ImportMap {}
 
 impl fmt::Debug for ImportMap {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let mut importable_paths: Vec<_> = self
+        let mut importable_names: Vec<_> = self
             .map
             .iter()
             .map(|(item, _)| match item {
@@ -270,56 +209,40 @@ impl fmt::Debug for ImportMap {
             })
             .collect();
 
-        importable_paths.sort();
-        f.write_str(&importable_paths.join("\n"))
+        importable_names.sort();
+        f.write_str(&importable_names.join("\n"))
     }
 }
 
-fn fst_path(db: &dyn DefDatabase, path: &ImportPath) -> String {
-    let _p = profile::span("fst_path");
-    let mut s = path.display(db).to_string();
-    s.make_ascii_lowercase();
-    s
-}
-
-#[derive(Debug, Eq, PartialEq, Hash)]
-pub enum ImportKind {
-    Module,
-    Function,
-    Adt,
-    EnumVariant,
-    Const,
-    Static,
-    Trait,
-    TraitAlias,
-    TypeAlias,
-    BuiltinType,
-    AssociatedItem,
-    Macro,
-}
-
 /// A way to match import map contents against the search query.
 #[derive(Debug)]
-pub enum SearchMode {
+enum SearchMode {
     /// Import map entry should strictly match the query string.
-    Equals,
-    /// Import map entry should contain the query string.
-    Contains,
+    Exact,
     /// Import map entry should contain all letters from the query string,
     /// in the same order, but not necessary adjacent.
     Fuzzy,
 }
 
+/// Three possible ways to search for the name in associated and/or other items.
+#[derive(Debug, Clone, Copy)]
+pub enum AssocSearchMode {
+    /// Search for the name in both associated and other items.
+    Include,
+    /// Search for the name in other items only.
+    Exclude,
+    /// Search for the name in the associated items only.
+    AssocItemsOnly,
+}
+
 #[derive(Debug)]
 pub struct Query {
     query: String,
     lowercased: String,
-    name_only: bool,
-    assoc_items_only: bool,
     search_mode: SearchMode,
+    assoc_mode: AssocSearchMode,
     case_sensitive: bool,
     limit: usize,
-    exclude_import_kinds: FxHashSet<ImportKind>,
 }
 
 impl Query {
@@ -328,30 +251,21 @@ impl Query {
         Self {
             query,
             lowercased,
-            name_only: false,
-            assoc_items_only: false,
-            search_mode: SearchMode::Contains,
+            search_mode: SearchMode::Exact,
+            assoc_mode: AssocSearchMode::Include,
             case_sensitive: false,
-            limit: usize::max_value(),
-            exclude_import_kinds: FxHashSet::default(),
+            limit: usize::MAX,
         }
     }
 
-    /// Matches entries' names only, ignoring the rest of
-    /// the qualifier.
-    /// Example: for `std::marker::PhantomData`, the name is `PhantomData`.
-    pub fn name_only(self) -> Self {
-        Self { name_only: true, ..self }
-    }
-
-    /// Matches only the entries that are associated items, ignoring the rest.
-    pub fn assoc_items_only(self) -> Self {
-        Self { assoc_items_only: true, ..self }
+    /// Fuzzy finds items instead of exact matching.
+    pub fn fuzzy(self) -> Self {
+        Self { search_mode: SearchMode::Fuzzy, ..self }
     }
 
-    /// Specifies the way to search for the entries using the query.
-    pub fn search_mode(self, search_mode: SearchMode) -> Self {
-        Self { search_mode, ..self }
+    /// Specifies whether we want to include associated items in the result.
+    pub fn assoc_search_mode(self, assoc_mode: AssocSearchMode) -> Self {
+        Self { assoc_mode, ..self }
     }
 
     /// Limits the returned number of items to `limit`.
@@ -364,12 +278,6 @@ impl Query {
         Self { case_sensitive: true, ..self }
     }
 
-    /// Do not include imports of the specified kind in the search results.
-    pub fn exclude_import_kind(mut self, import_kind: ImportKind) -> Self {
-        self.exclude_import_kinds.insert(import_kind);
-        self
-    }
-
     fn import_matches(
         &self,
         db: &dyn DefDatabase,
@@ -377,49 +285,36 @@ impl Query {
         enforce_lowercase: bool,
     ) -> bool {
         let _p = profile::span("import_map::Query::import_matches");
-        if import.is_trait_assoc_item {
-            if self.exclude_import_kinds.contains(&ImportKind::AssociatedItem) {
-                return false;
-            }
-        } else if self.assoc_items_only {
-            return false;
+        match (import.is_trait_assoc_item, self.assoc_mode) {
+            (true, AssocSearchMode::Exclude) => return false,
+            (false, AssocSearchMode::AssocItemsOnly) => return false,
+            _ => {}
         }
 
-        let mut input = if import.is_trait_assoc_item || self.name_only {
-            import.path.segments.last().unwrap().display(db.upcast()).to_string()
-        } else {
-            import.path.display(db).to_string()
-        };
-        if enforce_lowercase || !self.case_sensitive {
+        let mut input = import.name.display(db.upcast()).to_string();
+        let case_insensitive = enforce_lowercase || !self.case_sensitive;
+        if case_insensitive {
             input.make_ascii_lowercase();
         }
 
-        let query_string =
-            if !enforce_lowercase && self.case_sensitive { &self.query } else { &self.lowercased };
+        let query_string = if case_insensitive { &self.lowercased } else { &self.query };
 
         match self.search_mode {
-            SearchMode::Equals => &input == query_string,
-            SearchMode::Contains => input.contains(query_string),
+            SearchMode::Exact => &input == query_string,
             SearchMode::Fuzzy => {
-                let mut unchecked_query_chars = query_string.chars();
-                let mut mismatching_query_char = unchecked_query_chars.next();
-
-                for input_char in input.chars() {
-                    match mismatching_query_char {
-                        None => return true,
-                        Some(matching_query_char) if matching_query_char == input_char => {
-                            mismatching_query_char = unchecked_query_chars.next();
-                        }
-                        _ => (),
+                let mut input_chars = input.chars();
+                for query_char in query_string.chars() {
+                    if input_chars.find(|&it| it == query_char).is_none() {
+                        return false;
                     }
                 }
-                mismatching_query_char.is_none()
+                true
             }
         }
     }
 }
 
-/// Searches dependencies of `krate` for an importable path matching `query`.
+/// Searches dependencies of `krate` for an importable name matching `query`.
 ///
 /// This returns a list of items that could be imported from dependencies of `krate`.
 pub fn search_dependencies(
@@ -442,65 +337,44 @@ pub fn search_dependencies(
 
     let mut stream = op.union();
 
-    let mut all_indexed_values = FxHashSet::default();
-    while let Some((_, indexed_values)) = stream.next() {
-        all_indexed_values.extend(indexed_values.iter().copied());
-    }
-
     let mut res = FxHashSet::default();
-    for indexed_value in all_indexed_values {
-        let import_map = &import_maps[indexed_value.index];
-        let importables = &import_map.importables[indexed_value.value as usize..];
+    while let Some((_, indexed_values)) = stream.next() {
+        for indexed_value in indexed_values {
+            let import_map = &import_maps[indexed_value.index];
+            let importables = &import_map.importables[indexed_value.value as usize..];
 
-        let common_importable_data = &import_map.map[&importables[0]];
-        if !query.import_matches(db, common_importable_data, true) {
-            continue;
-        }
+            let common_importable_data = &import_map.map[&importables[0]];
+            if !query.import_matches(db, common_importable_data, true) {
+                continue;
+            }
 
-        // Path shared by the importable items in this group.
-        let common_importables_path_fst = fst_path(db, &common_importable_data.path);
-        // Add the items from this `ModPath` group. Those are all subsequent items in
-        // `importables` whose paths match `path`.
-        let iter = importables
-            .iter()
-            .copied()
-            .take_while(|item| {
-                common_importables_path_fst == fst_path(db, &import_map.map[item].path)
-            })
-            .filter(|&item| match item_import_kind(item) {
-                Some(import_kind) => !query.exclude_import_kinds.contains(&import_kind),
-                None => true,
-            })
-            .filter(|item| {
-                !query.case_sensitive // we've already checked the common importables path case-insensitively
+            // Name shared by the importable items in this group.
+            let common_importable_name =
+                common_importable_data.name.to_smol_str().to_ascii_lowercase();
+            // Add the items from this name group. Those are all subsequent items in
+            // `importables` whose name match `common_importable_name`.
+            let iter = importables
+                .iter()
+                .copied()
+                .take_while(|item| {
+                    common_importable_name
+                        == import_map.map[item].name.to_smol_str().to_ascii_lowercase()
+                })
+                .filter(|item| {
+                    !query.case_sensitive // we've already checked the common importables name case-insensitively
                         || query.import_matches(db, &import_map.map[item], false)
-            });
-        res.extend(iter);
+                });
+            res.extend(iter);
 
-        if res.len() >= query.limit {
-            return res;
+            if res.len() >= query.limit {
+                return res;
+            }
         }
     }
 
     res
 }
 
-fn item_import_kind(item: ItemInNs) -> Option<ImportKind> {
-    Some(match item.as_module_def_id()? {
-        ModuleDefId::ModuleId(_) => ImportKind::Module,
-        ModuleDefId::FunctionId(_) => ImportKind::Function,
-        ModuleDefId::AdtId(_) => ImportKind::Adt,
-        ModuleDefId::EnumVariantId(_) => ImportKind::EnumVariant,
-        ModuleDefId::ConstId(_) => ImportKind::Const,
-        ModuleDefId::StaticId(_) => ImportKind::Static,
-        ModuleDefId::TraitId(_) => ImportKind::Trait,
-        ModuleDefId::TraitAliasId(_) => ImportKind::TraitAlias,
-        ModuleDefId::TypeAliasId(_) => ImportKind::TypeAlias,
-        ModuleDefId::BuiltinType(_) => ImportKind::BuiltinType,
-        ModuleDefId::MacroId(_) => ImportKind::Macro,
-    })
-}
-
 #[cfg(test)]
 mod tests {
     use base_db::{fixture::WithFixture, SourceDatabase, Upcast};
@@ -510,16 +384,39 @@ mod tests {
 
     use super::*;
 
+    impl ImportMap {
+        fn fmt_for_test(&self, db: &dyn DefDatabase) -> String {
+            let mut importable_paths: Vec<_> = self
+                .map
+                .iter()
+                .map(|(item, info)| {
+                    let path = render_path(db, info);
+                    let ns = match item {
+                        ItemInNs::Types(_) => "t",
+                        ItemInNs::Values(_) => "v",
+                        ItemInNs::Macros(_) => "m",
+                    };
+                    format!("- {path} ({ns})")
+                })
+                .collect();
+
+            importable_paths.sort();
+            importable_paths.join("\n")
+        }
+    }
+
     fn check_search(ra_fixture: &str, crate_name: &str, query: Query, expect: Expect) {
         let db = TestDB::with_files(ra_fixture);
         let crate_graph = db.crate_graph();
         let krate = crate_graph
             .iter()
-            .find(|krate| {
-                crate_graph[*krate].display_name.as_ref().map(|n| n.to_string())
-                    == Some(crate_name.to_string())
+            .find(|&krate| {
+                crate_graph[krate]
+                    .display_name
+                    .as_ref()
+                    .is_some_and(|it| &**it.crate_name() == crate_name)
             })
-            .unwrap();
+            .expect("could not find crate");
 
         let actual = search_dependencies(db.upcast(), krate, query)
             .into_iter()
@@ -530,7 +427,7 @@ mod tests {
                 let (path, mark) = match assoc_item_path(&db, &dependency_imports, dependency) {
                     Some(assoc_item_path) => (assoc_item_path, "a"),
                     None => (
-                        dependency_imports.path_of(dependency)?.display(&db).to_string(),
+                        render_path(&db, dependency_imports.import_info_for(dependency)?),
                         match dependency {
                             ItemInNs::Types(ModuleDefId::FunctionId(_))
                             | ItemInNs::Values(ModuleDefId::FunctionId(_)) => "f",
@@ -560,57 +457,25 @@ mod tests {
         dependency_imports: &ImportMap,
         dependency: ItemInNs,
     ) -> Option<String> {
-        let dependency_assoc_item_id = match dependency {
-            ItemInNs::Types(ModuleDefId::FunctionId(id))
-            | ItemInNs::Values(ModuleDefId::FunctionId(id)) => AssocItemId::from(id),
-            ItemInNs::Types(ModuleDefId::ConstId(id))
-            | ItemInNs::Values(ModuleDefId::ConstId(id)) => AssocItemId::from(id),
-            ItemInNs::Types(ModuleDefId::TypeAliasId(id))
-            | ItemInNs::Values(ModuleDefId::TypeAliasId(id)) => AssocItemId::from(id),
+        let (dependency_assoc_item_id, container) = match dependency.as_module_def_id()? {
+            ModuleDefId::FunctionId(id) => (AssocItemId::from(id), id.lookup(db).container),
+            ModuleDefId::ConstId(id) => (AssocItemId::from(id), id.lookup(db).container),
+            ModuleDefId::TypeAliasId(id) => (AssocItemId::from(id), id.lookup(db).container),
             _ => return None,
         };
 
-        let trait_ = assoc_to_trait(db, dependency)?;
-        if let ModuleDefId::TraitId(tr) = trait_.as_module_def_id()? {
-            let trait_data = db.trait_data(tr);
-            let assoc_item_name =
-                trait_data.items.iter().find_map(|(assoc_item_name, assoc_item_id)| {
-                    if &dependency_assoc_item_id == assoc_item_id {
-                        Some(assoc_item_name)
-                    } else {
-                        None
-                    }
-                })?;
-            return Some(format!(
-                "{}::{}",
-                dependency_imports.path_of(trait_)?.display(db),
-                assoc_item_name.display(db.upcast())
-            ));
-        }
-        None
-    }
-
-    fn assoc_to_trait(db: &dyn DefDatabase, item: ItemInNs) -> Option<ItemInNs> {
-        let assoc: AssocItemId = match item {
-            ItemInNs::Types(it) | ItemInNs::Values(it) => match it {
-                ModuleDefId::TypeAliasId(it) => it.into(),
-                ModuleDefId::FunctionId(it) => it.into(),
-                ModuleDefId::ConstId(it) => it.into(),
-                _ => return None,
-            },
-            _ => return None,
+        let ItemContainerId::TraitId(trait_id) = container else {
+            return None;
         };
 
-        let container = match assoc {
-            AssocItemId::FunctionId(it) => it.lookup(db).container,
-            AssocItemId::ConstId(it) => it.lookup(db).container,
-            AssocItemId::TypeAliasId(it) => it.lookup(db).container,
-        };
+        let trait_info = dependency_imports.import_info_for(ItemInNs::Types(trait_id.into()))?;
 
-        match container {
-            ItemContainerId::TraitId(it) => Some(ItemInNs::Types(it.into())),
-            _ => None,
-        }
+        let trait_data = db.trait_data(trait_id);
+        let (assoc_item_name, _) = trait_data
+            .items
+            .iter()
+            .find(|(_, assoc_item_id)| &dependency_assoc_item_id == assoc_item_id)?;
+        Some(format!("{}::{}", render_path(db, trait_info), assoc_item_name.display(db.upcast())))
     }
 
     fn check(ra_fixture: &str, expect: Expect) {
@@ -633,6 +498,24 @@ mod tests {
         expect.assert_eq(&actual)
     }
 
+    fn render_path(db: &dyn DefDatabase, info: &ImportInfo) -> String {
+        let mut module = info.container;
+        let mut segments = vec![&info.name];
+
+        let def_map = module.def_map(db);
+        assert!(def_map.block_id().is_none(), "block local items should not be in `ImportMap`");
+
+        while let Some(parent) = module.containing_module(db) {
+            let parent_data = &def_map[parent.local_id];
+            let (name, _) =
+                parent_data.children.iter().find(|(_, id)| **id == module.local_id).unwrap();
+            segments.push(name);
+            module = parent;
+        }
+
+        segments.iter().rev().map(|it| it.display(db.upcast())).join("::")
+    }
+
     #[test]
     fn smoke() {
         check(
@@ -749,6 +632,7 @@ mod tests {
     #[test]
     fn module_reexport() {
         // Reexporting modules from a dependency adds all contents to the import map.
+        // XXX: The rendered paths are relative to the defining crate.
         check(
             r"
             //- /main.rs crate:main deps:lib
@@ -764,9 +648,9 @@ mod tests {
                 - module::S (t)
                 - module::S (v)
                 main:
+                - module::S (t)
+                - module::S (v)
                 - reexported_module (t)
-                - reexported_module::S (t)
-                - reexported_module::S (v)
             "#]],
         );
     }
@@ -868,10 +752,9 @@ mod tests {
         check_search(
             ra_fixture,
             "main",
-            Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy),
+            Query::new("fmt".to_string()).fuzzy(),
             expect![[r#"
                 dep::fmt (t)
-                dep::fmt::Display (t)
                 dep::fmt::Display::FMT_CONST (a)
                 dep::fmt::Display::format_function (a)
                 dep::fmt::Display::format_method (a)
@@ -898,7 +781,9 @@ mod tests {
         check_search(
             ra_fixture,
             "main",
-            Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy).assoc_items_only(),
+            Query::new("fmt".to_string())
+                .fuzzy()
+                .assoc_search_mode(AssocSearchMode::AssocItemsOnly),
             expect![[r#"
                 dep::fmt::Display::FMT_CONST (a)
                 dep::fmt::Display::format_function (a)
@@ -909,23 +794,10 @@ mod tests {
         check_search(
             ra_fixture,
             "main",
-            Query::new("fmt".to_string())
-                .search_mode(SearchMode::Fuzzy)
-                .exclude_import_kind(ImportKind::AssociatedItem),
+            Query::new("fmt".to_string()).fuzzy().assoc_search_mode(AssocSearchMode::Exclude),
             expect![[r#"
-            dep::fmt (t)
-            dep::fmt::Display (t)
-        "#]],
-        );
-
-        check_search(
-            ra_fixture,
-            "main",
-            Query::new("fmt".to_string())
-                .search_mode(SearchMode::Fuzzy)
-                .assoc_items_only()
-                .exclude_import_kind(ImportKind::AssociatedItem),
-            expect![[r#""#]],
+                dep::fmt (t)
+            "#]],
         );
     }
 
@@ -958,13 +830,12 @@ mod tests {
         check_search(
             ra_fixture,
             "main",
-            Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy),
+            Query::new("fmt".to_string()).fuzzy(),
             expect![[r#"
                 dep::Fmt (m)
                 dep::Fmt (t)
                 dep::Fmt (v)
                 dep::fmt (t)
-                dep::fmt::Display (t)
                 dep::fmt::Display::fmt (a)
                 dep::format (f)
             "#]],
@@ -973,26 +844,12 @@ mod tests {
         check_search(
             ra_fixture,
             "main",
-            Query::new("fmt".to_string()).search_mode(SearchMode::Equals),
-            expect![[r#"
-                dep::Fmt (m)
-                dep::Fmt (t)
-                dep::Fmt (v)
-                dep::fmt (t)
-                dep::fmt::Display::fmt (a)
-            "#]],
-        );
-
-        check_search(
-            ra_fixture,
-            "main",
-            Query::new("fmt".to_string()).search_mode(SearchMode::Contains),
+            Query::new("fmt".to_string()),
             expect![[r#"
                 dep::Fmt (m)
                 dep::Fmt (t)
                 dep::Fmt (v)
                 dep::fmt (t)
-                dep::fmt::Display (t)
                 dep::fmt::Display::fmt (a)
             "#]],
         );
@@ -1033,7 +890,6 @@ mod tests {
                 dep::Fmt (t)
                 dep::Fmt (v)
                 dep::fmt (t)
-                dep::fmt::Display (t)
                 dep::fmt::Display::fmt (a)
             "#]],
         );
@@ -1041,7 +897,7 @@ mod tests {
         check_search(
             ra_fixture,
             "main",
-            Query::new("fmt".to_string()).name_only(),
+            Query::new("fmt".to_string()),
             expect![[r#"
                 dep::Fmt (m)
                 dep::Fmt (t)
@@ -1106,43 +962,10 @@ mod tests {
         pub fn no() {}
     "#,
             "main",
-            Query::new("".to_string()).limit(2),
-            expect![[r#"
-                dep::Fmt (m)
-                dep::Fmt (t)
-                dep::Fmt (v)
-                dep::fmt (t)
-            "#]],
-        );
-    }
-
-    #[test]
-    fn search_exclusions() {
-        let ra_fixture = r#"
-            //- /main.rs crate:main deps:dep
-            //- /dep.rs crate:dep
-
-            pub struct fmt;
-            pub struct FMT;
-        "#;
-
-        check_search(
-            ra_fixture,
-            "main",
-            Query::new("FMT".to_string()),
+            Query::new("".to_string()).fuzzy().limit(1),
             expect![[r#"
-                dep::FMT (t)
-                dep::FMT (v)
-                dep::fmt (t)
-                dep::fmt (v)
+                dep::fmt::Display (t)
             "#]],
         );
-
-        check_search(
-            ra_fixture,
-            "main",
-            Query::new("FMT".to_string()).exclude_import_kind(ImportKind::Adt),
-            expect![[r#""#]],
-        );
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
index 2001fb29a9e..2ac1bcdc079 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
@@ -14,8 +14,8 @@ use stdx::format_to;
 use syntax::ast;
 
 use crate::{
-    db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ConstId, HasModule,
-    ImplId, LocalModuleId, MacroId, ModuleDefId, ModuleId, TraitId,
+    db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ConstId,
+    ExternCrateId, HasModule, ImplId, LocalModuleId, MacroId, ModuleDefId, ModuleId, TraitId,
 };
 
 #[derive(Copy, Clone, Debug)]
@@ -50,6 +50,7 @@ pub struct ItemScope {
     unnamed_consts: Vec<ConstId>,
     /// Traits imported via `use Trait as _;`.
     unnamed_trait_imports: FxHashMap<TraitId, Visibility>,
+    extern_crate_decls: Vec<ExternCrateId>,
     /// Macros visible in current module in legacy textual scope
     ///
     /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first.
@@ -188,7 +189,11 @@ impl ItemScope {
     }
 
     pub(crate) fn define_impl(&mut self, imp: ImplId) {
-        self.impls.push(imp)
+        self.impls.push(imp);
+    }
+
+    pub(crate) fn define_extern_crate_decl(&mut self, extern_crate: ExternCrateId) {
+        self.extern_crate_decls.push(extern_crate);
     }
 
     pub(crate) fn define_unnamed_const(&mut self, konst: ConstId) {
@@ -397,6 +402,7 @@ impl ItemScope {
             legacy_macros,
             attr_macros,
             derive_macros,
+            extern_crate_decls,
         } = self;
         types.shrink_to_fit();
         values.shrink_to_fit();
@@ -409,6 +415,7 @@ impl ItemScope {
         legacy_macros.shrink_to_fit();
         attr_macros.shrink_to_fit();
         derive_macros.shrink_to_fit();
+        extern_crate_decls.shrink_to_fit();
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
index e74b71888c2..6f80bb6e07c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
@@ -46,7 +46,7 @@ use ast::{AstNode, HasName, StructKind};
 use base_db::CrateId;
 use either::Either;
 use hir_expand::{
-    ast_id_map::FileAstId,
+    ast_id_map::{AstIdNode, FileAstId},
     attrs::RawAttrs,
     hygiene::Hygiene,
     name::{name, AsName, Name},
@@ -314,7 +314,7 @@ from_attrs!(ModItem(ModItem), Variant(Idx<Variant>), Field(Idx<Field>), Param(Id
 
 /// Trait implemented by all item nodes in the item tree.
 pub trait ItemTreeNode: Clone {
-    type Source: AstNode + Into<ast::Item>;
+    type Source: AstIdNode + Into<ast::Item>;
 
     fn ast_id(&self) -> FileAstId<Self::Source>;
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
index e873316a578..ddf668d20b0 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
@@ -52,7 +52,7 @@ struct Printer<'a> {
     needs_indent: bool,
 }
 
-impl<'a> Printer<'a> {
+impl Printer<'_> {
     fn indented(&mut self, f: impl FnOnce(&mut Self)) {
         self.indent_level += 1;
         wln!(self);
@@ -572,7 +572,7 @@ impl<'a> Printer<'a> {
     }
 }
 
-impl<'a> Write for Printer<'a> {
+impl Write for Printer<'_> {
     fn write_str(&mut self, s: &str) -> fmt::Result {
         for line in s.split_inclusive('\n') {
             if self.needs_indent {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
index 0e9ac58fbaa..627479bb7c1 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
@@ -180,15 +180,15 @@ impl LangItems {
         T: Into<AttrDefId> + Copy,
     {
         let _p = profile::span("collect_lang_item");
-        if let Some(lang_item) = lang_attr(db, item) {
+        if let Some(lang_item) = db.lang_attr(item.into()) {
             self.items.entry(lang_item).or_insert_with(|| constructor(item));
         }
     }
 }
 
-pub fn lang_attr(db: &dyn DefDatabase, item: impl Into<AttrDefId> + Copy) -> Option<LangItem> {
-    let attrs = db.attrs(item.into());
-    attrs.by_key("lang").string_value().cloned().and_then(|it| LangItem::from_str(&it))
+pub(crate) fn lang_attr_query(db: &dyn DefDatabase, item: AttrDefId) -> Option<LangItem> {
+    let attrs = db.attrs(item);
+    attrs.by_key("lang").string_value().and_then(|it| LangItem::from_str(&it))
 }
 
 pub enum GenericRequirement {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
index 9d8b57a0da9..1e74e2dfcb4 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -64,7 +64,7 @@ use std::{
 
 use base_db::{impl_intern_key, salsa, CrateId, ProcMacroKind};
 use hir_expand::{
-    ast_id_map::FileAstId,
+    ast_id_map::{AstIdNode, FileAstId},
     attrs::{Attr, AttrId, AttrInput},
     builtin_attr_macro::BuiltinAttrExpander,
     builtin_derive_macro::BuiltinDeriveExpander,
@@ -88,8 +88,8 @@ use crate::{
     builtin_type::BuiltinType,
     data::adt::VariantData,
     item_tree::{
-        Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, MacroDef, MacroRules, Static,
-        Struct, Trait, TraitAlias, TypeAlias, Union,
+        Const, Enum, ExternCrate, Function, Impl, Import, ItemTreeId, ItemTreeNode, MacroDef,
+        MacroRules, Static, Struct, Trait, TraitAlias, TypeAlias, Union,
     },
 };
 
@@ -145,24 +145,28 @@ pub struct ModuleId {
 }
 
 impl ModuleId {
-    pub fn def_map(&self, db: &dyn db::DefDatabase) -> Arc<DefMap> {
+    pub fn def_map(self, db: &dyn db::DefDatabase) -> Arc<DefMap> {
         match self.block {
             Some(block) => db.block_def_map(block),
             None => db.crate_def_map(self.krate),
         }
     }
 
-    pub fn krate(&self) -> CrateId {
+    pub fn krate(self) -> CrateId {
         self.krate
     }
 
-    pub fn containing_module(&self, db: &dyn db::DefDatabase) -> Option<ModuleId> {
+    pub fn containing_module(self, db: &dyn db::DefDatabase) -> Option<ModuleId> {
         self.def_map(db).containing_module(self.local_id)
     }
 
-    pub fn containing_block(&self) -> Option<BlockId> {
+    pub fn containing_block(self) -> Option<BlockId> {
         self.block
     }
+
+    pub fn is_block_module(self) -> bool {
+        self.block.is_some() && self.local_id == DefMap::ROOT
+    }
 }
 
 /// An ID of a module, **local** to a `DefMap`.
@@ -314,6 +318,16 @@ type ImplLoc = ItemLoc<Impl>;
 impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
+pub struct ImportId(salsa::InternId);
+type ImportLoc = ItemLoc<Import>;
+impl_intern!(ImportId, ImportLoc, intern_import, lookup_intern_import);
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
+pub struct ExternCrateId(salsa::InternId);
+type ExternCrateLoc = ItemLoc<ExternCrate>;
+impl_intern!(ExternCrateId, ExternCrateLoc, intern_extern_crate, lookup_intern_extern_crate);
+
+#[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);
@@ -392,14 +406,14 @@ impl TypeParamId {
 
 impl TypeParamId {
     /// Caller should check if this toc id really belongs to a type
-    pub fn from_unchecked(x: TypeOrConstParamId) -> Self {
-        Self(x)
+    pub fn from_unchecked(it: TypeOrConstParamId) -> Self {
+        Self(it)
     }
 }
 
 impl From<TypeParamId> for TypeOrConstParamId {
-    fn from(x: TypeParamId) -> Self {
-        x.0
+    fn from(it: TypeParamId) -> Self {
+        it.0
     }
 }
 
@@ -418,14 +432,14 @@ impl ConstParamId {
 
 impl ConstParamId {
     /// Caller should check if this toc id really belongs to a const
-    pub fn from_unchecked(x: TypeOrConstParamId) -> Self {
-        Self(x)
+    pub fn from_unchecked(it: TypeOrConstParamId) -> Self {
+        Self(it)
     }
 }
 
 impl From<ConstParamId> for TypeOrConstParamId {
-    fn from(x: ConstParamId) -> Self {
-        x.0
+    fn from(it: ConstParamId) -> Self {
+        it.0
     }
 }
 
@@ -548,14 +562,14 @@ pub enum TypeOwnerId {
 impl TypeOwnerId {
     fn as_generic_def_id(self) -> Option<GenericDefId> {
         Some(match self {
-            TypeOwnerId::FunctionId(x) => GenericDefId::FunctionId(x),
-            TypeOwnerId::ConstId(x) => GenericDefId::ConstId(x),
-            TypeOwnerId::AdtId(x) => GenericDefId::AdtId(x),
-            TypeOwnerId::TraitId(x) => GenericDefId::TraitId(x),
-            TypeOwnerId::TraitAliasId(x) => GenericDefId::TraitAliasId(x),
-            TypeOwnerId::TypeAliasId(x) => GenericDefId::TypeAliasId(x),
-            TypeOwnerId::ImplId(x) => GenericDefId::ImplId(x),
-            TypeOwnerId::EnumVariantId(x) => GenericDefId::EnumVariantId(x),
+            TypeOwnerId::FunctionId(it) => GenericDefId::FunctionId(it),
+            TypeOwnerId::ConstId(it) => GenericDefId::ConstId(it),
+            TypeOwnerId::AdtId(it) => GenericDefId::AdtId(it),
+            TypeOwnerId::TraitId(it) => GenericDefId::TraitId(it),
+            TypeOwnerId::TraitAliasId(it) => GenericDefId::TraitAliasId(it),
+            TypeOwnerId::TypeAliasId(it) => GenericDefId::TypeAliasId(it),
+            TypeOwnerId::ImplId(it) => GenericDefId::ImplId(it),
+            TypeOwnerId::EnumVariantId(it) => GenericDefId::EnumVariantId(it),
             TypeOwnerId::InTypeConstId(_) | TypeOwnerId::ModuleId(_) | TypeOwnerId::StaticId(_) => {
                 return None
             }
@@ -578,15 +592,15 @@ impl_from!(
     for TypeOwnerId
 );
 
-// Every `DefWithBodyId` is a type owner, since bodies can contain type (e.g. `{ let x: Type = _; }`)
+// Every `DefWithBodyId` is a type owner, since bodies can contain type (e.g. `{ let it: Type = _; }`)
 impl From<DefWithBodyId> for TypeOwnerId {
     fn from(value: DefWithBodyId) -> Self {
         match value {
-            DefWithBodyId::FunctionId(x) => x.into(),
-            DefWithBodyId::StaticId(x) => x.into(),
-            DefWithBodyId::ConstId(x) => x.into(),
-            DefWithBodyId::InTypeConstId(x) => x.into(),
-            DefWithBodyId::VariantId(x) => x.into(),
+            DefWithBodyId::FunctionId(it) => it.into(),
+            DefWithBodyId::StaticId(it) => it.into(),
+            DefWithBodyId::ConstId(it) => it.into(),
+            DefWithBodyId::InTypeConstId(it) => it.into(),
+            DefWithBodyId::VariantId(it) => it.into(),
         }
     }
 }
@@ -594,14 +608,14 @@ impl From<DefWithBodyId> for TypeOwnerId {
 impl From<GenericDefId> for TypeOwnerId {
     fn from(value: GenericDefId) -> Self {
         match value {
-            GenericDefId::FunctionId(x) => x.into(),
-            GenericDefId::AdtId(x) => x.into(),
-            GenericDefId::TraitId(x) => x.into(),
-            GenericDefId::TraitAliasId(x) => x.into(),
-            GenericDefId::TypeAliasId(x) => x.into(),
-            GenericDefId::ImplId(x) => x.into(),
-            GenericDefId::EnumVariantId(x) => x.into(),
-            GenericDefId::ConstId(x) => x.into(),
+            GenericDefId::FunctionId(it) => it.into(),
+            GenericDefId::AdtId(it) => it.into(),
+            GenericDefId::TraitId(it) => it.into(),
+            GenericDefId::TraitAliasId(it) => it.into(),
+            GenericDefId::TypeAliasId(it) => it.into(),
+            GenericDefId::ImplId(it) => it.into(),
+            GenericDefId::EnumVariantId(it) => it.into(),
+            GenericDefId::ConstId(it) => it.into(),
         }
     }
 }
@@ -716,7 +730,7 @@ impl GeneralConstId {
                 .const_data(const_id)
                 .name
                 .as_ref()
-                .and_then(|x| x.as_str())
+                .and_then(|it| it.as_str())
                 .unwrap_or("_")
                 .to_owned(),
             GeneralConstId::ConstBlockId(id) => format!("{{anonymous const {id:?}}}"),
@@ -821,6 +835,7 @@ pub enum AttrDefId {
     ImplId(ImplId),
     GenericParamId(GenericParamId),
     ExternBlockId(ExternBlockId),
+    ExternCrateId(ExternCrateId),
 }
 
 impl_from!(
@@ -835,7 +850,8 @@ impl_from!(
     TypeAliasId,
     MacroId(Macro2Id, MacroRulesId, ProcMacroId),
     ImplId,
-    GenericParamId
+    GenericParamId,
+    ExternCrateId
     for AttrDefId
 );
 
@@ -927,6 +943,12 @@ impl HasModule for AdtId {
     }
 }
 
+impl HasModule for ExternCrateId {
+    fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
+        self.lookup(db).container
+    }
+}
+
 impl HasModule for VariantId {
     fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
         match self {
@@ -950,17 +972,17 @@ impl HasModule for MacroId {
 impl HasModule for TypeOwnerId {
     fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
         match self {
-            TypeOwnerId::FunctionId(x) => x.lookup(db).module(db),
-            TypeOwnerId::StaticId(x) => x.lookup(db).module(db),
-            TypeOwnerId::ConstId(x) => x.lookup(db).module(db),
-            TypeOwnerId::InTypeConstId(x) => x.lookup(db).owner.module(db),
-            TypeOwnerId::AdtId(x) => x.module(db),
-            TypeOwnerId::TraitId(x) => x.lookup(db).container,
-            TypeOwnerId::TraitAliasId(x) => x.lookup(db).container,
-            TypeOwnerId::TypeAliasId(x) => x.lookup(db).module(db),
-            TypeOwnerId::ImplId(x) => x.lookup(db).container,
-            TypeOwnerId::EnumVariantId(x) => x.parent.lookup(db).container,
-            TypeOwnerId::ModuleId(x) => *x,
+            TypeOwnerId::FunctionId(it) => it.lookup(db).module(db),
+            TypeOwnerId::StaticId(it) => it.lookup(db).module(db),
+            TypeOwnerId::ConstId(it) => it.lookup(db).module(db),
+            TypeOwnerId::InTypeConstId(it) => it.lookup(db).owner.module(db),
+            TypeOwnerId::AdtId(it) => it.module(db),
+            TypeOwnerId::TraitId(it) => it.lookup(db).container,
+            TypeOwnerId::TraitAliasId(it) => it.lookup(db).container,
+            TypeOwnerId::TypeAliasId(it) => it.lookup(db).module(db),
+            TypeOwnerId::ImplId(it) => it.lookup(db).container,
+            TypeOwnerId::EnumVariantId(it) => it.parent.lookup(db).container,
+            TypeOwnerId::ModuleId(it) => *it,
         }
     }
 }
@@ -1050,6 +1072,7 @@ impl AttrDefId {
                 .krate
             }
             AttrDefId::MacroId(it) => it.module(db).krate,
+            AttrDefId::ExternCrateId(it) => it.lookup(db).container.krate,
         }
     }
 }
@@ -1101,12 +1124,12 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
 
 /// Helper wrapper for `AstId` with `ModPath`
 #[derive(Clone, Debug, Eq, PartialEq)]
-struct AstIdWithPath<T: ast::AstNode> {
+struct AstIdWithPath<T: AstIdNode> {
     ast_id: AstId<T>,
     path: path::ModPath,
 }
 
-impl<T: ast::AstNode> AstIdWithPath<T> {
+impl<T: AstIdNode> AstIdWithPath<T> {
     fn new(file_id: HirFileId, ast_id: FileAstId<T>, path: path::ModPath) -> AstIdWithPath<T> {
         AstIdWithPath { ast_id: AstId::new(file_id, ast_id), path }
     }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
index af623fd0e5d..e523c229179 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
@@ -1,5 +1,9 @@
 //! Context for lowering paths.
-use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, AstId, HirFileId, InFile};
+use hir_expand::{
+    ast_id_map::{AstIdMap, AstIdNode},
+    hygiene::Hygiene,
+    AstId, HirFileId, InFile,
+};
 use once_cell::unsync::OnceCell;
 use syntax::ast;
 use triomphe::Arc;
@@ -37,7 +41,7 @@ impl<'a> LowerCtx<'a> {
         Path::from_src(ast, self)
     }
 
-    pub(crate) fn ast_id<N: syntax::AstNode>(&self, item: &N) -> Option<AstId<N>> {
+    pub(crate) fn ast_id<N: AstIdNode>(&self, item: &N) -> Option<AstId<N>> {
         let &(file_id, ref ast_id_map) = self.ast_id_map.as_ref()?;
         let ast_id_map = ast_id_map.get_or_init(|| self.db.ast_id_map(file_id));
         Some(InFile::new(file_id, ast_id_map.ast_id(item)))
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs
index f41f9719043..abd84c6a46d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs
@@ -279,6 +279,44 @@ impl < > core::cmp::Eq for Command< > where {}"#]],
 }
 
 #[test]
+fn test_partial_eq_expand_with_derive_const() {
+    // FIXME: actually expand with const
+    check(
+        r#"
+//- minicore: derive, eq
+#[derive_const(PartialEq, Eq)]
+enum Command {
+    Move { x: i32, y: i32 },
+    Do(&'static str),
+    Jump,
+}
+"#,
+        expect![[r#"
+#[derive_const(PartialEq, Eq)]
+enum Command {
+    Move { x: i32, y: i32 },
+    Do(&'static str),
+    Jump,
+}
+
+impl < > core::cmp::PartialEq for Command< > where {
+    fn eq(&self , other: &Self ) -> bool {
+        match (self , other) {
+            (Command::Move {
+                x: x_self, y: y_self,
+            }
+            , Command::Move {
+                x: x_other, y: y_other,
+            }
+            )=>x_self.eq(x_other) && y_self.eq(y_other), (Command::Do(f0_self, ), Command::Do(f0_other, ))=>f0_self.eq(f0_other), (Command::Jump, Command::Jump)=>true , _unused=>false
+        }
+    }
+}
+impl < > core::cmp::Eq for Command< > where {}"#]],
+    );
+}
+
+#[test]
 fn test_partial_ord_expand() {
     check(
         r#"
@@ -379,6 +417,44 @@ fn test_hash_expand() {
 use core::hash::Hash;
 
 #[derive(Hash)]
+struct Foo {
+    x: i32,
+    y: u64,
+    z: (i32, u64),
+}
+"#,
+        expect![[r#"
+use core::hash::Hash;
+
+#[derive(Hash)]
+struct Foo {
+    x: i32,
+    y: u64,
+    z: (i32, u64),
+}
+
+impl < > core::hash::Hash for Foo< > where {
+    fn hash<H: core::hash::Hasher>(&self , ra_expand_state: &mut H) {
+        match self {
+            Foo {
+                x: x, y: y, z: z,
+            }
+            => {
+                x.hash(ra_expand_state);
+                y.hash(ra_expand_state);
+                z.hash(ra_expand_state);
+            }
+            ,
+        }
+    }
+}"#]],
+    );
+    check(
+        r#"
+//- minicore: derive, hash
+use core::hash::Hash;
+
+#[derive(Hash)]
 enum Command {
     Move { x: i32, y: i32 },
     Do(&'static str),
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
index 07d9baa5897..b232651db96 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
@@ -201,7 +201,7 @@ macro_rules! format_args {
 }
 
 fn main() {
-    ::core::fmt::Arguments::new_v1(&["", " ", ], &[::core::fmt::Argument::new(&(arg1(a, b, c)), ::core::fmt::Display::fmt), ::core::fmt::Argument::new(&(arg2), ::core::fmt::Debug::fmt), ]);
+    ::core::fmt::Arguments::new_v1(&["", " ", ], &[::core::fmt::ArgumentV1::new(&(arg1(a, b, c)), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(arg2), ::core::fmt::Debug::fmt), ]);
 }
 "##]],
     );
@@ -235,11 +235,11 @@ macro_rules! format_args {
 
 fn main() {
     /* error: no rule matches input tokens */;
-    /* error: no rule matches input tokens */;
-    /* error: no rule matches input tokens */;
-    /* error: no rule matches input tokens */::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::Argument::new(&(), ::core::fmt::Display::fmt), ]);
-    /* error: no rule matches input tokens */;
-    ::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::Argument::new(&(5), ::core::fmt::Display::fmt), ]);
+    /* error: expected expression */;
+    /* error: expected expression, expected COMMA */;
+    /* error: expected expression */::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::ArgumentV1::new(&(), ::core::fmt::Display::fmt), ]);
+    /* error: expected expression, expected R_PAREN */;
+    ::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::ArgumentV1::new(&(5), ::core::fmt::Display::fmt), ]);
 }
 "##]],
     );
@@ -267,7 +267,7 @@ macro_rules! format_args {
 }
 
 fn main() {
-    ::core::fmt::Arguments::new_v1(&["", " ", ], &[::core::fmt::Argument::new(&(a::<A, B>()), ::core::fmt::Display::fmt), ::core::fmt::Argument::new(&(b), ::core::fmt::Debug::fmt), ]);
+    ::core::fmt::Arguments::new_v1(&["", " ", ], &[::core::fmt::ArgumentV1::new(&(a::<A, B>()), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(b), ::core::fmt::Debug::fmt), ]);
 }
 "##]],
     );
@@ -300,7 +300,7 @@ macro_rules! format_args {
 }
 
 fn main() {
-    ::core::fmt::Arguments::new_v1(&[r#""#, r#",mismatch,""#, r#"",""#, r#"""#, ], &[::core::fmt::Argument::new(&(location_csv_pat(db, &analysis, vfs, &sm, pat_id)), ::core::fmt::Display::fmt), ::core::fmt::Argument::new(&(mismatch.expected.display(db)), ::core::fmt::Display::fmt), ::core::fmt::Argument::new(&(mismatch.actual.display(db)), ::core::fmt::Display::fmt), ]);
+    ::core::fmt::Arguments::new_v1(&[r#""#, r#",mismatch,""#, r#"",""#, r#"""#, ], &[::core::fmt::ArgumentV1::new(&(location_csv_pat(db, &analysis, vfs, &sm, pat_id)), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(mismatch.expected.display(db)), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(mismatch.actual.display(db)), ::core::fmt::Display::fmt), ]);
 }
 "##]],
     );
@@ -334,7 +334,7 @@ macro_rules! format_args {
 }
 
 fn main() {
-    ::core::fmt::Arguments::new_v1(&["xxx", "y", "zzz", ], &[::core::fmt::Argument::new(&(2), ::core::fmt::Display::fmt), ::core::fmt::Argument::new(&(b), ::core::fmt::Debug::fmt), ]);
+    ::core::fmt::Arguments::new_v1(&["xxx", "y", "zzz", ], &[::core::fmt::ArgumentV1::new(&(2), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(b), ::core::fmt::Debug::fmt), ]);
 }
 "##]],
     );
@@ -364,8 +364,8 @@ macro_rules! format_args {
 
 fn main() {
     let _ =
-        /* error: no rule matches input tokens *//* parse error: expected field name or number */
-::core::fmt::Arguments::new_v1(&["", " ", ], &[::core::fmt::Argument::new(&(a.), ::core::fmt::Display::fmt), ::core::fmt::Argument::new(&(), ::core::fmt::Debug::fmt), ]);
+        /* error: expected field name or number *//* parse error: expected field name or number */
+::core::fmt::Arguments::new_v1(&["", " ", ], &[::core::fmt::ArgumentV1::new(&(a.), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(), ::core::fmt::Debug::fmt), ]);
 }
 "##]],
     );
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
index 553ffe3d0b8..b26f9867580 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
@@ -98,6 +98,42 @@ fn#19 main#20(#21)#21 {#22
 "##]],
     );
 }
+
+#[test]
+fn token_mapping_eager() {
+    check(
+        r#"
+#[rustc_builtin_macro]
+#[macro_export]
+macro_rules! format_args {}
+
+macro_rules! identity {
+    ($expr:expr) => { $expr };
+}
+
+fn main(foo: ()) {
+    format_args/*+tokenids*/!("{} {} {}", format_args!("{}", 0), foo, identity!(10), "bar")
+}
+
+"#,
+        expect![[r##"
+#[rustc_builtin_macro]
+#[macro_export]
+macro_rules! format_args {}
+
+macro_rules! identity {
+    ($expr:expr) => { $expr };
+}
+
+fn main(foo: ()) {
+    // format_args/*+tokenids*/!("{} {} {}"#1,#3 format_args!("{}", 0#10),#12 foo#13,#14 identity!(10#18),#21 "bar"#22)
+::core#4294967295::fmt#4294967295::Arguments#4294967295::new_v1#4294967295(&#4294967295[#4294967295""#4294967295,#4294967295 " "#4294967295,#4294967295 " "#4294967295,#4294967295 ]#4294967295,#4294967295 &#4294967295[::core#4294967295::fmt#4294967295::ArgumentV1#4294967295::new#4294967295(&#4294967295(::core#4294967295::fmt#4294967295::Arguments#4294967295::new_v1#4294967295(&#4294967295[#4294967295""#4294967295,#4294967295 ]#4294967295,#4294967295 &#4294967295[::core#4294967295::fmt#4294967295::ArgumentV1#4294967295::new#4294967295(&#4294967295(#42949672950#10)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::Display#4294967295::fmt#4294967295)#4294967295,#4294967295 ]#4294967295)#4294967295)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::Display#4294967295::fmt#4294967295)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::ArgumentV1#4294967295::new#4294967295(&#4294967295(#4294967295foo#13)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::Display#4294967295::fmt#4294967295)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::ArgumentV1#4294967295::new#4294967295(&#4294967295(#429496729510#18)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::Display#4294967295::fmt#4294967295)#4294967295,#4294967295 ]#4294967295)#4294967295
+}
+
+"##]],
+    );
+}
+
 #[test]
 fn float_field_access_macro_input() {
     check(
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
index 4a62696df08..7a87e61c693 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
@@ -20,8 +20,8 @@ use ::mbe::TokenMap;
 use base_db::{fixture::WithFixture, ProcMacro, SourceDatabase};
 use expect_test::Expect;
 use hir_expand::{
-    db::{ExpandDatabase, TokenExpander},
-    AstId, InFile, MacroDefId, MacroDefKind, MacroFile,
+    db::{DeclarativeMacroExpander, ExpandDatabase},
+    AstId, InFile, MacroFile,
 };
 use stdx::format_to;
 use syntax::{
@@ -100,32 +100,29 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
         let call_offset = macro_.syntax().text_range().start().into();
         let file_ast_id = db.ast_id_map(source.file_id).ast_id(&macro_);
         let ast_id = AstId::new(source.file_id, file_ast_id.upcast());
-        let kind = MacroDefKind::Declarative(ast_id);
 
-        let macro_def = db
-            .macro_def(MacroDefId { krate, kind, local_inner: false, allow_internal_unsafe: false })
-            .unwrap();
-        if let TokenExpander::DeclarativeMacro { mac, def_site_token_map } = &*macro_def {
-            let tt = match &macro_ {
-                ast::Macro::MacroRules(mac) => mac.token_tree().unwrap(),
-                ast::Macro::MacroDef(_) => unimplemented!(""),
-            };
+        let DeclarativeMacroExpander { mac, def_site_token_map } =
+            &*db.decl_macro_expander(krate, ast_id);
+        assert_eq!(mac.err(), None);
+        let tt = match &macro_ {
+            ast::Macro::MacroRules(mac) => mac.token_tree().unwrap(),
+            ast::Macro::MacroDef(_) => unimplemented!(""),
+        };
 
-            let tt_start = tt.syntax().text_range().start();
-            tt.syntax().descendants_with_tokens().filter_map(SyntaxElement::into_token).for_each(
-                |token| {
-                    let range = token.text_range().checked_sub(tt_start).unwrap();
-                    if let Some(id) = def_site_token_map.token_by_range(range) {
-                        let offset = (range.end() + tt_start).into();
-                        text_edits.push((offset..offset, format!("#{}", id.0)));
-                    }
-                },
-            );
-            text_edits.push((
-                call_offset..call_offset,
-                format!("// call ids will be shifted by {:?}\n", mac.shift()),
-            ));
-        }
+        let tt_start = tt.syntax().text_range().start();
+        tt.syntax().descendants_with_tokens().filter_map(SyntaxElement::into_token).for_each(
+            |token| {
+                let range = token.text_range().checked_sub(tt_start).unwrap();
+                if let Some(id) = def_site_token_map.token_by_range(range) {
+                    let offset = (range.end() + tt_start).into();
+                    text_edits.push((offset..offset, format!("#{}", id.0)));
+                }
+            },
+        );
+        text_edits.push((
+            call_offset..call_offset,
+            format!("// call ids will be shifted by {:?}\n", mac.shift()),
+        ));
     }
 
     for macro_call in source_file.syntax().descendants().filter_map(ast::MacroCall::cast) {
@@ -190,7 +187,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
         let range: Range<usize> = range.into();
 
         if show_token_ids {
-            if let Some((tree, map, _)) = arg.as_deref() {
+            if let Some((tree, map, _)) = arg.value.as_deref() {
                 let tt_range = call.token_tree().unwrap().syntax().text_range();
                 let mut ranges = Vec::new();
                 extract_id_ranges(&mut ranges, map, tree);
@@ -239,7 +236,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
 
     for impl_id in def_map[local_id].scope.impls() {
         let src = impl_id.lookup(&db).source(&db);
-        if src.file_id.is_builtin_derive(&db).is_some() {
+        if src.file_id.is_builtin_derive(&db) {
             let pp = pretty_print_macro_expansion(src.value.syntax().clone(), None);
             format_to!(expanded_text, "\n{}", pp)
         }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
index 0ab1bd8490c..86818ce26dd 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
@@ -60,7 +60,7 @@ mod tests;
 use std::{cmp::Ord, ops::Deref};
 
 use base_db::{CrateId, Edition, FileId, ProcMacroKind};
-use hir_expand::{name::Name, InFile, MacroCallId, MacroDefId};
+use hir_expand::{name::Name, HirFileId, InFile, MacroCallId, MacroDefId};
 use itertools::Itertools;
 use la_arena::Arena;
 use profile::Count;
@@ -196,6 +196,10 @@ impl BlockRelativeModuleId {
     fn into_module(self, krate: CrateId) -> ModuleId {
         ModuleId { krate, block: self.block, local_id: self.local_id }
     }
+
+    fn is_block_module(self) -> bool {
+        self.block.is_some() && self.local_id == DefMap::ROOT
+    }
 }
 
 impl std::ops::Index<LocalModuleId> for DefMap {
@@ -278,7 +282,9 @@ pub struct ModuleData {
     pub origin: ModuleOrigin,
     /// Declared visibility of this module.
     pub visibility: Visibility,
-    /// Always [`None`] for block modules
+    /// Parent module in the same `DefMap`.
+    ///
+    /// [`None`] for block modules because they are always its `DefMap`'s root.
     pub parent: Option<LocalModuleId>,
     pub children: FxHashMap<Name, LocalModuleId>,
     pub scope: ItemScope,
@@ -626,6 +632,17 @@ impl ModuleData {
         self.origin.definition_source(db)
     }
 
+    /// Same as [`definition_source`] but only returns the file id to prevent parsing the ASt.
+    pub fn definition_source_file_id(&self) -> HirFileId {
+        match self.origin {
+            ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition } => {
+                definition.into()
+            }
+            ModuleOrigin::Inline { definition, .. } => definition.file_id,
+            ModuleOrigin::BlockExpr { block } => block.file_id,
+        }
+    }
+
     /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
     /// `None` for the crate root or block.
     pub fn declaration_source(&self, db: &dyn DefDatabase) -> Option<InFile<ast::Module>> {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
index 62fb3c7882c..c048716d740 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
@@ -52,10 +52,10 @@ use crate::{
     tt,
     visibility::{RawVisibility, Visibility},
     AdtId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, EnumVariantId,
-    ExternBlockLoc, FunctionId, FunctionLoc, ImplLoc, Intern, ItemContainerId, LocalModuleId,
-    Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, ModuleDefId,
-    ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc, StructLoc, TraitAliasLoc, TraitLoc,
-    TypeAliasLoc, UnionLoc, UnresolvedMacro,
+    ExternBlockLoc, ExternCrateLoc, FunctionId, FunctionLoc, ImplLoc, ImportLoc, Intern,
+    ItemContainerId, LocalModuleId, Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId,
+    MacroRulesLoc, ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc, StructLoc,
+    TraitAliasLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro,
 };
 
 static GLOB_RECURSION_LIMIT: Limit = Limit::new(100);
@@ -156,10 +156,9 @@ struct Import {
     alias: Option<ImportAlias>,
     visibility: RawVisibility,
     kind: ImportKind,
+    source: ImportSource,
     is_prelude: bool,
-    is_extern_crate: bool,
     is_macro_use: bool,
-    source: ImportSource,
 }
 
 impl Import {
@@ -168,26 +167,23 @@ impl Import {
         krate: CrateId,
         tree: &ItemTree,
         id: ItemTreeId<item_tree::Import>,
-    ) -> Vec<Self> {
+        mut cb: impl FnMut(Self),
+    ) {
         let it = &tree[id.value];
         let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into());
         let visibility = &tree[it.visibility];
         let is_prelude = attrs.by_key("prelude_import").exists();
-
-        let mut res = Vec::new();
         it.use_tree.expand(|idx, path, kind, alias| {
-            res.push(Self {
+            cb(Self {
                 path,
                 alias,
                 visibility: visibility.clone(),
                 kind,
                 is_prelude,
-                is_extern_crate: false,
                 is_macro_use: false,
                 source: ImportSource::Import { id, use_tree: idx },
             });
         });
-        res
     }
 
     fn from_extern_crate(
@@ -205,7 +201,6 @@ impl Import {
             visibility: visibility.clone(),
             kind: ImportKind::Plain,
             is_prelude: false,
-            is_extern_crate: true,
             is_macro_use: attrs.by_key("macro_use").exists(),
             source: ImportSource::ExternCrate(id),
         }
@@ -776,7 +771,7 @@ impl DefCollector<'_> {
         let _p = profile::span("resolve_import")
             .detail(|| format!("{}", import.path.display(self.db.upcast())));
         tracing::debug!("resolving import: {:?} ({:?})", import, self.def_map.data.edition);
-        if import.is_extern_crate {
+        if matches!(import.source, ImportSource::ExternCrate { .. }) {
             let name = import
                 .path
                 .as_ident()
@@ -813,11 +808,8 @@ impl DefCollector<'_> {
                 }
             }
 
-            // Check whether all namespace is resolved
-            if def.take_types().is_some()
-                && def.take_values().is_some()
-                && def.take_macros().is_some()
-            {
+            // Check whether all namespaces are resolved.
+            if def.is_full() {
                 PartialResolvedImport::Resolved(def)
             } else {
                 PartialResolvedImport::Indeterminate(def)
@@ -826,7 +818,7 @@ impl DefCollector<'_> {
     }
 
     fn resolve_extern_crate(&self, name: &Name) -> Option<CrateRootModuleId> {
-        if *name == name!(self) {
+        if *name == name![self] {
             cov_mark::hit!(extern_crate_self_as);
             Some(self.def_map.crate_root())
         } else {
@@ -867,7 +859,7 @@ impl DefCollector<'_> {
                 tracing::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
 
                 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
-                if import.is_extern_crate
+                if matches!(import.source, ImportSource::ExternCrate { .. })
                     && self.def_map.block.is_none()
                     && module_id == DefMap::ROOT
                 {
@@ -1585,21 +1577,34 @@ impl ModCollector<'_, '_> {
             match item {
                 ModItem::Mod(m) => self.collect_module(m, &attrs),
                 ModItem::Import(import_id) => {
-                    let imports = Import::from_use(
+                    let _import_id = ImportLoc {
+                        container: module,
+                        id: ItemTreeId::new(self.tree_id, import_id),
+                    }
+                    .intern(db);
+                    Import::from_use(
                         db,
                         krate,
                         self.item_tree,
                         ItemTreeId::new(self.tree_id, import_id),
-                    );
-                    self.def_collector.unresolved_imports.extend(imports.into_iter().map(
-                        |import| ImportDirective {
-                            module_id: self.module_id,
-                            import,
-                            status: PartialResolvedImport::Unresolved,
+                        |import| {
+                            self.def_collector.unresolved_imports.push(ImportDirective {
+                                module_id: self.module_id,
+                                import,
+                                status: PartialResolvedImport::Unresolved,
+                            });
                         },
-                    ));
+                    )
                 }
                 ModItem::ExternCrate(import_id) => {
+                    let extern_crate_id = ExternCrateLoc {
+                        container: module,
+                        id: ItemTreeId::new(self.tree_id, import_id),
+                    }
+                    .intern(db);
+                    self.def_collector.def_map.modules[self.module_id]
+                        .scope
+                        .define_extern_crate_decl(extern_crate_id);
                     self.def_collector.unresolved_imports.push(ImportDirective {
                         module_id: self.module_id,
                         import: Import::from_extern_crate(
@@ -2230,8 +2235,12 @@ impl ModCollector<'_, '_> {
     }
 
     fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) {
-        let Some((source, target)) = Self::borrow_modules(self.def_collector.def_map.modules.as_mut(), module_id, self.module_id) else {
-            return
+        let Some((source, target)) = Self::borrow_modules(
+            self.def_collector.def_map.modules.as_mut(),
+            module_id,
+            self.module_id,
+        ) else {
+            return;
         };
 
         for (name, macs) in source.scope.legacy_macros() {
@@ -2271,7 +2280,7 @@ impl ModCollector<'_, '_> {
     fn emit_unconfigured_diagnostic(&mut self, item: ModItem, cfg: &CfgExpr) {
         let ast_id = item.ast_id(self.item_tree);
 
-        let ast_id = InFile::new(self.file_id(), ast_id.upcast());
+        let ast_id = InFile::new(self.file_id(), ast_id.erase());
         self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code(
             self.module_id,
             ast_id,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
index 18b424255cd..e82e97b628e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
@@ -2,12 +2,9 @@
 
 use base_db::CrateId;
 use cfg::{CfgExpr, CfgOptions};
-use hir_expand::{attrs::AttrId, MacroCallKind};
+use hir_expand::{attrs::AttrId, ErasedAstId, MacroCallKind};
 use la_arena::Idx;
-use syntax::{
-    ast::{self, AnyHasAttrs},
-    SyntaxError,
-};
+use syntax::{ast, SyntaxError};
 
 use crate::{
     item_tree::{self, ItemTreeId},
@@ -24,7 +21,7 @@ pub enum DefDiagnosticKind {
 
     UnresolvedImport { id: ItemTreeId<item_tree::Import>, index: Idx<ast::UseTree> },
 
-    UnconfiguredCode { ast: AstId<AnyHasAttrs>, cfg: CfgExpr, opts: CfgOptions },
+    UnconfiguredCode { ast: ErasedAstId, cfg: CfgExpr, opts: CfgOptions },
 
     UnresolvedProcMacro { ast: MacroCallKind, krate: CrateId },
 
@@ -81,7 +78,7 @@ impl DefDiagnostic {
 
     pub fn unconfigured_code(
         container: LocalModuleId,
-        ast: AstId<ast::AnyHasAttrs>,
+        ast: ErasedAstId,
         cfg: CfgExpr,
         opts: CfgOptions,
     ) -> Self {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
index 5f6163175a7..de22ea10146 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
@@ -12,11 +12,12 @@
 
 use base_db::Edition;
 use hir_expand::name::Name;
+use triomphe::Arc;
 
 use crate::{
     db::DefDatabase,
     item_scope::BUILTIN_SCOPE,
-    nameres::{sub_namespace_match, BuiltinShadowMode, DefMap, MacroSubNs},
+    nameres::{sub_namespace_match, BlockInfo, BuiltinShadowMode, DefMap, MacroSubNs},
     path::{ModPath, PathKind},
     per_ns::PerNs,
     visibility::{RawVisibility, Visibility},
@@ -159,13 +160,15 @@ impl DefMap {
                 (None, new) => new,
             };
 
-            match &current_map.block {
-                Some(block) => {
+            match current_map.block {
+                Some(block) if original_module == Self::ROOT => {
+                    // Block modules "inherit" names from its parent module.
                     original_module = block.parent.local_id;
                     arc = block.parent.def_map(db, current_map.krate);
-                    current_map = &*arc;
+                    current_map = &arc;
                 }
-                None => return result,
+                // Proper (non-block) modules, including those in block `DefMap`s, don't.
+                _ => return result,
             }
         }
     }
@@ -189,7 +192,7 @@ impl DefMap {
         ));
 
         let mut segments = path.segments().iter().enumerate();
-        let mut curr_per_ns: PerNs = match path.kind {
+        let mut curr_per_ns = match path.kind {
             PathKind::DollarCrate(krate) => {
                 if krate == self.krate {
                     cov_mark::hit!(macro_dollar_crate_self);
@@ -241,51 +244,54 @@ impl DefMap {
                 )
             }
             PathKind::Super(lvl) => {
-                let mut module = original_module;
-                for i in 0..lvl {
-                    match self.modules[module].parent {
-                        Some(it) => module = it,
-                        None => match &self.block {
-                            Some(block) => {
-                                // Look up remaining path in parent `DefMap`
-                                let new_path = ModPath::from_segments(
-                                    PathKind::Super(lvl - i),
-                                    path.segments().to_vec(),
-                                );
-                                tracing::debug!(
-                                    "`super` path: {} -> {} in parent map",
-                                    path.display(db.upcast()),
-                                    new_path.display(db.upcast())
-                                );
-                                return block
-                                    .parent
-                                    .def_map(db, self.krate)
-                                    .resolve_path_fp_with_macro(
-                                        db,
-                                        mode,
-                                        block.parent.local_id,
-                                        &new_path,
-                                        shadow,
-                                        expected_macro_subns,
-                                    );
-                            }
-                            None => {
-                                tracing::debug!("super path in root module");
-                                return ResolvePathResult::empty(ReachedFixedPoint::Yes);
-                            }
-                        },
-                    }
+                let mut local_id = original_module;
+                let mut ext;
+                let mut def_map = self;
+
+                // Adjust `local_id` to `self`, i.e. the nearest non-block module.
+                if def_map.module_id(local_id).is_block_module() {
+                    (ext, local_id) = adjust_to_nearest_non_block_module(db, def_map, local_id);
+                    def_map = &ext;
                 }
 
-                // Resolve `self` to the containing crate-rooted module if we're a block
-                self.with_ancestor_maps(db, module, &mut |def_map, module| {
-                    if def_map.block.is_some() {
-                        None // keep ascending
+                // Go up the module tree but skip block modules as `super` always refers to the
+                // nearest non-block module.
+                for _ in 0..lvl {
+                    // Loop invariant: at the beginning of each loop, `local_id` must refer to a
+                    // non-block module.
+                    if let Some(parent) = def_map.modules[local_id].parent {
+                        local_id = parent;
+                        if def_map.module_id(local_id).is_block_module() {
+                            (ext, local_id) =
+                                adjust_to_nearest_non_block_module(db, def_map, local_id);
+                            def_map = &ext;
+                        }
                     } else {
-                        Some(PerNs::types(def_map.module_id(module).into(), Visibility::Public))
+                        stdx::always!(def_map.block.is_none());
+                        tracing::debug!("super path in root module");
+                        return ResolvePathResult::empty(ReachedFixedPoint::Yes);
                     }
-                })
-                .expect("block DefMap not rooted in crate DefMap")
+                }
+
+                let module = def_map.module_id(local_id);
+                stdx::never!(module.is_block_module());
+
+                if self.block != def_map.block {
+                    // If we have a different `DefMap` from `self` (the orignal `DefMap` we started
+                    // with), resolve the remaining path segments in that `DefMap`.
+                    let path =
+                        ModPath::from_segments(PathKind::Super(0), path.segments().iter().cloned());
+                    return def_map.resolve_path_fp_with_macro(
+                        db,
+                        mode,
+                        local_id,
+                        &path,
+                        shadow,
+                        expected_macro_subns,
+                    );
+                }
+
+                PerNs::types(module.into(), Visibility::Public)
             }
             PathKind::Abs => {
                 // 2018-style absolute path -- only extern prelude
@@ -508,3 +514,27 @@ impl DefMap {
         }
     }
 }
+
+/// Given a block module, returns its nearest non-block module and the `DefMap` it blongs to.
+fn adjust_to_nearest_non_block_module(
+    db: &dyn DefDatabase,
+    def_map: &DefMap,
+    mut local_id: LocalModuleId,
+) -> (Arc<DefMap>, LocalModuleId) {
+    // INVARIANT: `local_id` in `def_map` must be a block module.
+    stdx::always!(def_map.module_id(local_id).is_block_module());
+
+    let mut ext;
+    // This needs to be a local variable due to our mighty lifetime.
+    let mut def_map = def_map;
+    loop {
+        let BlockInfo { parent, .. } = def_map.block.expect("block module without parent module");
+
+        ext = parent.def_map(db, def_map.krate);
+        def_map = &ext;
+        local_id = parent.local_id;
+        if !parent.is_block_module() {
+            return (ext, local_id);
+        }
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path.rs b/src/tools/rust-analyzer/crates/hir-def/src/path.rs
index ff4ae69546c..06530cc7ebd 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/path.rs
@@ -45,7 +45,7 @@ pub enum Path {
         /// Invariant: the same len as `self.mod_path.segments` or `None` if all segments are `None`.
         generic_args: Option<Box<[Option<Interned<GenericArgs>>]>>,
     },
-    /// A link to a lang item. It is used in desugaring of things like `x?`. We can show these
+    /// A link to a lang item. It is used in desugaring of things like `it?`. We can show these
     /// links via a normal path since they might be private and not accessible in the usage place.
     LangItem(LangItemTarget),
 }
@@ -135,10 +135,7 @@ impl Path {
 
     pub fn segments(&self) -> PathSegments<'_> {
         let Path::Normal { mod_path, generic_args, .. } = self else {
-            return PathSegments {
-                segments: &[],
-                generic_args: None,
-            };
+            return PathSegments { segments: &[], generic_args: None };
         };
         let s =
             PathSegments { segments: mod_path.segments(), generic_args: generic_args.as_deref() };
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
index 1cb17ff0d26..abd817893cc 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
@@ -74,8 +74,8 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx<'_>) -> Option<Path
                     // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
                     Some(trait_ref) => {
                         let Path::Normal { mod_path, generic_args: path_generic_args, .. } =
-                            Path::from_src(trait_ref.path()?, ctx)? else
-                        {
+                            Path::from_src(trait_ref.path()?, ctx)?
+                        else {
                             return None;
                         };
                         let num_segments = mod_path.segments().len();
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
index 0aead6f37f7..11d58a6ba09 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
@@ -12,8 +12,8 @@ use crate::{
 };
 
 pub(crate) fn print_path(db: &dyn ExpandDatabase, path: &Path, buf: &mut dyn Write) -> fmt::Result {
-    if let Path::LangItem(x) = path {
-        return write!(buf, "$lang_item::{x:?}");
+    if let Path::LangItem(it) = path {
+        return write!(buf, "$lang_item::{it:?}");
     }
     match path.type_anchor() {
         Some(anchor) => {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
index 0d6f55411c1..10f5702845e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -22,10 +22,10 @@ use crate::{
     per_ns::PerNs,
     visibility::{RawVisibility, Visibility},
     AdtId, AssocItemId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId,
-    EnumVariantId, ExternBlockId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId,
-    ItemContainerId, LifetimeParamId, LocalModuleId, Lookup, Macro2Id, MacroId, MacroRulesId,
-    ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId,
-    TypeOrConstParamId, TypeOwnerId, TypeParamId, VariantId,
+    EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, GenericDefId, GenericParamId,
+    HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalModuleId, Lookup, Macro2Id, MacroId,
+    MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, TraitAliasId, TraitId,
+    TypeAliasId, TypeOrConstParamId, TypeOwnerId, TypeParamId, VariantId,
 };
 
 #[derive(Debug, Clone)]
@@ -186,12 +186,12 @@ impl Resolver {
             Path::LangItem(l) => {
                 return Some((
                     match *l {
-                        LangItemTarget::Union(x) => TypeNs::AdtId(x.into()),
-                        LangItemTarget::TypeAlias(x) => TypeNs::TypeAliasId(x),
-                        LangItemTarget::Struct(x) => TypeNs::AdtId(x.into()),
-                        LangItemTarget::EnumVariant(x) => TypeNs::EnumVariantId(x),
-                        LangItemTarget::EnumId(x) => TypeNs::AdtId(x.into()),
-                        LangItemTarget::Trait(x) => TypeNs::TraitId(x),
+                        LangItemTarget::Union(it) => TypeNs::AdtId(it.into()),
+                        LangItemTarget::TypeAlias(it) => TypeNs::TypeAliasId(it),
+                        LangItemTarget::Struct(it) => TypeNs::AdtId(it.into()),
+                        LangItemTarget::EnumVariant(it) => TypeNs::EnumVariantId(it),
+                        LangItemTarget::EnumId(it) => TypeNs::AdtId(it.into()),
+                        LangItemTarget::Trait(it) => TypeNs::TraitId(it),
                         LangItemTarget::Function(_)
                         | LangItemTarget::ImplDef(_)
                         | LangItemTarget::Static(_) => return None,
@@ -273,10 +273,10 @@ impl Resolver {
             Path::Normal { mod_path, .. } => mod_path,
             Path::LangItem(l) => {
                 return Some(ResolveValueResult::ValueNs(match *l {
-                    LangItemTarget::Function(x) => ValueNs::FunctionId(x),
-                    LangItemTarget::Static(x) => ValueNs::StaticId(x),
-                    LangItemTarget::Struct(x) => ValueNs::StructId(x),
-                    LangItemTarget::EnumVariant(x) => ValueNs::EnumVariantId(x),
+                    LangItemTarget::Function(it) => ValueNs::FunctionId(it),
+                    LangItemTarget::Static(it) => ValueNs::StaticId(it),
+                    LangItemTarget::Struct(it) => ValueNs::StructId(it),
+                    LangItemTarget::EnumVariant(it) => ValueNs::EnumVariantId(it),
                     LangItemTarget::Union(_)
                     | LangItemTarget::ImplDef(_)
                     | LangItemTarget::TypeAlias(_)
@@ -425,14 +425,14 @@ impl Resolver {
     /// The shadowing is accounted for: in
     ///
     /// ```
-    /// let x = 92;
+    /// let it = 92;
     /// {
-    ///     let x = 92;
+    ///     let it = 92;
     ///     $0
     /// }
     /// ```
     ///
-    /// there will be only one entry for `x` in the result.
+    /// there will be only one entry for `it` in the result.
     ///
     /// The result is ordered *roughly* from the innermost scope to the
     /// outermost: when the name is introduced in two namespaces in two scopes,
@@ -1018,20 +1018,26 @@ impl HasResolver for ExternBlockId {
     }
 }
 
+impl HasResolver for ExternCrateId {
+    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+        self.lookup(db).container.resolver(db)
+    }
+}
+
 impl HasResolver for TypeOwnerId {
     fn resolver(self, db: &dyn DefDatabase) -> Resolver {
         match self {
-            TypeOwnerId::FunctionId(x) => x.resolver(db),
-            TypeOwnerId::StaticId(x) => x.resolver(db),
-            TypeOwnerId::ConstId(x) => x.resolver(db),
-            TypeOwnerId::InTypeConstId(x) => x.lookup(db).owner.resolver(db),
-            TypeOwnerId::AdtId(x) => x.resolver(db),
-            TypeOwnerId::TraitId(x) => x.resolver(db),
-            TypeOwnerId::TraitAliasId(x) => x.resolver(db),
-            TypeOwnerId::TypeAliasId(x) => x.resolver(db),
-            TypeOwnerId::ImplId(x) => x.resolver(db),
-            TypeOwnerId::EnumVariantId(x) => x.resolver(db),
-            TypeOwnerId::ModuleId(x) => x.resolver(db),
+            TypeOwnerId::FunctionId(it) => it.resolver(db),
+            TypeOwnerId::StaticId(it) => it.resolver(db),
+            TypeOwnerId::ConstId(it) => it.resolver(db),
+            TypeOwnerId::InTypeConstId(it) => it.lookup(db).owner.resolver(db),
+            TypeOwnerId::AdtId(it) => it.resolver(db),
+            TypeOwnerId::TraitId(it) => it.resolver(db),
+            TypeOwnerId::TraitAliasId(it) => it.resolver(db),
+            TypeOwnerId::TypeAliasId(it) => it.resolver(db),
+            TypeOwnerId::ImplId(it) => it.resolver(db),
+            TypeOwnerId::EnumVariantId(it) => it.resolver(db),
+            TypeOwnerId::ModuleId(it) => it.resolver(db),
         }
     }
 }