Repository: rust-analyzer/rust-analyzer
Pull request #8447 (2021-04-09 13:25:28)

Resolve prelude and crate root names in the root DefMap
Should fix https://github.com/rust-analyzer/rust-analyzer/issues/8418

bors r+


Patch:
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index d13d7be278..fb4ddff5ee 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -478,7 +478,7 @@ impl DefCollector<'_> {
             self.def_map.edition,
         );
 
-        let res = self.def_map.resolve_name_in_extern_prelude(&extern_crate.name);
+        let res = self.def_map.resolve_name_in_extern_prelude(self.db, &extern_crate.name);
 
         if let Some(ModuleDefId::ModuleId(m)) = res.take_types() {
             cov_mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use);
@@ -534,6 +534,7 @@ impl DefCollector<'_> {
         log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
         if import.is_extern_crate {
             let res = self.def_map.resolve_name_in_extern_prelude(
+                self.db,
                 &import
                     .path
                     .as_ident()
diff --git a/crates/hir_def/src/nameres/path_resolution.rs b/crates/hir_def/src/nameres/path_resolution.rs
index a9cf651d2a..ccc9f22eb5 100644
--- a/crates/hir_def/src/nameres/path_resolution.rs
+++ b/crates/hir_def/src/nameres/path_resolution.rs
@@ -60,12 +60,26 @@ impl ResolvePathResult {
 }
 
 impl DefMap {
-    pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs {
+    pub(super) fn resolve_name_in_extern_prelude(
+        &self,
+        db: &dyn DefDatabase,
+        name: &Name,
+    ) -> PerNs {
         if name == &name!(self) {
             cov_mark::hit!(extern_crate_self_as);
             return PerNs::types(self.module_id(self.root).into(), Visibility::Public);
         }
-        self.extern_prelude
+
+        let arc;
+        let root = match self.block {
+            Some(_) => {
+                arc = self.crate_root(db).def_map(db);
+                &*arc
+            }
+            None => self,
+        };
+
+        root.extern_prelude
             .get(name)
             .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public))
     }
@@ -191,7 +205,7 @@ impl DefMap {
                     None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
                 };
                 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
-                self.resolve_name_in_crate_root_or_extern_prelude(&segment)
+                self.resolve_name_in_crate_root_or_extern_prelude(db, &segment)
             }
             PathKind::Plain => {
                 let (_, segment) = match segments.next() {
@@ -394,9 +408,21 @@ impl DefMap {
         from_legacy_macro.or(from_scope_or_builtin).or(from_extern_prelude).or(from_prelude)
     }
 
-    fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs {
-        let from_crate_root = self[self.root].scope.get(name);
-        let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
+    fn resolve_name_in_crate_root_or_extern_prelude(
+        &self,
+        db: &dyn DefDatabase,
+        name: &Name,
+    ) -> PerNs {
+        let arc;
+        let crate_def_map = match self.block {
+            Some(_) => {
+                arc = self.crate_root(db).def_map(db);
+                &arc
+            }
+            None => self,
+        };
+        let from_crate_root = crate_def_map[crate_def_map.root].scope.get(name);
+        let from_extern_prelude = self.resolve_name_in_extern_prelude(db, name);
 
         from_crate_root.or(from_extern_prelude)
     }


Test patch:
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index 65b71fdfad..1c1aa491d6 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -3413,3 +3413,33 @@ fn foo() {
         "#]],
     );
 }
+
+#[test]
+fn renamed_extern_crate_in_block() {
+    check_types(
+        r#"
+//- /lib.rs crate:lib deps:serde
+use serde::Deserialize;
+
+struct Foo {}
+
+const _ : () = {
+    extern crate serde as _serde;
+    impl _serde::Deserialize for Foo {
+        fn deserialize() -> u8 { 0 }
+    }
+};
+
+fn foo() {
+    Foo::deserialize();
+  //^^^^^^^^^^^^^^^^^^ u8
+}
+
+//- /serde.rs crate:serde
+
+pub trait Deserialize {
+    fn deserialize() -> u8;
+}
+    "#,
+    );
+}