Skip to content

Commit 40ba51c

Browse files
authored
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
2 parents 46e2d6e + 044c831 commit 40ba51c

File tree

3 files changed

+81
-29
lines changed

3 files changed

+81
-29
lines changed

crates/hir-def/src/resolver.rs

+39-19
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,17 @@ impl Resolver {
166166
db: &dyn DefDatabase,
167167
path: &Path,
168168
) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>)> {
169+
self.resolve_path_in_type_ns_with_prefix_info(db, path).map(
170+
|(resolution, remaining_segments, import, _)| (resolution, remaining_segments, import),
171+
)
172+
}
173+
174+
pub fn resolve_path_in_type_ns_with_prefix_info(
175+
&self,
176+
db: &dyn DefDatabase,
177+
path: &Path,
178+
) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>, ResolvePathResultPrefixInfo)>
179+
{
169180
let path = match path {
170181
Path::BarePath(mod_path) => mod_path,
171182
Path::Normal(it) => it.mod_path(),
@@ -181,7 +192,12 @@ impl Resolver {
181192
| LangItemTarget::ImplDef(_)
182193
| LangItemTarget::Static(_) => return None,
183194
};
184-
return Some((type_ns, seg.as_ref().map(|_| 1), None));
195+
return Some((
196+
type_ns,
197+
seg.as_ref().map(|_| 1),
198+
None,
199+
ResolvePathResultPrefixInfo::default(),
200+
));
185201
}
186202
};
187203
let first_name = path.segments().first()?;
@@ -197,17 +213,32 @@ impl Resolver {
197213
Scope::ExprScope(_) | Scope::MacroDefScope(_) => continue,
198214
Scope::GenericParams { params, def } => {
199215
if let Some(id) = params.find_type_by_name(first_name, *def) {
200-
return Some((TypeNs::GenericParam(id), remaining_idx(), None));
216+
return Some((
217+
TypeNs::GenericParam(id),
218+
remaining_idx(),
219+
None,
220+
ResolvePathResultPrefixInfo::default(),
221+
));
201222
}
202223
}
203224
&Scope::ImplDefScope(impl_) => {
204225
if *first_name == sym::Self_.clone() {
205-
return Some((TypeNs::SelfType(impl_), remaining_idx(), None));
226+
return Some((
227+
TypeNs::SelfType(impl_),
228+
remaining_idx(),
229+
None,
230+
ResolvePathResultPrefixInfo::default(),
231+
));
206232
}
207233
}
208234
&Scope::AdtScope(adt) => {
209235
if *first_name == sym::Self_.clone() {
210-
return Some((TypeNs::AdtSelfType(adt), remaining_idx(), None));
236+
return Some((
237+
TypeNs::AdtSelfType(adt),
238+
remaining_idx(),
239+
None,
240+
ResolvePathResultPrefixInfo::default(),
241+
));
211242
}
212243
}
213244
Scope::BlockScope(m) => {
@@ -220,18 +251,6 @@ impl Resolver {
220251
self.module_scope.resolve_path_in_type_ns(db, path)
221252
}
222253

223-
pub fn resolve_path_in_type_ns_fully_with_imports(
224-
&self,
225-
db: &dyn DefDatabase,
226-
path: &Path,
227-
) -> Option<(TypeNs, Option<ImportOrExternCrate>)> {
228-
let (res, unresolved, imp) = self.resolve_path_in_type_ns(db, path)?;
229-
if unresolved.is_some() {
230-
return None;
231-
}
232-
Some((res, imp))
233-
}
234-
235254
pub fn resolve_path_in_type_ns_fully(
236255
&self,
237256
db: &dyn DefDatabase,
@@ -986,11 +1005,12 @@ impl ModuleItemMap {
9861005
&self,
9871006
db: &dyn DefDatabase,
9881007
path: &ModPath,
989-
) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>)> {
990-
let (module_def, idx, _) =
1008+
) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>, ResolvePathResultPrefixInfo)>
1009+
{
1010+
let (module_def, idx, prefix_info) =
9911011
self.def_map.resolve_path_locally(db, self.module_id, path, BuiltinShadowMode::Other);
9921012
let (res, import) = to_type_ns(module_def)?;
993-
Some((res, idx, import))
1013+
Some((res, idx, import, prefix_info))
9941014
}
9951015
}
9961016

crates/hir-ty/src/lower.rs

+23-10
Original file line numberDiff line numberDiff line change
@@ -761,8 +761,8 @@ impl<'a> TyLoweringContext<'a> {
761761
path: &Path,
762762
on_diagnostic: &mut dyn FnMut(&mut Self, PathLoweringDiagnostic),
763763
) -> Option<(TypeNs, Option<usize>)> {
764-
let (resolution, remaining_index, _) =
765-
self.resolver.resolve_path_in_type_ns(self.db.upcast(), path)?;
764+
let (resolution, remaining_index, _, prefix_info) =
765+
self.resolver.resolve_path_in_type_ns_with_prefix_info(self.db.upcast(), path)?;
766766
let segments = path.segments();
767767

768768
match path {
@@ -771,13 +771,12 @@ impl<'a> TyLoweringContext<'a> {
771771
_ => return Some((resolution, remaining_index)),
772772
};
773773

774-
let (module_segments, resolved_segment_idx, resolved_segment) = match remaining_index {
775-
None => (
776-
segments.strip_last(),
777-
segments.len() - 1,
778-
segments.last().expect("resolved path has at least one element"),
779-
),
780-
Some(i) => (segments.take(i - 1), i - 1, segments.get(i - 1).unwrap()),
774+
let (module_segments, resolved_segment_idx, enum_segment) = match remaining_index {
775+
None if prefix_info.enum_variant => {
776+
(segments.strip_last_two(), segments.len() - 1, Some(segments.len() - 2))
777+
}
778+
None => (segments.strip_last(), segments.len() - 1, None),
779+
Some(i) => (segments.take(i - 1), i - 1, None),
781780
};
782781

783782
for (i, mod_segment) in module_segments.iter().enumerate() {
@@ -792,9 +791,23 @@ impl<'a> TyLoweringContext<'a> {
792791
}
793792
}
794793

794+
if let Some(enum_segment) = enum_segment {
795+
if segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some())
796+
&& segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some())
797+
{
798+
on_diagnostic(
799+
self,
800+
PathLoweringDiagnostic::GenericArgsProhibited {
801+
segment: (enum_segment + 1) as u32,
802+
reason: GenericArgsProhibitedReason::EnumVariant,
803+
},
804+
);
805+
}
806+
}
807+
795808
self.handle_type_ns_resolution(
796809
&resolution,
797-
resolved_segment,
810+
segments.get(resolved_segment_idx).expect("should have resolved segment"),
798811
resolved_segment_idx,
799812
on_diagnostic,
800813
);

crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs

+19
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,25 @@ pub mod __private {
600600
//- /bar.rs crate:bar deps:foo edition:2018
601601
fn bar() {
602602
_ = foo::__private::Result::<(), ()>::Ok;
603+
}
604+
"#,
605+
);
606+
}
607+
608+
#[test]
609+
fn enum_variant_type_ns() {
610+
check_diagnostics(
611+
r#"
612+
enum KvnDeserializerErr<I> {
613+
UnexpectedKeyword { found: I, expected: I },
614+
}
615+
616+
fn foo() {
617+
let _x: KvnDeserializerErr<()> =
618+
KvnDeserializerErr::<()>::UnexpectedKeyword { found: (), expected: () };
619+
let _x: KvnDeserializerErr<()> =
620+
KvnDeserializerErr::<()>::UnexpectedKeyword::<()> { found: (), expected: () };
621+
// ^^^^^^ 💡 error: you can specify generic arguments on either the enum or the variant, but not both
603622
}
604623
"#,
605624
);

0 commit comments

Comments
 (0)