1
Fork 0

Fix a bug where enum variants were not considered properly in type ns resolution

They should be considered just as well as in value ns, for example for struct literals.
This commit is contained in:
Chayim Refael Friedman 2025-01-19 06:31:23 +02:00
parent 61af2cc09a
commit 31e8419de6
3 changed files with 81 additions and 29 deletions

View file

@ -166,6 +166,17 @@ impl Resolver {
db: &dyn DefDatabase, db: &dyn DefDatabase,
path: &Path, path: &Path,
) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>)> { ) -> 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 { let path = match path {
Path::BarePath(mod_path) => mod_path, Path::BarePath(mod_path) => mod_path,
Path::Normal(it) => it.mod_path(), Path::Normal(it) => it.mod_path(),
@ -181,7 +192,12 @@ impl Resolver {
| LangItemTarget::ImplDef(_) | LangItemTarget::ImplDef(_)
| LangItemTarget::Static(_) => return None, | 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()?; let first_name = path.segments().first()?;
@ -197,17 +213,32 @@ impl Resolver {
Scope::ExprScope(_) | Scope::MacroDefScope(_) => continue, Scope::ExprScope(_) | Scope::MacroDefScope(_) => continue,
Scope::GenericParams { params, def } => { Scope::GenericParams { params, def } => {
if let Some(id) = params.find_type_by_name(first_name, *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_) => { &Scope::ImplDefScope(impl_) => {
if *first_name == sym::Self_.clone() { 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) => { &Scope::AdtScope(adt) => {
if *first_name == sym::Self_.clone() { 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) => { Scope::BlockScope(m) => {
@ -220,18 +251,6 @@ impl Resolver {
self.module_scope.resolve_path_in_type_ns(db, path) 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( pub fn resolve_path_in_type_ns_fully(
&self, &self,
db: &dyn DefDatabase, db: &dyn DefDatabase,
@ -986,11 +1005,12 @@ impl ModuleItemMap {
&self, &self,
db: &dyn DefDatabase, db: &dyn DefDatabase,
path: &ModPath, path: &ModPath,
) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>)> { ) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>, ResolvePathResultPrefixInfo)>
let (module_def, idx, _) = {
let (module_def, idx, prefix_info) =
self.def_map.resolve_path_locally(db, self.module_id, path, BuiltinShadowMode::Other); self.def_map.resolve_path_locally(db, self.module_id, path, BuiltinShadowMode::Other);
let (res, import) = to_type_ns(module_def)?; let (res, import) = to_type_ns(module_def)?;
Some((res, idx, import)) Some((res, idx, import, prefix_info))
} }
} }

View file

@ -761,8 +761,8 @@ impl<'a> TyLoweringContext<'a> {
path: &Path, path: &Path,
on_diagnostic: &mut dyn FnMut(&mut Self, PathLoweringDiagnostic), on_diagnostic: &mut dyn FnMut(&mut Self, PathLoweringDiagnostic),
) -> Option<(TypeNs, Option<usize>)> { ) -> Option<(TypeNs, Option<usize>)> {
let (resolution, remaining_index, _) = let (resolution, remaining_index, _, prefix_info) =
self.resolver.resolve_path_in_type_ns(self.db.upcast(), path)?; self.resolver.resolve_path_in_type_ns_with_prefix_info(self.db.upcast(), path)?;
let segments = path.segments(); let segments = path.segments();
match path { match path {
@ -771,13 +771,12 @@ impl<'a> TyLoweringContext<'a> {
_ => return Some((resolution, remaining_index)), _ => return Some((resolution, remaining_index)),
}; };
let (module_segments, resolved_segment_idx, resolved_segment) = match remaining_index { let (module_segments, resolved_segment_idx, enum_segment) = match remaining_index {
None => ( None if prefix_info.enum_variant => {
segments.strip_last(), (segments.strip_last_two(), segments.len() - 1, Some(segments.len() - 2))
segments.len() - 1, }
segments.last().expect("resolved path has at least one element"), None => (segments.strip_last(), segments.len() - 1, None),
), Some(i) => (segments.take(i - 1), i - 1, None),
Some(i) => (segments.take(i - 1), i - 1, segments.get(i - 1).unwrap()),
}; };
for (i, mod_segment) in module_segments.iter().enumerate() { 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( self.handle_type_ns_resolution(
&resolution, &resolution,
resolved_segment, segments.get(resolved_segment_idx).expect("should have resolved segment"),
resolved_segment_idx, resolved_segment_idx,
on_diagnostic, on_diagnostic,
); );

View file

@ -600,6 +600,25 @@ pub mod __private {
//- /bar.rs crate:bar deps:foo edition:2018 //- /bar.rs crate:bar deps:foo edition:2018
fn bar() { fn bar() {
_ = foo::__private::Result::<(), ()>::Ok; _ = foo::__private::Result::<(), ()>::Ok;
}
"#,
);
}
#[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
} }
"#, "#,
); );