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 985c6387ba0b0..f483efa85179b 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 @@ -528,3 +528,65 @@ fn f() {$0 "#]], ) } + +#[test] +fn resolve_extern_prelude_in_block() { + check_at( + r#" +//- /main.rs crate:main deps:core +fn main() { + mod f { + use core::S; + $0 + } +} + +//- /core.rs crate:core +pub struct S; + "#, + expect![[r#" + block scope + f: t + + block scope::f + S: ti vi + + crate + main: v + "#]], + ) +} + +#[test] +fn shadow_extern_prelude_in_block() { + check_at( + r#" +//- /main.rs crate:main deps:core +fn main() { + mod core { pub struct S; } + { + fn inner() {} // forces a block def map + use core::S; // should resolve to the local one + $0 + } +} + +//- /core.rs crate:core +pub const S; + "#, + expect![[r#" + block scope + S: ti vi + inner: v + + block scope + core: t + + block scope::core + S: t v + + crate + main: v + "#]], + ) +} 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 262bc538b9415..587997c47361a 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 @@ -395,6 +395,8 @@ impl DefCollector<'_> { .cfg() .map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false)); if is_cfg_enabled { + self.inject_prelude(); + ModCollector { def_collector: self, macro_depth: 0, 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 ee29b89f3d3b5..d621f3a360a96 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 @@ -221,7 +221,7 @@ impl DefMap { None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), }; tracing::debug!("resolving {:?} in crate root (+ extern prelude)", segment); - self.resolve_name_in_crate_root_or_extern_prelude(db, segment) + self.resolve_name_in_crate_root_or_extern_prelude(db, original_module, segment) } PathKind::Plain => { let (_, segment) = match segments.next() { @@ -470,9 +470,9 @@ impl DefMap { }; let extern_prelude = || { - if self.block.is_some() { - // Don't resolve extern prelude in block `DefMap`s, defer it to the crate def map so - // that blocks can properly shadow them + if self.block.is_some() && module == DefMap::ROOT { + // Don't resolve extern prelude in pseudo-modules of blocks, because + // they might been shadowed by local names. return PerNs::none(); } self.data.extern_prelude.get(name).map_or(PerNs::none(), |&(it, extern_crate)| { @@ -505,6 +505,7 @@ impl DefMap { fn resolve_name_in_crate_root_or_extern_prelude( &self, db: &dyn DefDatabase, + module: LocalModuleId, name: &Name, ) -> PerNs { let from_crate_root = match self.block { @@ -515,8 +516,8 @@ impl DefMap { None => self[Self::ROOT].scope.get(name), }; let from_extern_prelude = || { - if self.block.is_some() { - // Don't resolve extern prelude in block `DefMap`s. + if self.block.is_some() && module == DefMap::ROOT { + // Don't resolve extern prelude in pseudo-module of a block. return PerNs::none(); } self.data.extern_prelude.get(name).copied().map_or(