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
This commit is contained in:
commit
64d4181a3c
3 changed files with 81 additions and 29 deletions
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
|
|
|
@ -600,6 +600,25 @@ pub mod __private {
|
|||
//- /bar.rs crate:bar deps:foo edition:2018
|
||||
fn bar() {
|
||||
_ = 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
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue