Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #19461 from Hmikihiro/shadow_by_module
fix: shadow type by module
Lukas Wirth 2025-04-10
parent 062205f · parent 2bdb229 · commit f880acd
-rw-r--r--crates/hir-def/src/resolver.rs28
-rw-r--r--crates/hir-ty/src/infer.rs3
-rw-r--r--crates/hir-ty/src/lower/path.rs7
-rw-r--r--crates/hir/src/attrs.rs3
-rw-r--r--crates/hir/src/source_analyzer.rs2
-rw-r--r--crates/ide/src/goto_definition.rs144
6 files changed, 180 insertions, 7 deletions
diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs
index ae185759a5..7e941854a2 100644
--- a/crates/hir-def/src/resolver.rs
+++ b/crates/hir-def/src/resolver.rs
@@ -105,9 +105,8 @@ pub enum TypeNs {
BuiltinType(BuiltinType),
TraitId(TraitId),
TraitAliasId(TraitAliasId),
- // Module belong to type ns, but the resolver is used when all module paths
- // are fully resolved.
- // ModuleId(ModuleId)
+
+ ModuleId(ModuleId),
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -249,6 +248,24 @@ impl Resolver {
}
Scope::BlockScope(m) => {
if let Some(res) = m.resolve_path_in_type_ns(db, path) {
+ let res = match res.0 {
+ TypeNs::ModuleId(_) if res.1.is_none() => {
+ if let Some(ModuleDefId::BuiltinType(builtin)) = BUILTIN_SCOPE
+ .get(first_name)
+ .and_then(|builtin| builtin.take_types())
+ {
+ (
+ TypeNs::BuiltinType(builtin),
+ remaining_idx(),
+ None,
+ ResolvePathResultPrefixInfo::default(),
+ )
+ } else {
+ res
+ }
+ }
+ _ => res,
+ };
return Some(res);
}
}
@@ -1193,11 +1210,12 @@ fn to_type_ns(per_ns: PerNs) -> Option<(TypeNs, Option<ImportOrExternCrate>)> {
ModuleDefId::TraitId(it) => TypeNs::TraitId(it),
ModuleDefId::TraitAliasId(it) => TypeNs::TraitAliasId(it),
+ ModuleDefId::ModuleId(it) => TypeNs::ModuleId(it),
+
ModuleDefId::FunctionId(_)
| ModuleDefId::ConstId(_)
| ModuleDefId::MacroId(_)
- | ModuleDefId::StaticId(_)
- | ModuleDefId::ModuleId(_) => return None,
+ | ModuleDefId::StaticId(_) => return None,
};
Some((res, def.import))
}
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index eba54b3a51..950c8cadd4 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -1666,7 +1666,8 @@ impl<'a> InferenceContext<'a> {
TypeNs::AdtId(AdtId::EnumId(_))
| TypeNs::BuiltinType(_)
| TypeNs::TraitId(_)
- | TypeNs::TraitAliasId(_) => {
+ | TypeNs::TraitAliasId(_)
+ | TypeNs::ModuleId(_) => {
// FIXME diagnostic
(self.err_ty(), None)
}
diff --git a/crates/hir-ty/src/lower/path.rs b/crates/hir-ty/src/lower/path.rs
index 86a97e923e..bc2d9d9080 100644
--- a/crates/hir-ty/src/lower/path.rs
+++ b/crates/hir-ty/src/lower/path.rs
@@ -279,7 +279,9 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
TypeNs::BuiltinType(it) => self.lower_path_inner(it.into(), infer_args),
TypeNs::TypeAliasId(it) => self.lower_path_inner(it.into(), infer_args),
// FIXME: report error
- TypeNs::EnumVariantId(_) => return (TyKind::Error.intern(Interner), None),
+ TypeNs::EnumVariantId(_) | TypeNs::ModuleId(_) => {
+ return (TyKind::Error.intern(Interner), None);
+ }
};
self.skip_resolved_segment();
@@ -310,6 +312,9 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
TypeNs::BuiltinType(_) => {
prohibit_generics_on_resolved(GenericArgsProhibitedReason::PrimitiveTy)
}
+ TypeNs::ModuleId(_) => {
+ prohibit_generics_on_resolved(GenericArgsProhibitedReason::Module)
+ }
TypeNs::AdtId(_)
| TypeNs::EnumVariantId(_)
| TypeNs::TypeAliasId(_)
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs
index 3c449f6e32..b1c478d1bf 100644
--- a/crates/hir/src/attrs.rs
+++ b/crates/hir/src/attrs.rs
@@ -210,6 +210,9 @@ fn resolve_assoc_or_field(
// XXX: Do these get resolved?
return None;
}
+ TypeNs::ModuleId(_) => {
+ return None;
+ }
};
// Resolve inherent items first, then trait items, then fields.
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 7a5c52d734..6a39f9cab8 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -1527,6 +1527,7 @@ fn resolve_hir_path_(
TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()),
TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
TypeNs::TraitAliasId(it) => PathResolution::Def(TraitAlias::from(it).into()),
+ TypeNs::ModuleId(it) => PathResolution::Def(ModuleDef::Module(it.into())),
};
match unresolved {
Some(unresolved) => resolver
@@ -1654,6 +1655,7 @@ fn resolve_hir_path_qualifier(
TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()),
TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
TypeNs::TraitAliasId(it) => PathResolution::Def(TraitAlias::from(it).into()),
+ TypeNs::ModuleId(it) => PathResolution::Def(ModuleDef::Module(it.into())),
};
match unresolved {
Some(unresolved) => resolver
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index 23ec729e57..a7c8a92f0e 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -3333,4 +3333,148 @@ fn main() {
"#,
);
}
+
+ #[test]
+ fn struct_shadow_by_module() {
+ check(
+ r#"
+mod foo {
+ pub mod bar {
+ // ^^^
+ pub type baz = usize;
+ }
+}
+struct bar;
+fn main() {
+ use foo::bar;
+ let x: ba$0r::baz = 5;
+
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn type_alias_shadow_by_module() {
+ check(
+ r#"
+mod foo {
+ pub mod bar {
+ // ^^^
+ pub fn baz() {}
+ }
+}
+
+trait Qux {}
+
+fn item<bar: Qux>() {
+ use foo::bar;
+ ba$0r::baz();
+}
+}
+"#,
+ );
+
+ check(
+ r#"
+mod foo {
+ pub mod bar {
+ // ^^^
+ pub fn baz() {}
+ }
+}
+
+fn item<bar>(x: bar) {
+ use foo::bar;
+ let x: bar$0 = x;
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn trait_shadow_by_module() {
+ check(
+ r#"
+pub mod foo {
+ pub mod Bar {}
+ // ^^^
+}
+
+trait Bar {}
+
+fn main() {
+ use foo::Bar;
+ fn f<Qux: B$0ar>() {}
+}
+ "#,
+ );
+ }
+
+ #[test]
+ fn const_shadow_by_module() {
+ check(
+ r#"
+pub mod foo {
+ pub struct u8 {}
+ pub mod bar {
+ pub mod u8 {}
+ }
+}
+
+fn main() {
+ use foo::u8;
+ {
+ use foo::bar::u8;
+
+ fn f1<const N: u$08>() {}
+ }
+ fn f2<const N: u8>() {}
+}
+"#,
+ );
+
+ check(
+ r#"
+pub mod foo {
+ pub struct u8 {}
+ // ^^
+ pub mod bar {
+ pub mod u8 {}
+ }
+}
+
+fn main() {
+ use foo::u8;
+ {
+ use foo::bar::u8;
+
+ fn f1<const N: u8>() {}
+ }
+ fn f2<const N: u$08>() {}
+}
+"#,
+ );
+
+ check(
+ r#"
+pub mod foo {
+ pub struct buz {}
+ pub mod bar {
+ pub mod buz {}
+ // ^^^
+ }
+}
+
+fn main() {
+ use foo::buz;
+ {
+ use foo::bar::buz;
+
+ fn f1<const N: buz$0>() {}
+ }
+}
+"#,
+ );
+ }
}