about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs79
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/path.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/resolver.rs103
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs127
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs128
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs54
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs355
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower/diagnostics.rs11
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/diagnostics.rs52
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs140
14 files changed, 848 insertions, 247 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
index 9bd7d38f0a6..39d383f0159 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
@@ -85,6 +85,8 @@ use crate::{
     FxIndexMap, LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId, ProcMacroId, UseId,
 };
 
+pub use self::path_resolution::ResolvePathResultPrefixInfo;
+
 const PREDEFINED_TOOLS: &[SmolStr] = &[
     SmolStr::new_static("clippy"),
     SmolStr::new_static("rustfmt"),
@@ -615,13 +617,15 @@ impl DefMap {
         (res.resolved_def, res.segment_index)
     }
 
+    /// The first `Option<usize>` points at the `Enum` segment in case of `Enum::Variant`, the second
+    /// points at the unresolved segments.
     pub(crate) fn resolve_path_locally(
         &self,
         db: &dyn DefDatabase,
         original_module: LocalModuleId,
         path: &ModPath,
         shadow: BuiltinShadowMode,
-    ) -> (PerNs, Option<usize>) {
+    ) -> (PerNs, Option<usize>, ResolvePathResultPrefixInfo) {
         let res = self.resolve_path_fp_with_macro_single(
             db,
             ResolveMode::Other,
@@ -630,7 +634,7 @@ impl DefMap {
             shadow,
             None, // Currently this function isn't used for macro resolution.
         );
-        (res.resolved_def, res.segment_index)
+        (res.resolved_def, res.segment_index, res.prefix_info)
     }
 
     /// Ascends the `DefMap` hierarchy and calls `f` with every `DefMap` and containing module.
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
index f391cc41c18..318a8d5aa1f 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
@@ -38,7 +38,7 @@ use crate::{
         attr_resolution::{attr_macro_as_call_id, derive_macro_as_call_id},
         diagnostics::DefDiagnostic,
         mod_resolution::ModDir,
-        path_resolution::ReachedFixedPoint,
+        path_resolution::{ReachedFixedPoint, ResolvePathResultPrefixInfo},
         proc_macro::{parse_macro_name_and_helper_attrs, ProcMacroDef, ProcMacroKind},
         sub_namespace_match, BuiltinShadowMode, DefMap, MacroSubNs, ModuleData, ModuleOrigin,
         ResolveMode,
@@ -797,7 +797,7 @@ impl DefCollector<'_> {
             return PartialResolvedImport::Unresolved;
         }
 
-        if res.from_differing_crate {
+        if let ResolvePathResultPrefixInfo::DifferingCrate = res.prefix_info {
             return PartialResolvedImport::Resolved(
                 def.filter_visibility(|v| matches!(v, Visibility::Public)),
             );
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
index 8eb195680d1..9573697a871 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
@@ -43,21 +43,34 @@ pub(super) struct ResolvePathResult {
     pub(super) resolved_def: PerNs,
     pub(super) segment_index: Option<usize>,
     pub(super) reached_fixedpoint: ReachedFixedPoint,
-    pub(super) from_differing_crate: bool,
+    pub(super) prefix_info: ResolvePathResultPrefixInfo,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum ResolvePathResultPrefixInfo {
+    None,
+    DifferingCrate,
+    /// Path of the form `Enum::Variant` (and not `Variant` alone).
+    Enum,
 }
 
 impl ResolvePathResult {
     fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
-        ResolvePathResult::new(PerNs::none(), reached_fixedpoint, None, false)
+        ResolvePathResult::new(
+            PerNs::none(),
+            reached_fixedpoint,
+            None,
+            ResolvePathResultPrefixInfo::None,
+        )
     }
 
     fn new(
         resolved_def: PerNs,
         reached_fixedpoint: ReachedFixedPoint,
         segment_index: Option<usize>,
-        from_differing_crate: bool,
+        prefix_info: ResolvePathResultPrefixInfo,
     ) -> ResolvePathResult {
-        ResolvePathResult { resolved_def, segment_index, reached_fixedpoint, from_differing_crate }
+        ResolvePathResult { resolved_def, segment_index, reached_fixedpoint, prefix_info }
     }
 }
 
@@ -157,7 +170,17 @@ impl DefMap {
             if result.reached_fixedpoint == ReachedFixedPoint::No {
                 result.reached_fixedpoint = new.reached_fixedpoint;
             }
-            result.from_differing_crate |= new.from_differing_crate;
+            result.prefix_info = match (result.prefix_info, new.prefix_info) {
+                (ResolvePathResultPrefixInfo::None, it) => it,
+                (ResolvePathResultPrefixInfo::DifferingCrate, _) => {
+                    ResolvePathResultPrefixInfo::DifferingCrate
+                }
+                (
+                    ResolvePathResultPrefixInfo::Enum,
+                    ResolvePathResultPrefixInfo::DifferingCrate,
+                ) => ResolvePathResultPrefixInfo::DifferingCrate,
+                (ResolvePathResultPrefixInfo::Enum, _) => ResolvePathResultPrefixInfo::Enum,
+            };
             result.segment_index = match (result.segment_index, new.segment_index) {
                 (Some(idx), None) => Some(idx),
                 (Some(old), Some(new)) => Some(old.max(new)),
@@ -403,14 +426,14 @@ impl DefMap {
 
     fn resolve_remaining_segments<'a>(
         &self,
-        segments: impl Iterator<Item = (usize, &'a Name)>,
+        mut segments: impl Iterator<Item = (usize, &'a Name)>,
         mut curr_per_ns: PerNs,
         path: &ModPath,
         db: &dyn DefDatabase,
         shadow: BuiltinShadowMode,
         original_module: LocalModuleId,
     ) -> ResolvePathResult {
-        for (i, segment) in segments {
+        while let Some((i, segment)) = segments.next() {
             let curr = match curr_per_ns.take_types_full() {
                 Some(r) => r,
                 None => {
@@ -443,7 +466,7 @@ impl DefMap {
                             def,
                             ReachedFixedPoint::Yes,
                             s.map(|s| s + i),
-                            true,
+                            ResolvePathResultPrefixInfo::DifferingCrate,
                         );
                     }
 
@@ -488,17 +511,28 @@ impl DefMap {
                             ),
                         })
                     });
-                    match res {
-                        Some(res) => res,
-                        None => {
-                            return ResolvePathResult::new(
-                                PerNs::types(e.into(), curr.vis, curr.import),
-                                ReachedFixedPoint::Yes,
-                                Some(i),
-                                false,
-                            )
+                    // FIXME: Need to filter visibility here and below? Not sure.
+                    return match res {
+                        Some(res) => {
+                            if segments.next().is_some() {
+                                // Enum variants are in value namespace, segments left => no resolution.
+                                ResolvePathResult::empty(ReachedFixedPoint::No)
+                            } else {
+                                ResolvePathResult::new(
+                                    res,
+                                    ReachedFixedPoint::Yes,
+                                    None,
+                                    ResolvePathResultPrefixInfo::Enum,
+                                )
+                            }
                         }
-                    }
+                        None => ResolvePathResult::new(
+                            PerNs::types(e.into(), curr.vis, curr.import),
+                            ReachedFixedPoint::Yes,
+                            Some(i),
+                            ResolvePathResultPrefixInfo::None,
+                        ),
+                    };
                 }
                 s => {
                     // could be an inherent method call in UFCS form
@@ -513,7 +547,7 @@ impl DefMap {
                         PerNs::types(s, curr.vis, curr.import),
                         ReachedFixedPoint::Yes,
                         Some(i),
-                        false,
+                        ResolvePathResultPrefixInfo::None,
                     );
                 }
             };
@@ -522,7 +556,12 @@ impl DefMap {
                 .filter_visibility(|vis| vis.is_visible_from_def_map(db, self, original_module));
         }
 
-        ResolvePathResult::new(curr_per_ns, ReachedFixedPoint::Yes, None, false)
+        ResolvePathResult::new(
+            curr_per_ns,
+            ReachedFixedPoint::Yes,
+            None,
+            ResolvePathResultPrefixInfo::None,
+        )
     }
 
     fn resolve_name_in_module(
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path.rs b/src/tools/rust-analyzer/crates/hir-def/src/path.rs
index 44e132061ad..e59c37104dd 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/path.rs
@@ -240,6 +240,7 @@ pub struct PathSegment<'a> {
     pub args_and_bindings: Option<&'a GenericArgs>,
 }
 
+#[derive(Debug, Clone, Copy)]
 pub struct PathSegments<'a> {
     segments: &'a [Name],
     generic_args: Option<&'a [Option<GenericArgs>]>,
@@ -259,6 +260,7 @@ impl<'a> PathSegments<'a> {
     pub fn last(&self) -> Option<PathSegment<'a>> {
         self.get(self.len().checked_sub(1)?)
     }
+
     pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> {
         let res = PathSegment {
             name: self.segments.get(idx)?,
@@ -266,24 +268,37 @@ impl<'a> PathSegments<'a> {
         };
         Some(res)
     }
+
     pub fn skip(&self, len: usize) -> PathSegments<'a> {
         PathSegments {
             segments: self.segments.get(len..).unwrap_or(&[]),
             generic_args: self.generic_args.and_then(|it| it.get(len..)),
         }
     }
+
     pub fn take(&self, len: usize) -> PathSegments<'a> {
         PathSegments {
             segments: self.segments.get(..len).unwrap_or(self.segments),
             generic_args: self.generic_args.map(|it| it.get(..len).unwrap_or(it)),
         }
     }
+
     pub fn strip_last(&self) -> PathSegments<'a> {
         PathSegments {
             segments: self.segments.split_last().map_or(&[], |it| it.1),
             generic_args: self.generic_args.map(|it| it.split_last().map_or(&[][..], |it| it.1)),
         }
     }
+
+    pub fn strip_last_two(&self) -> PathSegments<'a> {
+        PathSegments {
+            segments: self.segments.get(..self.segments.len().saturating_sub(2)).unwrap_or(&[]),
+            generic_args: self
+                .generic_args
+                .map(|it| it.get(..it.len().saturating_sub(2)).unwrap_or(&[])),
+        }
+    }
+
     pub fn iter(&self) -> impl Iterator<Item = PathSegment<'a>> {
         self.segments
             .iter()
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 f4dfd42a30e..4f15c8091c9 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -21,7 +21,7 @@ use crate::{
     hir::{BindingId, ExprId, LabelId},
     item_scope::{BuiltinShadowMode, ImportId, ImportOrExternCrate, BUILTIN_SCOPE},
     lang_item::LangItemTarget,
-    nameres::{DefMap, MacroSubNs},
+    nameres::{DefMap, MacroSubNs, ResolvePathResultPrefixInfo},
     path::{ModPath, Path, PathKind},
     per_ns::PerNs,
     type_ref::{LifetimeRef, TypesMap},
@@ -263,25 +263,37 @@ impl Resolver {
         &self,
         db: &dyn DefDatabase,
         path: &Path,
-        mut hygiene_id: HygieneId,
+        hygiene_id: HygieneId,
     ) -> Option<ResolveValueResult> {
+        self.resolve_path_in_value_ns_with_prefix_info(db, path, hygiene_id).map(|(it, _)| it)
+    }
+
+    pub fn resolve_path_in_value_ns_with_prefix_info(
+        &self,
+        db: &dyn DefDatabase,
+        path: &Path,
+        mut hygiene_id: HygieneId,
+    ) -> Option<(ResolveValueResult, ResolvePathResultPrefixInfo)> {
         let path = match path {
             Path::BarePath(mod_path) => mod_path,
             Path::Normal(it) => it.mod_path(),
             Path::LangItem(l, None) => {
-                return Some(ResolveValueResult::ValueNs(
-                    match *l {
-                        LangItemTarget::Function(it) => ValueNs::FunctionId(it),
-                        LangItemTarget::Static(it) => ValueNs::StaticId(it),
-                        LangItemTarget::Struct(it) => ValueNs::StructId(it),
-                        LangItemTarget::EnumVariant(it) => ValueNs::EnumVariantId(it),
-                        LangItemTarget::Union(_)
-                        | LangItemTarget::ImplDef(_)
-                        | LangItemTarget::TypeAlias(_)
-                        | LangItemTarget::Trait(_)
-                        | LangItemTarget::EnumId(_) => return None,
-                    },
-                    None,
+                return Some((
+                    ResolveValueResult::ValueNs(
+                        match *l {
+                            LangItemTarget::Function(it) => ValueNs::FunctionId(it),
+                            LangItemTarget::Static(it) => ValueNs::StaticId(it),
+                            LangItemTarget::Struct(it) => ValueNs::StructId(it),
+                            LangItemTarget::EnumVariant(it) => ValueNs::EnumVariantId(it),
+                            LangItemTarget::Union(_)
+                            | LangItemTarget::ImplDef(_)
+                            | LangItemTarget::TypeAlias(_)
+                            | LangItemTarget::Trait(_)
+                            | LangItemTarget::EnumId(_) => return None,
+                        },
+                        None,
+                    ),
+                    ResolvePathResultPrefixInfo::None,
                 ))
             }
             Path::LangItem(l, Some(_)) => {
@@ -296,7 +308,10 @@ impl Resolver {
                     | LangItemTarget::ImplDef(_)
                     | LangItemTarget::Static(_) => return None,
                 };
-                return Some(ResolveValueResult::Partial(type_ns, 1, None));
+                return Some((
+                    ResolveValueResult::Partial(type_ns, 1, None),
+                    ResolvePathResultPrefixInfo::None,
+                ));
             }
         };
         let n_segments = path.segments().len();
@@ -326,9 +341,12 @@ impl Resolver {
                             });
 
                         if let Some(e) = entry {
-                            return Some(ResolveValueResult::ValueNs(
-                                ValueNs::LocalBinding(e.binding()),
-                                None,
+                            return Some((
+                                ResolveValueResult::ValueNs(
+                                    ValueNs::LocalBinding(e.binding()),
+                                    None,
+                                ),
+                                ResolvePathResultPrefixInfo::None,
                             ));
                         }
                     }
@@ -350,14 +368,17 @@ impl Resolver {
                     Scope::GenericParams { params, def } => {
                         if let Some(id) = params.find_const_by_name(first_name, *def) {
                             let val = ValueNs::GenericParam(id);
-                            return Some(ResolveValueResult::ValueNs(val, None));
+                            return Some((
+                                ResolveValueResult::ValueNs(val, None),
+                                ResolvePathResultPrefixInfo::None,
+                            ));
                         }
                     }
                     &Scope::ImplDefScope(impl_) => {
                         if *first_name == sym::Self_.clone() {
-                            return Some(ResolveValueResult::ValueNs(
-                                ValueNs::ImplSelf(impl_),
-                                None,
+                            return Some((
+                                ResolveValueResult::ValueNs(ValueNs::ImplSelf(impl_), None),
+                                ResolvePathResultPrefixInfo::None,
                             ));
                         }
                     }
@@ -377,22 +398,27 @@ impl Resolver {
                     Scope::GenericParams { params, def } => {
                         if let Some(id) = params.find_type_by_name(first_name, *def) {
                             let ty = TypeNs::GenericParam(id);
-                            return Some(ResolveValueResult::Partial(ty, 1, None));
+                            return Some((
+                                ResolveValueResult::Partial(ty, 1, None),
+                                ResolvePathResultPrefixInfo::None,
+                            ));
                         }
                     }
                     &Scope::ImplDefScope(impl_) => {
                         if *first_name == sym::Self_.clone() {
-                            return Some(ResolveValueResult::Partial(
-                                TypeNs::SelfType(impl_),
-                                1,
-                                None,
+                            return Some((
+                                ResolveValueResult::Partial(TypeNs::SelfType(impl_), 1, None),
+                                ResolvePathResultPrefixInfo::None,
                             ));
                         }
                     }
                     Scope::AdtScope(adt) => {
                         if *first_name == sym::Self_.clone() {
                             let ty = TypeNs::AdtSelfType(*adt);
-                            return Some(ResolveValueResult::Partial(ty, 1, None));
+                            return Some((
+                                ResolveValueResult::Partial(ty, 1, None),
+                                ResolvePathResultPrefixInfo::None,
+                            ));
                         }
                     }
                     Scope::BlockScope(m) => {
@@ -413,7 +439,10 @@ impl Resolver {
         // `use core::u16;`.
         if path.kind == PathKind::Plain && n_segments > 1 {
             if let Some(builtin) = BuiltinType::by_name(first_name) {
-                return Some(ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1, None));
+                return Some((
+                    ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1, None),
+                    ResolvePathResultPrefixInfo::None,
+                ));
             }
         }
 
@@ -924,15 +953,15 @@ impl ModuleItemMap {
         &self,
         db: &dyn DefDatabase,
         path: &ModPath,
-    ) -> Option<ResolveValueResult> {
-        let (module_def, idx) =
+    ) -> Option<(ResolveValueResult, ResolvePathResultPrefixInfo)> {
+        let (module_def, unresolved_idx, prefix_info) =
             self.def_map.resolve_path_locally(db, self.module_id, path, BuiltinShadowMode::Other);
-        match idx {
+        match unresolved_idx {
             None => {
                 let (value, import) = to_value_ns(module_def)?;
-                Some(ResolveValueResult::ValueNs(value, import))
+                Some((ResolveValueResult::ValueNs(value, import), prefix_info))
             }
-            Some(idx) => {
+            Some(unresolved_idx) => {
                 let def = module_def.take_types_full()?;
                 let ty = match def.def {
                     ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
@@ -948,7 +977,7 @@ impl ModuleItemMap {
                     | ModuleDefId::MacroId(_)
                     | ModuleDefId::StaticId(_) => return None,
                 };
-                Some(ResolveValueResult::Partial(ty, idx, def.import))
+                Some((ResolveValueResult::Partial(ty, unresolved_idx, def.import), prefix_info))
             }
         }
     }
@@ -958,7 +987,7 @@ impl ModuleItemMap {
         db: &dyn DefDatabase,
         path: &ModPath,
     ) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>)> {
-        let (module_def, idx) =
+        let (module_def, idx, _) =
             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))
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
index 5720539d34e..25bb3a76de2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -16,6 +16,7 @@
 pub(crate) mod cast;
 pub(crate) mod closure;
 mod coerce;
+mod diagnostics;
 mod expr;
 mod mutability;
 mod pat;
@@ -57,15 +58,20 @@ use crate::{
     db::HirDatabase,
     fold_tys,
     generics::Generics,
-    infer::{coerce::CoerceMany, expr::ExprIsRead, unify::InferenceTable},
+    infer::{
+        coerce::CoerceMany,
+        diagnostics::{Diagnostics, InferenceTyLoweringContext as TyLoweringContext},
+        expr::ExprIsRead,
+        unify::InferenceTable,
+    },
     lower::{diagnostics::TyLoweringDiagnostic, ImplTraitLoweringMode},
     mir::MirSpan,
     to_assoc_type_id,
     traits::FnTrait,
     utils::{InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder},
     AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, Goal, ImplTraitId,
-    ImplTraitIdx, InEnvironment, Interner, Lifetime, OpaqueTyId, ParamLoweringMode, ProjectionTy,
-    Substitution, TraitEnvironment, Ty, TyBuilder, TyExt,
+    ImplTraitIdx, InEnvironment, Interner, Lifetime, OpaqueTyId, ParamLoweringMode,
+    PathLoweringDiagnostic, ProjectionTy, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt,
 };
 
 // This lint has a false positive here. See the link below for details.
@@ -276,6 +282,10 @@ pub enum InferenceDiagnostic {
         source: InferenceTyDiagnosticSource,
         diag: TyLoweringDiagnostic,
     },
+    PathDiagnostic {
+        node: ExprOrPatId,
+        diag: PathLoweringDiagnostic,
+    },
 }
 
 /// A mismatch between an expected and an inferred type.
@@ -442,6 +452,7 @@ pub struct InferenceResult {
     /// [`InferenceContext`] and store the tuples substitution there. This map is the reverse of
     /// that which allows us to resolve a [`TupleFieldId`]s type.
     pub tuple_field_access_types: FxHashMap<TupleId, Substitution>,
+    /// During inference this field is empty and [`InferenceContext::diagnostics`] is filled instead.
     pub diagnostics: Vec<InferenceDiagnostic>,
     pub type_of_expr: ArenaMap<ExprId, Ty>,
     /// For each pattern record the type it resolves to.
@@ -579,6 +590,8 @@ pub(crate) struct InferenceContext<'a> {
     pub(crate) db: &'a dyn HirDatabase,
     pub(crate) owner: DefWithBodyId,
     pub(crate) body: &'a Body,
+    /// Generally you should not resolve things via this resolver. Instead create a TyLoweringContext
+    /// and resolve the path via its methods. This will ensure proper error reporting.
     pub(crate) resolver: Resolver,
     generics: OnceCell<Option<Generics>>,
     table: unify::InferenceTable<'a>,
@@ -620,6 +633,8 @@ pub(crate) struct InferenceContext<'a> {
     /// comment on `InferenceContext::sort_closures`
     closure_dependencies: FxHashMap<ClosureId, Vec<ClosureId>>,
     deferred_closures: FxHashMap<ClosureId, Vec<(Ty, Ty, Vec<Ty>, ExprId)>>,
+
+    diagnostics: Diagnostics,
 }
 
 #[derive(Clone, Debug)]
@@ -701,6 +716,7 @@ impl<'a> InferenceContext<'a> {
             deferred_closures: FxHashMap::default(),
             closure_dependencies: FxHashMap::default(),
             inside_assignment: false,
+            diagnostics: Diagnostics::default(),
         }
     }
 
@@ -724,8 +740,10 @@ impl<'a> InferenceContext<'a> {
             mut result,
             mut deferred_cast_checks,
             tuple_field_accesses_rev,
+            diagnostics,
             ..
         } = self;
+        let mut diagnostics = diagnostics.finish();
         // Destructure every single field so whenever new fields are added to `InferenceResult` we
         // don't forget to handle them here.
         let InferenceResult {
@@ -733,7 +751,6 @@ impl<'a> InferenceContext<'a> {
             field_resolutions: _,
             variant_resolutions: _,
             assoc_resolutions,
-            diagnostics,
             type_of_expr,
             type_of_pat,
             type_of_binding,
@@ -752,6 +769,7 @@ impl<'a> InferenceContext<'a> {
             mutated_bindings_in_closure: _,
             tuple_field_access_types: _,
             coercion_casts,
+            diagnostics: _,
         } = &mut result;
         table.fallback_if_possible();
 
@@ -866,6 +884,9 @@ impl<'a> InferenceContext<'a> {
                     *has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown());
             })
             .collect();
+
+        result.diagnostics = diagnostics;
+
         result
     }
 
@@ -1238,41 +1259,28 @@ impl<'a> InferenceContext<'a> {
         self.result.type_of_binding.insert(id, ty);
     }
 
-    fn push_diagnostic(&mut self, diagnostic: InferenceDiagnostic) {
-        self.result.diagnostics.push(diagnostic);
-    }
-
-    fn push_ty_diagnostics(
-        &mut self,
-        source: InferenceTyDiagnosticSource,
-        diagnostics: Vec<TyLoweringDiagnostic>,
-    ) {
-        self.result.diagnostics.extend(
-            diagnostics.into_iter().map(|diag| InferenceDiagnostic::TyDiagnostic { source, diag }),
-        );
+    fn push_diagnostic(&self, diagnostic: InferenceDiagnostic) {
+        self.diagnostics.push(diagnostic);
     }
 
     fn with_ty_lowering<R>(
         &mut self,
         types_map: &TypesMap,
         types_source: InferenceTyDiagnosticSource,
-        f: impl FnOnce(&mut crate::lower::TyLoweringContext<'_>) -> R,
+        f: impl FnOnce(&mut TyLoweringContext<'_>) -> R,
     ) -> R {
-        let mut ctx = crate::lower::TyLoweringContext::new(
+        let mut ctx = TyLoweringContext::new(
             self.db,
             &self.resolver,
             types_map,
             self.owner.into(),
+            &self.diagnostics,
+            types_source,
         );
-        let result = f(&mut ctx);
-        self.push_ty_diagnostics(types_source, ctx.diagnostics);
-        result
+        f(&mut ctx)
     }
 
-    fn with_body_ty_lowering<R>(
-        &mut self,
-        f: impl FnOnce(&mut crate::lower::TyLoweringContext<'_>) -> R,
-    ) -> R {
+    fn with_body_ty_lowering<R>(&mut self, f: impl FnOnce(&mut TyLoweringContext<'_>) -> R) -> R {
         self.with_ty_lowering(&self.body.types, InferenceTyDiagnosticSource::Body, f)
     }
 
@@ -1451,51 +1459,55 @@ impl<'a> InferenceContext<'a> {
         }
     }
 
-    fn resolve_variant(&mut self, path: Option<&Path>, value_ns: bool) -> (Ty, Option<VariantId>) {
+    fn resolve_variant(
+        &mut self,
+        node: ExprOrPatId,
+        path: Option<&Path>,
+        value_ns: bool,
+    ) -> (Ty, Option<VariantId>) {
         let path = match path {
             Some(path) => path,
             None => return (self.err_ty(), None),
         };
-        let mut ctx = crate::lower::TyLoweringContext::new(
+        let mut ctx = TyLoweringContext::new(
             self.db,
             &self.resolver,
             &self.body.types,
             self.owner.into(),
+            &self.diagnostics,
+            InferenceTyDiagnosticSource::Body,
         );
         let (resolution, unresolved) = if value_ns {
-            match self.resolver.resolve_path_in_value_ns(self.db.upcast(), path, HygieneId::ROOT) {
-                Some(ResolveValueResult::ValueNs(value, _)) => match value {
+            let Some(res) = ctx.resolve_path_in_value_ns(path, node, HygieneId::ROOT) else {
+                return (self.err_ty(), None);
+            };
+            match res {
+                ResolveValueResult::ValueNs(value, _) => match value {
                     ValueNs::EnumVariantId(var) => {
                         let substs = ctx.substs_from_path(path, var.into(), true);
-                        self.push_ty_diagnostics(
-                            InferenceTyDiagnosticSource::Body,
-                            ctx.diagnostics,
-                        );
+                        drop(ctx);
                         let ty = self.db.ty(var.lookup(self.db.upcast()).parent.into());
                         let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
                         return (ty, Some(var.into()));
                     }
                     ValueNs::StructId(strukt) => {
                         let substs = ctx.substs_from_path(path, strukt.into(), true);
-                        self.push_ty_diagnostics(
-                            InferenceTyDiagnosticSource::Body,
-                            ctx.diagnostics,
-                        );
+                        drop(ctx);
                         let ty = self.db.ty(strukt.into());
                         let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
                         return (ty, Some(strukt.into()));
                     }
                     ValueNs::ImplSelf(impl_id) => (TypeNs::SelfType(impl_id), None),
-                    _ => return (self.err_ty(), None),
+                    _ => {
+                        drop(ctx);
+                        return (self.err_ty(), None);
+                    }
                 },
-                Some(ResolveValueResult::Partial(typens, unresolved, _)) => {
-                    (typens, Some(unresolved))
-                }
-                None => return (self.err_ty(), None),
+                ResolveValueResult::Partial(typens, unresolved, _) => (typens, Some(unresolved)),
             }
         } else {
-            match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path) {
-                Some((it, idx, _)) => (it, idx),
+            match ctx.resolve_path_in_type_ns(path, node) {
+                Some((it, idx)) => (it, idx),
                 None => return (self.err_ty(), None),
             }
         };
@@ -1506,21 +1518,21 @@ impl<'a> InferenceContext<'a> {
         return match resolution {
             TypeNs::AdtId(AdtId::StructId(strukt)) => {
                 let substs = ctx.substs_from_path(path, strukt.into(), true);
-                self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics);
+                drop(ctx);
                 let ty = self.db.ty(strukt.into());
                 let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
                 forbid_unresolved_segments((ty, Some(strukt.into())), unresolved)
             }
             TypeNs::AdtId(AdtId::UnionId(u)) => {
                 let substs = ctx.substs_from_path(path, u.into(), true);
-                self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics);
+                drop(ctx);
                 let ty = self.db.ty(u.into());
                 let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
                 forbid_unresolved_segments((ty, Some(u.into())), unresolved)
             }
             TypeNs::EnumVariantId(var) => {
                 let substs = ctx.substs_from_path(path, var.into(), true);
-                self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics);
+                drop(ctx);
                 let ty = self.db.ty(var.lookup(self.db.upcast()).parent.into());
                 let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
                 forbid_unresolved_segments((ty, Some(var.into())), unresolved)
@@ -1531,6 +1543,7 @@ impl<'a> InferenceContext<'a> {
                 let mut ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs);
 
                 let Some(mut remaining_idx) = unresolved else {
+                    drop(ctx);
                     return self.resolve_variant_on_alias(ty, None, mod_path);
                 };
 
@@ -1538,6 +1551,7 @@ impl<'a> InferenceContext<'a> {
 
                 // We need to try resolving unresolved segments one by one because each may resolve
                 // to a projection, which `TyLoweringContext` cannot handle on its own.
+                let mut tried_resolving_once = false;
                 while !remaining_segments.is_empty() {
                     let resolved_segment = path.segments().get(remaining_idx - 1).unwrap();
                     let current_segment = remaining_segments.take(1);
@@ -1558,18 +1572,27 @@ impl<'a> InferenceContext<'a> {
                         }
                     }
 
+                    if tried_resolving_once {
+                        // FIXME: with `inherent_associated_types` this is allowed, but our `lower_partly_resolved_path()`
+                        // will need to be updated to err at the correct segment.
+                        //
+                        // We need to stop here because otherwise the segment index passed to `lower_partly_resolved_path()`
+                        // will be incorrect, and that can mess up error reporting.
+                        break;
+                    }
+
                     // `lower_partly_resolved_path()` returns `None` as type namespace unless
                     // `remaining_segments` is empty, which is never the case here. We don't know
                     // which namespace the new `ty` is in until normalized anyway.
                     (ty, _) = ctx.lower_partly_resolved_path(
+                        node,
                         resolution,
                         resolved_segment,
                         current_segment,
+                        (remaining_idx - 1) as u32,
                         false,
-                        &mut |_, _reason| {
-                            // FIXME: Report an error.
-                        },
                     );
+                    tried_resolving_once = true;
 
                     ty = self.table.insert_type_vars(ty);
                     ty = self.table.normalize_associated_types_in(ty);
@@ -1582,7 +1605,7 @@ impl<'a> InferenceContext<'a> {
                     remaining_idx += 1;
                     remaining_segments = remaining_segments.skip(1);
                 }
-                self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics);
+                drop(ctx);
 
                 let variant = ty.as_adt().and_then(|(id, _)| match id {
                     AdtId::StructId(s) => Some(VariantId::StructId(s)),
@@ -1601,7 +1624,7 @@ impl<'a> InferenceContext<'a> {
                 };
                 let substs =
                     ctx.substs_from_path_segment(resolved_seg, Some(it.into()), true, None);
-                self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics);
+                drop(ctx);
                 let ty = self.db.ty(it.into());
                 let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs
new file mode 100644
index 00000000000..032dc37899d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs
@@ -0,0 +1,128 @@
+//! This file contains the [`Diagnostics`] type used during inference,
+//! and a wrapper around [`TyLoweringContext`] ([`InferenceTyLoweringContext`]) that replaces
+//! it and takes care of diagnostics in inference.
+
+use std::cell::RefCell;
+use std::ops::{Deref, DerefMut};
+
+use hir_def::body::HygieneId;
+use hir_def::hir::ExprOrPatId;
+use hir_def::path::{Path, PathSegment, PathSegments};
+use hir_def::resolver::{ResolveValueResult, Resolver, TypeNs};
+use hir_def::type_ref::TypesMap;
+use hir_def::TypeOwnerId;
+
+use crate::db::HirDatabase;
+use crate::{
+    InferenceDiagnostic, InferenceTyDiagnosticSource, Ty, TyLoweringContext, TyLoweringDiagnostic,
+};
+
+// Unfortunately, this struct needs to use interior mutability (but we encapsulate it)
+// because when lowering types and paths we hold a `TyLoweringContext` that holds a reference
+// to our resolver and so we cannot have mutable reference, but we really want to have
+// ability to dispatch diagnostics during this work otherwise the code becomes a complete mess.
+#[derive(Debug, Default, Clone)]
+pub(super) struct Diagnostics(RefCell<Vec<InferenceDiagnostic>>);
+
+impl Diagnostics {
+    pub(super) fn push(&self, diagnostic: InferenceDiagnostic) {
+        self.0.borrow_mut().push(diagnostic);
+    }
+
+    fn push_ty_diagnostics(
+        &self,
+        source: InferenceTyDiagnosticSource,
+        diagnostics: Vec<TyLoweringDiagnostic>,
+    ) {
+        self.0.borrow_mut().extend(
+            diagnostics.into_iter().map(|diag| InferenceDiagnostic::TyDiagnostic { source, diag }),
+        );
+    }
+
+    pub(super) fn finish(self) -> Vec<InferenceDiagnostic> {
+        self.0.into_inner()
+    }
+}
+
+pub(super) struct InferenceTyLoweringContext<'a> {
+    ctx: TyLoweringContext<'a>,
+    diagnostics: &'a Diagnostics,
+    source: InferenceTyDiagnosticSource,
+}
+
+impl<'a> InferenceTyLoweringContext<'a> {
+    pub(super) fn new(
+        db: &'a dyn HirDatabase,
+        resolver: &'a Resolver,
+        types_map: &'a TypesMap,
+        owner: TypeOwnerId,
+        diagnostics: &'a Diagnostics,
+        source: InferenceTyDiagnosticSource,
+    ) -> Self {
+        Self { ctx: TyLoweringContext::new(db, resolver, types_map, owner), diagnostics, source }
+    }
+
+    pub(super) fn resolve_path_in_type_ns(
+        &mut self,
+        path: &Path,
+        node: ExprOrPatId,
+    ) -> Option<(TypeNs, Option<usize>)> {
+        let diagnostics = self.diagnostics;
+        self.ctx.resolve_path_in_type_ns(path, &mut |_, diag| {
+            diagnostics.push(InferenceDiagnostic::PathDiagnostic { node, diag })
+        })
+    }
+
+    pub(super) fn resolve_path_in_value_ns(
+        &mut self,
+        path: &Path,
+        node: ExprOrPatId,
+        hygiene_id: HygieneId,
+    ) -> Option<ResolveValueResult> {
+        let diagnostics = self.diagnostics;
+        self.ctx.resolve_path_in_value_ns(path, hygiene_id, &mut |_, diag| {
+            diagnostics.push(InferenceDiagnostic::PathDiagnostic { node, diag })
+        })
+    }
+
+    pub(super) fn lower_partly_resolved_path(
+        &mut self,
+        node: ExprOrPatId,
+        resolution: TypeNs,
+        resolved_segment: PathSegment<'_>,
+        remaining_segments: PathSegments<'_>,
+        resolved_segment_idx: u32,
+        infer_args: bool,
+    ) -> (Ty, Option<TypeNs>) {
+        let diagnostics = self.diagnostics;
+        self.ctx.lower_partly_resolved_path(
+            resolution,
+            resolved_segment,
+            remaining_segments,
+            resolved_segment_idx,
+            infer_args,
+            &mut |_, diag| diagnostics.push(InferenceDiagnostic::PathDiagnostic { node, diag }),
+        )
+    }
+}
+
+impl<'a> Deref for InferenceTyLoweringContext<'a> {
+    type Target = TyLoweringContext<'a>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.ctx
+    }
+}
+
+impl DerefMut for InferenceTyLoweringContext<'_> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.ctx
+    }
+}
+
+impl Drop for InferenceTyLoweringContext<'_> {
+    fn drop(&mut self) {
+        self.diagnostics
+            .push_ty_diagnostics(self.source, std::mem::take(&mut self.ctx.diagnostics));
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
index a13541be695..3dccd536bef 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
@@ -531,7 +531,7 @@ impl InferenceContext<'_> {
                         (params, ret_ty)
                     }
                     None => {
-                        self.result.diagnostics.push(InferenceDiagnostic::ExpectedFunction {
+                        self.push_diagnostic(InferenceDiagnostic::ExpectedFunction {
                             call_expr: tgt_expr,
                             found: callee_ty.clone(),
                         });
@@ -707,7 +707,7 @@ impl InferenceContext<'_> {
                 self.result.standard_types.never.clone()
             }
             Expr::RecordLit { path, fields, spread, .. } => {
-                let (ty, def_id) = self.resolve_variant(path.as_deref(), false);
+                let (ty, def_id) = self.resolve_variant(tgt_expr.into(), path.as_deref(), false);
 
                 if let Some(t) = expected.only_has_type(&mut self.table) {
                     self.unify(&ty, &t);
@@ -1816,9 +1816,10 @@ impl InferenceContext<'_> {
                 if !is_public {
                     if let Either::Left(field) = field_id {
                         // FIXME: Merge this diagnostic into UnresolvedField?
-                        self.result
-                            .diagnostics
-                            .push(InferenceDiagnostic::PrivateField { expr: tgt_expr, field });
+                        self.push_diagnostic(InferenceDiagnostic::PrivateField {
+                            expr: tgt_expr,
+                            field,
+                        });
                     }
                 }
                 ty
@@ -1835,7 +1836,7 @@ impl InferenceContext<'_> {
                     VisibleFromModule::Filter(self.resolver.module()),
                     name,
                 );
-                self.result.diagnostics.push(InferenceDiagnostic::UnresolvedField {
+                self.push_diagnostic(InferenceDiagnostic::UnresolvedField {
                     expr: tgt_expr,
                     receiver: receiver_ty.clone(),
                     name: name.clone(),
@@ -1927,7 +1928,7 @@ impl InferenceContext<'_> {
                     },
                 );
 
-                self.result.diagnostics.push(InferenceDiagnostic::UnresolvedMethodCall {
+                self.push_diagnostic(InferenceDiagnostic::UnresolvedMethodCall {
                     expr: tgt_expr,
                     receiver: receiver_ty.clone(),
                     name: method_name.clone(),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
index 50e761196ec..00398f019da 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
@@ -35,7 +35,7 @@ impl InferenceContext<'_> {
         ellipsis: Option<u32>,
         subs: &[PatId],
     ) -> Ty {
-        let (ty, def) = self.resolve_variant(path, true);
+        let (ty, def) = self.resolve_variant(id.into(), path, true);
         let var_data = def.map(|it| it.variant_data(self.db.upcast()));
         if let Some(variant) = def {
             self.write_variant_resolution(id.into(), variant);
@@ -115,7 +115,7 @@ impl InferenceContext<'_> {
         id: PatId,
         subs: impl ExactSizeIterator<Item = (Name, PatId)>,
     ) -> Ty {
-        let (ty, def) = self.resolve_variant(path, false);
+        let (ty, def) = self.resolve_variant(id.into(), path, false);
         if let Some(variant) = def {
             self.write_variant_resolution(id.into(), variant);
         }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
index a6296c3af23..d79bf9a05e8 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
@@ -14,6 +14,7 @@ use crate::{
     builder::ParamKind,
     consteval, error_lifetime,
     generics::generics,
+    infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext,
     method_resolution::{self, VisibleFromModule},
     to_chalk_trait_id, InferenceDiagnostic, Interner, Substitution, TraitRef, TraitRefExt, Ty,
     TyBuilder, TyExt, TyKind, ValueTyDefId,
@@ -147,36 +148,38 @@ impl InferenceContext<'_> {
         path: &Path,
         id: ExprOrPatId,
     ) -> Option<(ValueNs, Option<chalk_ir::Substitution<Interner>>)> {
+        // Don't use `self.make_ty()` here as we need `orig_ns`.
+        let mut ctx = TyLoweringContext::new(
+            self.db,
+            &self.resolver,
+            &self.body.types,
+            self.owner.into(),
+            &self.diagnostics,
+            InferenceTyDiagnosticSource::Body,
+        );
         let (value, self_subst) = if let Some(type_ref) = path.type_anchor() {
             let last = path.segments().last()?;
 
-            // Don't use `self.make_ty()` here as we need `orig_ns`.
-            let mut ctx = crate::lower::TyLoweringContext::new(
-                self.db,
-                &self.resolver,
-                &self.body.types,
-                self.owner.into(),
-            );
             let (ty, orig_ns) = ctx.lower_ty_ext(type_ref);
             let ty = self.table.insert_type_vars(ty);
             let ty = self.table.normalize_associated_types_in(ty);
 
             let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1);
             let (ty, _) = ctx.lower_ty_relative_path(ty, orig_ns, remaining_segments_for_ty);
-            self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics);
+            drop(ctx);
             let ty = self.table.insert_type_vars(ty);
             let ty = self.table.normalize_associated_types_in(ty);
             self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))?
         } else {
             let hygiene = self.body.expr_or_pat_path_hygiene(id);
             // FIXME: report error, unresolved first path segment
-            let value_or_partial =
-                self.resolver.resolve_path_in_value_ns(self.db.upcast(), path, hygiene)?;
+            let value_or_partial = ctx.resolve_path_in_value_ns(path, id, hygiene)?;
+            drop(ctx);
 
             match value_or_partial {
                 ResolveValueResult::ValueNs(it, _) => (it, None),
                 ResolveValueResult::Partial(def, remaining_index, _) => self
-                    .resolve_assoc_item(def, path, remaining_index, id)
+                    .resolve_assoc_item(id, def, path, remaining_index, id)
                     .map(|(it, substs)| (it, Some(substs)))?,
             }
         };
@@ -212,6 +215,7 @@ impl InferenceContext<'_> {
 
     fn resolve_assoc_item(
         &mut self,
+        node: ExprOrPatId,
         def: TypeNs,
         path: &Path,
         remaining_index: usize,
@@ -260,17 +264,23 @@ impl InferenceContext<'_> {
                 // as Iterator>::Item::default`)
                 let remaining_segments_for_ty =
                     remaining_segments.take(remaining_segments.len() - 1);
-                let (ty, _) = self.with_body_ty_lowering(|ctx| {
-                    ctx.lower_partly_resolved_path(
-                        def,
-                        resolved_segment,
-                        remaining_segments_for_ty,
-                        true,
-                        &mut |_, _reason| {
-                            // FIXME: Report an error.
-                        },
-                    )
-                });
+                let mut ctx = TyLoweringContext::new(
+                    self.db,
+                    &self.resolver,
+                    &self.body.types,
+                    self.owner.into(),
+                    &self.diagnostics,
+                    InferenceTyDiagnosticSource::Body,
+                );
+                let (ty, _) = ctx.lower_partly_resolved_path(
+                    node,
+                    def,
+                    resolved_segment,
+                    remaining_segments_for_ty,
+                    (remaining_index - 1) as u32,
+                    true,
+                );
+                drop(ctx);
                 if ty.is_unknown() {
                     return None;
                 }
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 2610bb704e2..4bfa51c8490 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -23,6 +23,7 @@ use chalk_ir::{
 
 use either::Either;
 use hir_def::{
+    body::HygieneId,
     builtin_type::BuiltinType,
     data::adt::StructKind,
     expander::Expander,
@@ -31,9 +32,9 @@ use hir_def::{
         WherePredicateTypeTarget,
     },
     lang_item::LangItem,
-    nameres::MacroSubNs,
+    nameres::{MacroSubNs, ResolvePathResultPrefixInfo},
     path::{GenericArg, GenericArgs, ModPath, Path, PathKind, PathSegment, PathSegments},
-    resolver::{HasResolver, LifetimeNs, Resolver, TypeNs},
+    resolver::{HasResolver, LifetimeNs, ResolveValueResult, Resolver, TypeNs, ValueNs},
     type_ref::{
         ConstRef, LifetimeRef, PathId, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound,
         TypeRef, TypeRefId, TypesMap, TypesSourceMap,
@@ -514,8 +515,8 @@ impl<'a> TyLoweringContext<'a> {
     /// This is only for `generic_predicates_for_param`, where we can't just
     /// lower the self types of the predicates since that could lead to cycles.
     /// So we just check here if the `type_ref` resolves to a generic param, and which.
-    fn lower_ty_only_param(&self, type_ref: TypeRefId) -> Option<TypeOrConstParamId> {
-        let type_ref = &self.types_map[type_ref];
+    fn lower_ty_only_param(&mut self, type_ref_id: TypeRefId) -> Option<TypeOrConstParamId> {
+        let type_ref = &self.types_map[type_ref_id];
         let path = match type_ref {
             TypeRef::Path(path) => path,
             _ => return None,
@@ -526,8 +527,10 @@ impl<'a> TyLoweringContext<'a> {
         if path.segments().len() > 1 {
             return None;
         }
-        let resolution = match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path) {
-            Some((it, None, _)) => it,
+        let resolution = match self
+            .resolve_path_in_type_ns(path, &mut Self::on_path_diagnostic_callback(type_ref_id))
+        {
+            Some((it, None)) => it,
             _ => return None,
         };
         match resolution {
@@ -562,11 +565,9 @@ impl<'a> TyLoweringContext<'a> {
         resolution: TypeNs,
         resolved_segment: PathSegment<'_>,
         remaining_segments: PathSegments<'_>,
+        _resolved_segment_idx: u32,
         infer_args: bool,
-        on_prohibited_generics_for_resolved_segment: &mut dyn FnMut(
-            &mut Self,
-            GenericArgsProhibitedReason,
-        ),
+        _on_diagnostic: &mut dyn FnMut(&mut Self, PathLoweringDiagnostic),
     ) -> (Ty, Option<TypeNs>) {
         let ty = match resolution {
             TypeNs::TraitId(trait_) => {
@@ -633,44 +634,28 @@ impl<'a> TyLoweringContext<'a> {
                 // FIXME(trait_alias): Implement trait alias.
                 return (TyKind::Error.intern(Interner), None);
             }
-            TypeNs::GenericParam(param_id) => {
-                if resolved_segment.args_and_bindings.is_some() {
-                    on_prohibited_generics_for_resolved_segment(
-                        self,
-                        GenericArgsProhibitedReason::TyParam,
-                    );
+            TypeNs::GenericParam(param_id) => match self.type_param_mode {
+                ParamLoweringMode::Placeholder => {
+                    TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into()))
                 }
+                ParamLoweringMode::Variable => {
+                    let idx = match self
+                        .generics()
+                        .expect("generics in scope")
+                        .type_or_const_param_idx(param_id.into())
+                    {
+                        None => {
+                            never!("no matching generics");
+                            return (TyKind::Error.intern(Interner), None);
+                        }
+                        Some(idx) => idx,
+                    };
 
-                match self.type_param_mode {
-                    ParamLoweringMode::Placeholder => {
-                        TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into()))
-                    }
-                    ParamLoweringMode::Variable => {
-                        let idx = match self
-                            .generics()
-                            .expect("generics in scope")
-                            .type_or_const_param_idx(param_id.into())
-                        {
-                            None => {
-                                never!("no matching generics");
-                                return (TyKind::Error.intern(Interner), None);
-                            }
-                            Some(idx) => idx,
-                        };
-
-                        TyKind::BoundVar(BoundVar::new(self.in_binders, idx))
-                    }
+                    TyKind::BoundVar(BoundVar::new(self.in_binders, idx))
                 }
-                .intern(Interner)
             }
+            .intern(Interner),
             TypeNs::SelfType(impl_id) => {
-                if resolved_segment.args_and_bindings.is_some() {
-                    on_prohibited_generics_for_resolved_segment(
-                        self,
-                        GenericArgsProhibitedReason::SelfTy,
-                    );
-                }
-
                 let generics = self.generics().expect("impl should have generic param scope");
 
                 match self.type_param_mode {
@@ -696,13 +681,6 @@ impl<'a> TyLoweringContext<'a> {
                 }
             }
             TypeNs::AdtSelfType(adt) => {
-                if resolved_segment.args_and_bindings.is_some() {
-                    on_prohibited_generics_for_resolved_segment(
-                        self,
-                        GenericArgsProhibitedReason::SelfTy,
-                    );
-                }
-
                 let generics = generics(self.db.upcast(), adt.into());
                 let substs = match self.type_param_mode {
                     ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db),
@@ -715,12 +693,6 @@ impl<'a> TyLoweringContext<'a> {
 
             TypeNs::AdtId(it) => self.lower_path_inner(resolved_segment, it.into(), infer_args),
             TypeNs::BuiltinType(it) => {
-                if resolved_segment.args_and_bindings.is_some() {
-                    on_prohibited_generics_for_resolved_segment(
-                        self,
-                        GenericArgsProhibitedReason::PrimitiveTy,
-                    );
-                }
                 self.lower_path_inner(resolved_segment, it.into(), infer_args)
             }
             TypeNs::TypeAliasId(it) => {
@@ -732,6 +704,220 @@ impl<'a> TyLoweringContext<'a> {
         self.lower_ty_relative_path(ty, Some(resolution), remaining_segments)
     }
 
+    fn handle_type_ns_resolution(
+        &mut self,
+        resolution: &TypeNs,
+        resolved_segment: PathSegment<'_>,
+        resolved_segment_idx: usize,
+        on_diagnostic: &mut dyn FnMut(&mut Self, PathLoweringDiagnostic),
+    ) {
+        let mut prohibit_generics_on_resolved = |reason| {
+            if resolved_segment.args_and_bindings.is_some() {
+                on_diagnostic(
+                    self,
+                    PathLoweringDiagnostic::GenericArgsProhibited {
+                        segment: resolved_segment_idx as u32,
+                        reason,
+                    },
+                );
+            }
+        };
+
+        match resolution {
+            TypeNs::SelfType(_) => {
+                prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy)
+            }
+            TypeNs::GenericParam(_) => {
+                prohibit_generics_on_resolved(GenericArgsProhibitedReason::TyParam)
+            }
+            TypeNs::AdtSelfType(_) => {
+                prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy)
+            }
+            TypeNs::BuiltinType(_) => {
+                prohibit_generics_on_resolved(GenericArgsProhibitedReason::PrimitiveTy)
+            }
+            TypeNs::AdtId(_)
+            | TypeNs::EnumVariantId(_)
+            | TypeNs::TypeAliasId(_)
+            | TypeNs::TraitId(_)
+            | TypeNs::TraitAliasId(_) => {}
+        }
+    }
+
+    pub(crate) fn resolve_path_in_type_ns_fully(
+        &mut self,
+        path: &Path,
+        on_diagnostic: &mut dyn FnMut(&mut Self, PathLoweringDiagnostic),
+    ) -> Option<TypeNs> {
+        let (res, unresolved) = self.resolve_path_in_type_ns(path, on_diagnostic)?;
+        if unresolved.is_some() {
+            return None;
+        }
+        Some(res)
+    }
+
+    pub(crate) fn resolve_path_in_type_ns(
+        &mut self,
+        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 segments = path.segments();
+
+        match path {
+            // `segments.is_empty()` can occur with `self`.
+            Path::Normal(..) if !segments.is_empty() => (),
+            _ => 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()),
+        };
+
+        for (i, mod_segment) in module_segments.iter().enumerate() {
+            if mod_segment.args_and_bindings.is_some() {
+                on_diagnostic(
+                    self,
+                    PathLoweringDiagnostic::GenericArgsProhibited {
+                        segment: i as u32,
+                        reason: GenericArgsProhibitedReason::Module,
+                    },
+                );
+            }
+        }
+
+        self.handle_type_ns_resolution(
+            &resolution,
+            resolved_segment,
+            resolved_segment_idx,
+            on_diagnostic,
+        );
+
+        Some((resolution, remaining_index))
+    }
+
+    pub(crate) fn resolve_path_in_value_ns(
+        &mut self,
+        path: &Path,
+        hygiene_id: HygieneId,
+        on_diagnostic: &mut dyn FnMut(&mut Self, PathLoweringDiagnostic),
+    ) -> Option<ResolveValueResult> {
+        let (res, prefix_info) = self.resolver.resolve_path_in_value_ns_with_prefix_info(
+            self.db.upcast(),
+            path,
+            hygiene_id,
+        )?;
+
+        let segments = path.segments();
+        match path {
+            // `segments.is_empty()` can occur with `self`.
+            Path::Normal(..) if !segments.is_empty() => (),
+            _ => return Some(res),
+        };
+
+        let (mod_segments, enum_segment) = match res {
+            ResolveValueResult::Partial(_, unresolved_segment, _) => {
+                (segments.take(unresolved_segment - 1), None)
+            }
+            ResolveValueResult::ValueNs(ValueNs::EnumVariantId(_), _)
+                if prefix_info == ResolvePathResultPrefixInfo::Enum =>
+            {
+                (segments.strip_last_two(), segments.len().checked_sub(2))
+            }
+            ResolveValueResult::ValueNs(..) => (segments.strip_last(), None),
+        };
+        for (i, mod_segment) in mod_segments.iter().enumerate() {
+            if mod_segment.args_and_bindings.is_some() {
+                on_diagnostic(
+                    self,
+                    PathLoweringDiagnostic::GenericArgsProhibited {
+                        segment: i as u32,
+                        reason: GenericArgsProhibitedReason::Module,
+                    },
+                );
+            }
+        }
+
+        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,
+                    },
+                );
+            }
+        }
+
+        match &res {
+            ResolveValueResult::ValueNs(resolution, _) => {
+                let resolved_segment_idx =
+                    segments.len().checked_sub(1).unwrap_or_else(|| panic!("{path:?}"));
+                let resolved_segment = segments.last().unwrap();
+
+                let mut prohibit_generics_on_resolved = |reason| {
+                    if resolved_segment.args_and_bindings.is_some() {
+                        on_diagnostic(
+                            self,
+                            PathLoweringDiagnostic::GenericArgsProhibited {
+                                segment: resolved_segment_idx as u32,
+                                reason,
+                            },
+                        );
+                    }
+                };
+
+                match resolution {
+                    ValueNs::ImplSelf(_) => {
+                        prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy)
+                    }
+                    // FIXME: rustc generates E0107 (incorrect number of generic arguments) and not
+                    // E0109 (generic arguments provided for a type that doesn't accept them) for
+                    // consts and statics, presumably as a defense against future in which consts
+                    // and statics can be generic, or just because it was easier for rustc implementors.
+                    // That means we'll show the wrong error code. Because of us it's easier to do it
+                    // this way :)
+                    ValueNs::GenericParam(_) | ValueNs::ConstId(_) => {
+                        prohibit_generics_on_resolved(GenericArgsProhibitedReason::Const)
+                    }
+                    ValueNs::StaticId(_) => {
+                        prohibit_generics_on_resolved(GenericArgsProhibitedReason::Static)
+                    }
+                    ValueNs::FunctionId(_) | ValueNs::StructId(_) | ValueNs::EnumVariantId(_) => {}
+                    ValueNs::LocalBinding(_) => {}
+                }
+            }
+            ResolveValueResult::Partial(resolution, unresolved_idx, _) => {
+                let resolved_segment_idx = unresolved_idx - 1;
+                let resolved_segment = segments.get(resolved_segment_idx).unwrap();
+                self.handle_type_ns_resolution(
+                    resolution,
+                    resolved_segment,
+                    resolved_segment_idx,
+                    on_diagnostic,
+                );
+            }
+        };
+        Some(res)
+    }
+
+    fn on_path_diagnostic_callback(
+        type_ref: TypeRefId,
+    ) -> impl FnMut(&mut Self, PathLoweringDiagnostic) {
+        move |this, diag| {
+            this.push_diagnostic(type_ref, TyLoweringDiagnosticKind::PathDiagnostic(diag))
+        }
+    }
+
     pub(crate) fn lower_path(&mut self, path: &Path, path_id: PathId) -> (Ty, Option<TypeNs>) {
         // Resolve the path (in type namespace)
         if let Some(type_ref) = path.type_anchor() {
@@ -739,11 +925,13 @@ impl<'a> TyLoweringContext<'a> {
             return self.lower_ty_relative_path(ty, res, path.segments());
         }
 
-        let (resolution, remaining_index, _) =
-            match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path) {
-                Some(it) => it,
-                None => return (TyKind::Error.intern(Interner), None),
-            };
+        let (resolution, remaining_index) = match self.resolve_path_in_type_ns(
+            path,
+            &mut Self::on_path_diagnostic_callback(path_id.type_ref()),
+        ) {
+            Some(it) => it,
+            None => return (TyKind::Error.intern(Interner), None),
+        };
 
         if matches!(resolution, TypeNs::TraitId(_)) && remaining_index.is_none() {
             // trait object type without dyn
@@ -752,38 +940,22 @@ impl<'a> TyLoweringContext<'a> {
             return (ty, None);
         }
 
-        let (module_segments, resolved_segment_idx, resolved_segment, remaining_segments) =
-            match remaining_index {
-                None => (
-                    path.segments().strip_last(),
-                    path.segments().len() - 1,
-                    path.segments().last().expect("resolved path has at least one element"),
-                    PathSegments::EMPTY,
-                ),
-                Some(i) => (
-                    path.segments().take(i - 1),
-                    i - 1,
-                    path.segments().get(i - 1).unwrap(),
-                    path.segments().skip(i),
-                ),
-            };
-
-        self.prohibit_generics(path_id, 0, module_segments, GenericArgsProhibitedReason::Module);
+        let (resolved_segment_idx, resolved_segment, remaining_segments) = match remaining_index {
+            None => (
+                path.segments().len() - 1,
+                path.segments().last().expect("resolved path has at least one element"),
+                PathSegments::EMPTY,
+            ),
+            Some(i) => (i - 1, path.segments().get(i - 1).unwrap(), path.segments().skip(i)),
+        };
 
         self.lower_partly_resolved_path(
             resolution,
             resolved_segment,
             remaining_segments,
+            resolved_segment_idx as u32,
             false,
-            &mut |this, reason| {
-                this.push_diagnostic(
-                    path_id.type_ref(),
-                    TyLoweringDiagnosticKind::GenericArgsProhibited {
-                        segment: resolved_segment_idx as u32,
-                        reason,
-                    },
-                )
-            },
+            &mut Self::on_path_diagnostic_callback(path_id.type_ref()),
         )
     }
 
@@ -1085,7 +1257,9 @@ impl<'a> TyLoweringContext<'a> {
             if segment.args_and_bindings.is_some() {
                 self.push_diagnostic(
                     path_id.type_ref(),
-                    TyLoweringDiagnosticKind::GenericArgsProhibited { segment: idx, reason },
+                    TyLoweringDiagnosticKind::PathDiagnostic(
+                        PathLoweringDiagnostic::GenericArgsProhibited { segment: idx, reason },
+                    ),
                 );
             }
         });
@@ -1097,7 +1271,10 @@ impl<'a> TyLoweringContext<'a> {
         explicit_self_ty: Ty,
     ) -> Option<TraitRef> {
         let path = &self.types_map[path_id];
-        let resolved = match self.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), path)? {
+        let resolved = match self.resolve_path_in_type_ns_fully(
+            path,
+            &mut Self::on_path_diagnostic_callback(path_id.type_ref()),
+        )? {
             // FIXME(trait_alias): We need to handle trait alias here.
             TypeNs::TraitId(tr) => tr,
             _ => return None,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower/diagnostics.rs
index 61fedc8c3ac..7fe196cdbb5 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower/diagnostics.rs
@@ -1,3 +1,5 @@
+//! This files contains the declaration of diagnostics kinds for ty and path lowering.
+
 use either::Either;
 use hir_def::type_ref::TypeRefId;
 
@@ -11,7 +13,7 @@ pub struct TyLoweringDiagnostic {
 
 #[derive(Debug, PartialEq, Eq, Clone)]
 pub enum TyLoweringDiagnosticKind {
-    GenericArgsProhibited { segment: u32, reason: GenericArgsProhibitedReason },
+    PathDiagnostic(PathLoweringDiagnostic),
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -20,8 +22,15 @@ pub enum GenericArgsProhibitedReason {
     TyParam,
     SelfTy,
     PrimitiveTy,
+    Const,
+    Static,
     /// When there is a generic enum, within the expression `Enum::Variant`,
     /// either `Enum` or `Variant` are allowed to have generic arguments, but not both.
     // FIXME: This is not used now but it should be.
     EnumVariant,
 }
+
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub enum PathLoweringDiagnostic {
+    GenericArgsProhibited { segment: u32, reason: GenericArgsProhibitedReason },
+}
diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
index cbb1ed95ed6..fc77d1889c8 100644
--- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
@@ -15,12 +15,12 @@ use hir_expand::{name::Name, HirFileId, InFile};
 use hir_ty::{
     db::HirDatabase,
     diagnostics::{BodyValidationDiagnostic, UnsafetyReason},
-    CastError, InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringDiagnostic,
-    TyLoweringDiagnosticKind,
+    CastError, InferenceDiagnostic, InferenceTyDiagnosticSource, PathLoweringDiagnostic,
+    TyLoweringDiagnostic, TyLoweringDiagnosticKind,
 };
 use syntax::{
     ast::{self, HasGenericArgs},
-    AstPtr, SyntaxError, SyntaxNodePtr, TextRange,
+    match_ast, AstNode, AstPtr, SyntaxError, SyntaxNodePtr, TextRange,
 };
 use triomphe::Arc;
 
@@ -674,6 +674,39 @@ impl AnyDiagnostic {
                 };
                 Self::ty_diagnostic(diag, source_map, db)?
             }
+            InferenceDiagnostic::PathDiagnostic { node, diag } => {
+                let source = expr_or_pat_syntax(*node)?;
+                let syntax = source.value.to_node(&db.parse_or_expand(source.file_id));
+                let path = match_ast! {
+                    match (syntax.syntax()) {
+                        ast::RecordExpr(it) => it.path()?,
+                        ast::RecordPat(it) => it.path()?,
+                        ast::TupleStructPat(it) => it.path()?,
+                        ast::PathExpr(it) => it.path()?,
+                        ast::PathPat(it) => it.path()?,
+                        _ => return None,
+                    }
+                };
+                Self::path_diagnostic(diag, source.with_value(path))?
+            }
+        })
+    }
+
+    fn path_diagnostic(
+        diag: &PathLoweringDiagnostic,
+        path: InFile<ast::Path>,
+    ) -> Option<AnyDiagnostic> {
+        Some(match diag {
+            &PathLoweringDiagnostic::GenericArgsProhibited { segment, reason } => {
+                let segment = hir_segment_to_ast_segment(&path.value, segment)?;
+                let args = if let Some(generics) = segment.generic_arg_list() {
+                    AstPtr::new(&generics).wrap_left()
+                } else {
+                    AstPtr::new(&segment.parenthesized_arg_list()?).wrap_right()
+                };
+                let args = path.with_value(args);
+                GenericArgsProhibited { args, reason }.into()
+            }
         })
     }
 
@@ -693,17 +726,10 @@ impl AnyDiagnostic {
             Either::Right(source) => source,
         };
         let syntax = || source.value.to_node(&db.parse_or_expand(source.file_id));
-        Some(match diag.kind {
-            TyLoweringDiagnosticKind::GenericArgsProhibited { segment, reason } => {
+        Some(match &diag.kind {
+            TyLoweringDiagnosticKind::PathDiagnostic(diag) => {
                 let ast::Type::PathType(syntax) = syntax() else { return None };
-                let segment = hir_segment_to_ast_segment(&syntax.path()?, segment)?;
-                let args = if let Some(generics) = segment.generic_arg_list() {
-                    AstPtr::new(&generics).wrap_left()
-                } else {
-                    AstPtr::new(&segment.parenthesized_arg_list()?).wrap_right()
-                };
-                let args = source.with_value(args);
-                GenericArgsProhibited { args, reason }.into()
+                Self::path_diagnostic(diag, source.with_value(syntax.path()?))?
             }
         })
     }
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 a319a0bcf6d..a6d2ed32235 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
@@ -34,6 +34,8 @@ fn describe_reason(reason: GenericArgsProhibitedReason) -> String {
             return "you can specify generic arguments on either the enum or the variant, but not both"
                 .to_owned();
         }
+        GenericArgsProhibitedReason::Const => "constants",
+        GenericArgsProhibitedReason::Static => "statics",
     };
     format!("generic arguments are not allowed on {kind}")
 }
@@ -439,4 +441,142 @@ impl Trait for () {
         "#,
         );
     }
+
+    #[test]
+    fn in_record_expr() {
+        check_diagnostics(
+            r#"
+mod foo {
+    pub struct Bar { pub field: i32 }
+}
+fn baz() {
+    let _ = foo::<()>::Bar { field: 0 };
+            // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn in_record_pat() {
+        check_diagnostics(
+            r#"
+mod foo {
+    pub struct Bar { field: i32 }
+}
+fn baz(v: foo::Bar) {
+    let foo::<()>::Bar { .. } = v;
+        // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn in_tuple_struct_pat() {
+        check_diagnostics(
+            r#"
+mod foo {
+    pub struct Bar(i32);
+}
+fn baz(v: foo::Bar) {
+    let foo::<()>::Bar(..) = v;
+        // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn in_path_pat() {
+        check_diagnostics(
+            r#"
+mod foo {
+    pub struct Bar;
+}
+fn baz(v: foo::Bar) {
+    let foo::<()>::Bar = v;
+        // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn in_path_expr() {
+        check_diagnostics(
+            r#"
+mod foo {
+    pub struct Bar;
+}
+fn baz() {
+    let _ = foo::<()>::Bar;
+            // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn const_and_static() {
+        check_diagnostics(
+            r#"
+const CONST: i32 = 0;
+static STATIC: i32 = 0;
+fn baz() {
+    let _ = CONST::<()>;
+              // ^^^^^^ 💡 error: generic arguments are not allowed on constants
+    let _ = STATIC::<()>;
+               // ^^^^^^ 💡 error: generic arguments are not allowed on statics
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn enum_variant() {
+        check_diagnostics(
+            r#"
+enum Enum<A> {
+    Variant(A),
+}
+mod enum_ {
+    pub(super) use super::Enum::Variant as V;
+}
+fn baz() {
+    let v = Enum::<()>::Variant::<()>(());
+                            // ^^^^^^ 💡 error: you can specify generic arguments on either the enum or the variant, but not both
+    let Enum::<()>::Variant::<()>(..) = v;
+                        // ^^^^^^ 💡 error: you can specify generic arguments on either the enum or the variant, but not both
+    let _ = Enum::<()>::Variant(());
+    let _ = Enum::Variant::<()>(());
+}
+fn foo() {
+    use Enum::Variant;
+    let _ = Variant::<()>(());
+    let _ = enum_::V::<()>(());
+    let _ = enum_::<()>::V::<()>(());
+              // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn dyn_trait() {
+        check_diagnostics(
+            r#"
+mod foo {
+    pub trait Trait {}
+}
+
+fn bar() {
+    let _: &dyn foo::<()>::Trait;
+                // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+    let _: &foo::<()>::Trait;
+            // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+}
+        "#,
+        );
+    }
 }