Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #18976 from ChayimFriedman2/non-module-generic-args
fix: Fix a bug where enum variants were not considered properly in type ns resolution
Lukas Wirth 2025-01-20
parent 46e2d6e · parent 044c831 · commit 40ba51c
-rw-r--r--crates/hir-def/src/resolver.rs58
-rw-r--r--crates/hir-ty/src/lower.rs33
-rw-r--r--crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs19
3 files changed, 81 insertions, 29 deletions
diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs
index df48ce6737..0b9b6da8d5 100644
--- a/crates/hir-def/src/resolver.rs
+++ b/crates/hir-def/src/resolver.rs
@@ -166,6 +166,17 @@ impl Resolver {
db: &dyn DefDatabase,
path: &Path,
) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>)> {
+ self.resolve_path_in_type_ns_with_prefix_info(db, path).map(
+ |(resolution, remaining_segments, import, _)| (resolution, remaining_segments, import),
+ )
+ }
+
+ pub fn resolve_path_in_type_ns_with_prefix_info(
+ &self,
+ db: &dyn DefDatabase,
+ path: &Path,
+ ) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>, ResolvePathResultPrefixInfo)>
+ {
let path = match path {
Path::BarePath(mod_path) => mod_path,
Path::Normal(it) => it.mod_path(),
@@ -181,7 +192,12 @@ impl Resolver {
| LangItemTarget::ImplDef(_)
| LangItemTarget::Static(_) => return None,
};
- return Some((type_ns, seg.as_ref().map(|_| 1), None));
+ return Some((
+ type_ns,
+ seg.as_ref().map(|_| 1),
+ None,
+ ResolvePathResultPrefixInfo::default(),
+ ));
}
};
let first_name = path.segments().first()?;
@@ -197,17 +213,32 @@ impl Resolver {
Scope::ExprScope(_) | Scope::MacroDefScope(_) => continue,
Scope::GenericParams { params, def } => {
if let Some(id) = params.find_type_by_name(first_name, *def) {
- return Some((TypeNs::GenericParam(id), remaining_idx(), None));
+ return Some((
+ TypeNs::GenericParam(id),
+ remaining_idx(),
+ None,
+ ResolvePathResultPrefixInfo::default(),
+ ));
}
}
&Scope::ImplDefScope(impl_) => {
if *first_name == sym::Self_.clone() {
- return Some((TypeNs::SelfType(impl_), remaining_idx(), None));
+ return Some((
+ TypeNs::SelfType(impl_),
+ remaining_idx(),
+ None,
+ ResolvePathResultPrefixInfo::default(),
+ ));
}
}
&Scope::AdtScope(adt) => {
if *first_name == sym::Self_.clone() {
- return Some((TypeNs::AdtSelfType(adt), remaining_idx(), None));
+ return Some((
+ TypeNs::AdtSelfType(adt),
+ remaining_idx(),
+ None,
+ ResolvePathResultPrefixInfo::default(),
+ ));
}
}
Scope::BlockScope(m) => {
@@ -220,18 +251,6 @@ impl Resolver {
self.module_scope.resolve_path_in_type_ns(db, path)
}
- pub fn resolve_path_in_type_ns_fully_with_imports(
- &self,
- db: &dyn DefDatabase,
- path: &Path,
- ) -> Option<(TypeNs, Option<ImportOrExternCrate>)> {
- let (res, unresolved, imp) = self.resolve_path_in_type_ns(db, path)?;
- if unresolved.is_some() {
- return None;
- }
- Some((res, imp))
- }
-
pub fn resolve_path_in_type_ns_fully(
&self,
db: &dyn DefDatabase,
@@ -986,11 +1005,12 @@ impl ModuleItemMap {
&self,
db: &dyn DefDatabase,
path: &ModPath,
- ) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>)> {
- let (module_def, idx, _) =
+ ) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>, ResolvePathResultPrefixInfo)>
+ {
+ let (module_def, idx, prefix_info) =
self.def_map.resolve_path_locally(db, self.module_id, path, BuiltinShadowMode::Other);
let (res, import) = to_type_ns(module_def)?;
- Some((res, idx, import))
+ Some((res, idx, import, prefix_info))
}
}
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 24f67fd660..432b8f4d94 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -761,8 +761,8 @@ impl<'a> TyLoweringContext<'a> {
path: &Path,
on_diagnostic: &mut dyn FnMut(&mut Self, PathLoweringDiagnostic),
) -> Option<(TypeNs, Option<usize>)> {
- let (resolution, remaining_index, _) =
- self.resolver.resolve_path_in_type_ns(self.db.upcast(), path)?;
+ let (resolution, remaining_index, _, prefix_info) =
+ self.resolver.resolve_path_in_type_ns_with_prefix_info(self.db.upcast(), path)?;
let segments = path.segments();
match path {
@@ -771,13 +771,12 @@ impl<'a> TyLoweringContext<'a> {
_ => return Some((resolution, remaining_index)),
};
- let (module_segments, resolved_segment_idx, resolved_segment) = match remaining_index {
- None => (
- segments.strip_last(),
- segments.len() - 1,
- segments.last().expect("resolved path has at least one element"),
- ),
- Some(i) => (segments.take(i - 1), i - 1, segments.get(i - 1).unwrap()),
+ let (module_segments, resolved_segment_idx, enum_segment) = match remaining_index {
+ None if prefix_info.enum_variant => {
+ (segments.strip_last_two(), segments.len() - 1, Some(segments.len() - 2))
+ }
+ None => (segments.strip_last(), segments.len() - 1, None),
+ Some(i) => (segments.take(i - 1), i - 1, None),
};
for (i, mod_segment) in module_segments.iter().enumerate() {
@@ -792,9 +791,23 @@ impl<'a> TyLoweringContext<'a> {
}
}
+ if let Some(enum_segment) = enum_segment {
+ if segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some())
+ && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some())
+ {
+ on_diagnostic(
+ self,
+ PathLoweringDiagnostic::GenericArgsProhibited {
+ segment: (enum_segment + 1) as u32,
+ reason: GenericArgsProhibitedReason::EnumVariant,
+ },
+ );
+ }
+ }
+
self.handle_type_ns_resolution(
&resolution,
- resolved_segment,
+ segments.get(resolved_segment_idx).expect("should have resolved segment"),
resolved_segment_idx,
on_diagnostic,
);
diff --git a/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs b/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs
index 2b59c1a22f..7d62daf716 100644
--- a/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs
+++ b/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs
@@ -604,4 +604,23 @@ fn bar() {
"#,
);
}
+
+ #[test]
+ fn enum_variant_type_ns() {
+ check_diagnostics(
+ r#"
+enum KvnDeserializerErr<I> {
+ UnexpectedKeyword { found: I, expected: I },
+}
+
+fn foo() {
+ let _x: KvnDeserializerErr<()> =
+ KvnDeserializerErr::<()>::UnexpectedKeyword { found: (), expected: () };
+ let _x: KvnDeserializerErr<()> =
+ KvnDeserializerErr::<()>::UnexpectedKeyword::<()> { found: (), expected: () };
+ // ^^^^^^ 💡 error: you can specify generic arguments on either the enum or the variant, but not both
+}
+ "#,
+ );
+ }
}