about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/resolver.rs58
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs33
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs19
3 files changed, 81 insertions, 29 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
index df48ce67373..0b9b6da8d51 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/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/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
index 24f67fd6602..432b8f4d94e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/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/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs
index 2b59c1a22f6..7d62daf716c 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs
+++ b/src/tools/rust-analyzer/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
+}
+        "#,
+        );
+    }
 }