about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/rust-analyzer/Cargo.lock4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/generics.rs27
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs86
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lib.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lower.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/path.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs80
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/path/tests.rs126
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/pretty.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/resolver.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/files.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/db.rs30
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/generics.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs96
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lib.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs433
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/utils.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir/Cargo.toml8
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/diagnostics.rs76
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/display.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs237
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs442
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs3
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/make.rs2
34 files changed, 1549 insertions, 233 deletions
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 2bd4d17fe22..5861833d53a 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -509,6 +509,7 @@ dependencies = [
  "base-db",
  "cfg",
  "either",
+ "expect-test",
  "hir-def",
  "hir-expand",
  "hir-ty",
@@ -519,6 +520,9 @@ dependencies = [
  "span",
  "stdx",
  "syntax",
+ "syntax-bridge",
+ "test-fixture",
+ "test-utils",
  "tracing",
  "triomphe",
  "tt",
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
index d4a1120908f..867bee95bed 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
@@ -31,7 +31,7 @@ use crate::{
     path::{ModPath, Path},
     src::HasSource,
     type_ref::{TypeRef, TypeRefId, TypesMap, TypesSourceMap},
-    BlockId, DefWithBodyId, HasModule, Lookup,
+    BlockId, DefWithBodyId, HasModule, Lookup, SyntheticSyntax,
 };
 
 /// A wrapper around [`span::SyntaxContextId`] that is intended only for comparisons.
@@ -141,7 +141,7 @@ pub struct BodySourceMap {
     field_map_back: FxHashMap<ExprId, FieldSource>,
     pat_field_map_back: FxHashMap<PatId, PatFieldSource>,
 
-    types: TypesSourceMap,
+    pub types: TypesSourceMap,
 
     // FIXME: Make this a sane struct.
     template_map: Option<
@@ -160,9 +160,6 @@ pub struct BodySourceMap {
     diagnostics: Vec<BodyDiagnostic>,
 }
 
-#[derive(Default, Debug, Eq, PartialEq, Clone, Copy)]
-pub struct SyntheticSyntax;
-
 #[derive(Debug, Eq, PartialEq)]
 pub enum BodyDiagnostic {
     InactiveCode { node: InFile<SyntaxNodePtr>, cfg: CfgExpr, opts: CfgOptions },
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
index 2a13f74aac7..15dd6aba311 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
@@ -369,7 +369,7 @@ impl ImplData {
 
         let item_tree = tree_id.item_tree(db);
         let impl_def = &item_tree[tree_id.value];
-        let target_trait = impl_def.target_trait.clone();
+        let target_trait = impl_def.target_trait;
         let self_ty = impl_def.self_ty;
         let is_negative = impl_def.is_negative;
         let is_unsafe = impl_def.is_unsafe;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
index 11e9bb0d886..7b3f1d06d21 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
@@ -26,8 +26,8 @@ use crate::{
     nameres::{DefMap, MacroSubNs},
     path::{AssociatedTypeBinding, GenericArg, GenericArgs, NormalPath, Path},
     type_ref::{
-        ArrayType, ConstRef, FnType, LifetimeRef, RefType, TypeBound, TypeRef, TypeRefId, TypesMap,
-        TypesSourceMap,
+        ArrayType, ConstRef, FnType, LifetimeRef, PathId, RefType, TypeBound, TypeRef, TypeRefId,
+        TypesMap, TypesSourceMap,
     },
     AdtId, ConstParamId, GenericDefId, HasModule, ItemTreeLoc, LifetimeParamId,
     LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
@@ -225,6 +225,11 @@ impl GenericParams {
     }
 
     #[inline]
+    pub fn no_predicates(&self) -> bool {
+        self.where_predicates.is_empty()
+    }
+
+    #[inline]
     pub fn where_predicates(&self) -> std::slice::Iter<'_, WherePredicate> {
         self.where_predicates.iter()
     }
@@ -874,14 +879,20 @@ fn copy_type_bound(
     to: &mut TypesMap,
     to_source_map: &mut TypesSourceMap,
 ) -> TypeBound {
+    let mut copy_path_id = |path: PathId| {
+        let new_path = copy_path(&from[path], from, from_source_map, to, to_source_map);
+        let new_path_id = to.types.alloc(TypeRef::Path(new_path));
+        if let Some(&ptr) = from_source_map.types_map_back.get(path.type_ref()) {
+            to_source_map.types_map_back.insert(new_path_id, ptr);
+        }
+        PathId::from_type_ref_unchecked(new_path_id)
+    };
+
     match bound {
-        TypeBound::Path(path, modifier) => {
-            TypeBound::Path(copy_path(path, from, from_source_map, to, to_source_map), *modifier)
+        &TypeBound::Path(path, modifier) => TypeBound::Path(copy_path_id(path), modifier),
+        TypeBound::ForLifetime(lifetimes, path) => {
+            TypeBound::ForLifetime(lifetimes.clone(), copy_path_id(*path))
         }
-        TypeBound::ForLifetime(lifetimes, path) => TypeBound::ForLifetime(
-            lifetimes.clone(),
-            copy_path(path, from, from_source_map, to, to_source_map),
-        ),
         TypeBound::Lifetime(lifetime) => TypeBound::Lifetime(lifetime.clone()),
         TypeBound::Use(use_args) => TypeBound::Use(use_args.clone()),
         TypeBound::Error => TypeBound::Error,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
index 4d83ef99c84..6d4d519cd2b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
@@ -23,6 +23,7 @@ use crate::{
     hir::Literal,
     lower::LowerCtx,
     path::{GenericArg, Path},
+    SyntheticSyntax,
 };
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
@@ -91,19 +92,37 @@ impl Rawness {
     }
 }
 
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+/// A `TypeRefId` that is guaranteed to always be `TypeRef::Path`. We use this for things like
+/// impl's trait, that are always paths but need to be traced back to source code.
+pub struct PathId(TypeRefId);
+
+impl PathId {
+    #[inline]
+    pub fn from_type_ref_unchecked(type_ref: TypeRefId) -> Self {
+        Self(type_ref)
+    }
+
+    #[inline]
+    pub fn type_ref(self) -> TypeRefId {
+        self.0
+    }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
 pub struct TraitRef {
-    pub path: Path,
+    pub path: PathId,
 }
 
 impl TraitRef {
     /// Converts an `ast::PathType` to a `hir::TraitRef`.
     pub(crate) fn from_ast(ctx: &mut LowerCtx<'_>, node: ast::Type) -> Option<Self> {
         // FIXME: Use `Path::from_src`
-        match node {
-            ast::Type::PathType(path) => {
-                path.path().and_then(|it| ctx.lower_path(it)).map(|path| TraitRef { path })
-            }
+        match &node {
+            ast::Type::PathType(path) => path
+                .path()
+                .and_then(|it| ctx.lower_path(it))
+                .map(|path| TraitRef { path: ctx.alloc_path(path, AstPtr::new(&node)) }),
             _ => None,
         }
     }
@@ -173,11 +192,24 @@ impl TypesMap {
 impl Index<TypeRefId> for TypesMap {
     type Output = TypeRef;
 
+    #[inline]
     fn index(&self, index: TypeRefId) -> &Self::Output {
         &self.types[index]
     }
 }
 
+impl Index<PathId> for TypesMap {
+    type Output = Path;
+
+    #[inline]
+    fn index(&self, index: PathId) -> &Self::Output {
+        let TypeRef::Path(path) = &self[index.type_ref()] else {
+            unreachable!("`PathId` always points to `TypeRef::Path`");
+        };
+        path
+    }
+}
+
 pub type TypePtr = AstPtr<ast::Type>;
 pub type TypeSource = InFile<TypePtr>;
 
@@ -187,6 +219,12 @@ pub struct TypesSourceMap {
 }
 
 impl TypesSourceMap {
+    pub const EMPTY: Self = Self { types_map_back: ArenaMap::new() };
+
+    pub fn type_syntax(&self, id: TypeRefId) -> Result<TypeSource, SyntheticSyntax> {
+        self.types_map_back.get(id).cloned().ok_or(SyntheticSyntax)
+    }
+
     pub(crate) fn shrink_to_fit(&mut self) {
         let TypesSourceMap { types_map_back } = self;
         types_map_back.shrink_to_fit();
@@ -214,15 +252,15 @@ impl LifetimeRef {
 
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
 pub enum TypeBound {
-    Path(Path, TraitBoundModifier),
-    ForLifetime(Box<[Name]>, Path),
+    Path(PathId, TraitBoundModifier),
+    ForLifetime(Box<[Name]>, PathId),
     Lifetime(LifetimeRef),
     Use(Box<[UseArgRef]>),
     Error,
 }
 
 #[cfg(target_pointer_width = "64")]
-const _: [(); 32] = [(); ::std::mem::size_of::<TypeBound>()];
+const _: [(); 24] = [(); ::std::mem::size_of::<TypeBound>()];
 
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
 pub enum UseArgRef {
@@ -365,8 +403,8 @@ impl TypeRef {
                 TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
                     for bound in bounds {
                         match bound {
-                            TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
-                                go_path(path, f, map)
+                            &TypeBound::Path(path, _) | &TypeBound::ForLifetime(_, path) => {
+                                go_path(&map[path], f, map)
                             }
                             TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
                         }
@@ -397,8 +435,8 @@ impl TypeRef {
                         }
                         for bound in binding.bounds.iter() {
                             match bound {
-                                TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
-                                    go_path(path, f, map)
+                                &TypeBound::Path(path, _) | &TypeBound::ForLifetime(_, path) => {
+                                    go_path(&map[path], f, map)
                                 }
                                 TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
                             }
@@ -425,7 +463,7 @@ pub(crate) fn type_bounds_from_ast(
 
 impl TypeBound {
     pub(crate) fn from_ast(ctx: &mut LowerCtx<'_>, node: ast::TypeBound) -> Self {
-        let mut lower_path_type = |path_type: ast::PathType| ctx.lower_path(path_type.path()?);
+        let mut lower_path_type = |path_type: &ast::PathType| ctx.lower_path(path_type.path()?);
 
         match node.kind() {
             ast::TypeBoundKind::PathType(path_type) => {
@@ -433,8 +471,10 @@ impl TypeBound {
                     Some(_) => TraitBoundModifier::Maybe,
                     None => TraitBoundModifier::None,
                 };
-                lower_path_type(path_type)
-                    .map(|p| TypeBound::Path(p, m))
+                lower_path_type(&path_type)
+                    .map(|p| {
+                        TypeBound::Path(ctx.alloc_path(p, AstPtr::new(&path_type).upcast()), m)
+                    })
                     .unwrap_or(TypeBound::Error)
             }
             ast::TypeBoundKind::ForType(for_type) => {
@@ -445,12 +485,14 @@ impl TypeBound {
                         .collect(),
                     None => Box::default(),
                 };
-                let path = for_type.ty().and_then(|ty| match ty {
-                    ast::Type::PathType(path_type) => lower_path_type(path_type),
+                let path = for_type.ty().and_then(|ty| match &ty {
+                    ast::Type::PathType(path_type) => lower_path_type(path_type).map(|p| (p, ty)),
                     _ => None,
                 });
                 match path {
-                    Some(p) => TypeBound::ForLifetime(lt_refs, p),
+                    Some((p, ty)) => {
+                        TypeBound::ForLifetime(lt_refs, ctx.alloc_path(p, AstPtr::new(&ty)))
+                    }
                     None => TypeBound::Error,
                 }
             }
@@ -470,10 +512,10 @@ impl TypeBound {
         }
     }
 
-    pub fn as_path(&self) -> Option<(&Path, &TraitBoundModifier)> {
+    pub fn as_path<'a>(&self, map: &'a TypesMap) -> Option<(&'a Path, TraitBoundModifier)> {
         match self {
-            TypeBound::Path(p, m) => Some((p, m)),
-            TypeBound::ForLifetime(_, p) => Some((p, &TraitBoundModifier::None)),
+            &TypeBound::Path(p, m) => Some((&map[p], m)),
+            &TypeBound::ForLifetime(_, p) => Some((&map[p], TraitBoundModifier::None)),
             TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => None,
         }
     }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
index d519c1708b3..71848845a84 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
@@ -34,7 +34,7 @@ use crate::{
     lower::LowerCtx,
     path::AssociatedTypeBinding,
     type_ref::{
-        LifetimeRef, RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId,
+        LifetimeRef, PathId, RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId,
         TypesMap, TypesSourceMap,
     },
     visibility::RawVisibility,
@@ -514,7 +514,7 @@ impl<'a> Ctx<'a> {
         };
 
         let ret_type = if func.async_token().is_some() {
-            let future_impl = desugar_future_path(ret_type);
+            let future_impl = desugar_future_path(&mut body_ctx, ret_type);
             let ty_bound = TypeBound::Path(future_impl, TraitBoundModifier::None);
             body_ctx.alloc_type_ref_desugared(TypeRef::ImplTrait(ThinVec::from_iter([ty_bound])))
         } else {
@@ -936,7 +936,7 @@ impl<'a> Ctx<'a> {
     }
 }
 
-fn desugar_future_path(orig: TypeRefId) -> Path {
+fn desugar_future_path(ctx: &mut LowerCtx<'_>, orig: TypeRefId) -> PathId {
     let path = path![core::future::Future];
     let mut generic_args: Vec<_> =
         std::iter::repeat(None).take(path.segments().len() - 1).collect();
@@ -948,7 +948,8 @@ fn desugar_future_path(orig: TypeRefId) -> Path {
     };
     generic_args.push(Some(GenericArgs { bindings: Box::new([binding]), ..GenericArgs::empty() }));
 
-    Path::from_known_path(path, generic_args)
+    let path = Path::from_known_path(path, generic_args);
+    PathId::from_type_ref_unchecked(ctx.alloc_type_ref_desugared(TypeRef::Path(path)))
 }
 
 enum HasImplicitSelf {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
index b6816a1f968..0c5e3a3620a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
@@ -484,7 +484,7 @@ impl Printer<'_> {
                     w!(self, "!");
                 }
                 if let Some(tr) = target_trait {
-                    self.print_path(&tr.path, types_map);
+                    self.print_path(&types_map[tr.path], types_map);
                     w!(self, " for ");
                 }
                 self.print_type_ref(*self_ty, types_map);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
index eb55ba1d53d..8af27513ebc 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -1535,3 +1535,6 @@ fn macro_call_as_call_id_with_eager(
 pub struct UnresolvedMacro {
     pub path: hir_expand::mod_path::ModPath,
 }
+
+#[derive(Default, Debug, Eq, PartialEq, Clone, Copy)]
+pub struct SyntheticSyntax;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
index 350bb8d5172..7cddd48eb17 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
@@ -10,7 +10,7 @@ use triomphe::Arc;
 use crate::{
     db::DefDatabase,
     path::Path,
-    type_ref::{TypeBound, TypePtr, TypeRef, TypeRefId, TypesMap, TypesSourceMap},
+    type_ref::{PathId, TypeBound, TypePtr, TypeRef, TypeRefId, TypesMap, TypesSourceMap},
 };
 
 pub struct LowerCtx<'a> {
@@ -142,4 +142,8 @@ impl<'a> LowerCtx<'a> {
     pub(crate) fn alloc_error_type(&mut self) -> TypeRefId {
         self.types_map.types.alloc(TypeRef::Error)
     }
+
+    pub(crate) fn alloc_path(&mut self, path: Path, node: TypePtr) -> PathId {
+        PathId::from_type_ref_unchecked(self.alloc_type_ref(TypeRef::Path(path), node))
+    }
 }
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 aa2c4a6f1bc..44e132061ad 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/path.rs
@@ -1,5 +1,7 @@
 //! A desugared representation of paths like `crate::foo` or `<Type as Trait>::bar`.
 mod lower;
+#[cfg(test)]
+mod tests;
 
 use std::{
     fmt::{self, Display},
@@ -19,6 +21,8 @@ use syntax::ast;
 
 pub use hir_expand::mod_path::{path, ModPath, PathKind};
 
+pub use lower::hir_segment_to_ast_segment;
+
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub enum ImportAlias {
     /// Unnamed alias, as in `use Foo as _;`
@@ -230,7 +234,7 @@ impl Path {
     }
 }
 
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct PathSegment<'a> {
     pub name: &'a Name,
     pub args_and_bindings: Option<&'a GenericArgs>,
@@ -274,6 +278,12 @@ impl<'a> PathSegments<'a> {
             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 iter(&self) -> impl Iterator<Item = PathSegment<'a>> {
         self.segments
             .iter()
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
index 37c94a5f118..3b7e7653fba 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
@@ -17,13 +17,31 @@ use crate::{
     type_ref::{LifetimeRef, TypeBound, TypeRef},
 };
 
+#[cfg(test)]
+thread_local! {
+    /// This is used to test `hir_segment_to_ast_segment()`. It's a hack, but it makes testing much easier.
+    pub(super) static SEGMENT_LOWERING_MAP: std::cell::RefCell<rustc_hash::FxHashMap<ast::PathSegment, usize>> = std::cell::RefCell::default();
+}
+
 /// Converts an `ast::Path` to `Path`. Works with use trees.
 /// It correctly handles `$crate` based path from macro call.
+// If you modify the logic of the lowering, make sure to check if `hir_segment_to_ast_segment()`
+// also needs an update.
 pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<Path> {
     let mut kind = PathKind::Plain;
     let mut type_anchor = None;
     let mut segments = Vec::new();
     let mut generic_args = Vec::new();
+    #[cfg(test)]
+    let mut ast_segments = Vec::new();
+    #[cfg(test)]
+    let mut ast_segments_offset = 0;
+    #[allow(unused_mut)]
+    let mut push_segment = |_segment: &ast::PathSegment, segments: &mut Vec<Name>, name| {
+        #[cfg(test)]
+        ast_segments.push(_segment.clone());
+        segments.push(name);
+    };
     loop {
         let segment = path.segment()?;
 
@@ -34,6 +52,10 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<
         match segment.kind()? {
             ast::PathSegmentKind::Name(name_ref) => {
                 if name_ref.text() == "$crate" {
+                    if path.qualifier().is_some() {
+                        // FIXME: Report an error.
+                        return None;
+                    }
                     break kind = resolve_crate_root(
                         ctx.db.upcast(),
                         ctx.span_map().span_for_range(name_ref.syntax().text_range()).ctx,
@@ -56,10 +78,10 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<
                     generic_args.resize(segments.len(), None);
                     generic_args.push(args);
                 }
-                segments.push(name);
+                push_segment(&segment, &mut segments, name);
             }
             ast::PathSegmentKind::SelfTypeKw => {
-                segments.push(Name::new_symbol_root(sym::Self_.clone()));
+                push_segment(&segment, &mut segments, Name::new_symbol_root(sym::Self_.clone()));
             }
             ast::PathSegmentKind::Type { type_ref, trait_ref } => {
                 assert!(path.qualifier().is_none()); // this can only occur at the first segment
@@ -81,6 +103,10 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<
                         kind = mod_path.kind;
 
                         segments.extend(mod_path.segments().iter().cloned().rev());
+                        #[cfg(test)]
+                        {
+                            ast_segments_offset = mod_path.segments().len();
+                        }
                         if let Some(path_generic_args) = path_generic_args {
                             generic_args.resize(segments.len() - num_segments, None);
                             generic_args.extend(Vec::from(path_generic_args).into_iter().rev());
@@ -112,10 +138,18 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<
                 }
             }
             ast::PathSegmentKind::CrateKw => {
+                if path.qualifier().is_some() {
+                    // FIXME: Report an error.
+                    return None;
+                }
                 kind = PathKind::Crate;
                 break;
             }
             ast::PathSegmentKind::SelfKw => {
+                if path.qualifier().is_some() {
+                    // FIXME: Report an error.
+                    return None;
+                }
                 // don't break out if `self` is the last segment of a path, this mean we got a
                 // use tree like `foo::{self}` which we want to resolve as `foo`
                 if !segments.is_empty() {
@@ -162,6 +196,13 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<
         }
     }
 
+    #[cfg(test)]
+    {
+        ast_segments.reverse();
+        SEGMENT_LOWERING_MAP
+            .with_borrow_mut(|map| map.extend(ast_segments.into_iter().zip(ast_segments_offset..)));
+    }
+
     let mod_path = Interned::new(ModPath::from_segments(kind, segments));
     if type_anchor.is_none() && generic_args.is_empty() {
         return Some(Path::BarePath(mod_path));
@@ -181,6 +222,41 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<
     }
 }
 
+/// This function finds the AST segment that corresponds to the HIR segment
+/// with index `segment_idx` on the path that is lowered from `path`.
+pub fn hir_segment_to_ast_segment(path: &ast::Path, segment_idx: u32) -> Option<ast::PathSegment> {
+    // Too tightly coupled to `lower_path()`, but unfortunately we cannot decouple them,
+    // as keeping source maps for all paths segments will have a severe impact on memory usage.
+
+    let mut segments = path.segments();
+    if let Some(ast::PathSegmentKind::Type { trait_ref: Some(trait_ref), .. }) =
+        segments.clone().next().and_then(|it| it.kind())
+    {
+        segments.next();
+        return find_segment(trait_ref.path()?.segments().chain(segments), segment_idx);
+    }
+    return find_segment(segments, segment_idx);
+
+    fn find_segment(
+        segments: impl Iterator<Item = ast::PathSegment>,
+        segment_idx: u32,
+    ) -> Option<ast::PathSegment> {
+        segments
+            .filter(|segment| match segment.kind() {
+                Some(
+                    ast::PathSegmentKind::CrateKw
+                    | ast::PathSegmentKind::SelfKw
+                    | ast::PathSegmentKind::SuperKw
+                    | ast::PathSegmentKind::Type { .. },
+                )
+                | None => false,
+                Some(ast::PathSegmentKind::Name(name)) => name.text() != "$crate",
+                Some(ast::PathSegmentKind::SelfTypeKw) => true,
+            })
+            .nth(segment_idx as usize)
+    }
+}
+
 pub(super) fn lower_generic_args(
     lower_ctx: &mut LowerCtx<'_>,
     node: ast::GenericArgList,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/tests.rs
new file mode 100644
index 00000000000..67a27bf85e8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/hir-def/src/path/tests.rs
@@ -0,0 +1,126 @@
+use expect_test::{expect, Expect};
+use span::Edition;
+use syntax::ast::{self, make};
+use test_fixture::WithFixture;
+
+use crate::{
+    lower::LowerCtx,
+    path::{
+        lower::{hir_segment_to_ast_segment, SEGMENT_LOWERING_MAP},
+        Path,
+    },
+    pretty,
+    test_db::TestDB,
+    type_ref::{TypesMap, TypesSourceMap},
+};
+
+fn lower_path(path: ast::Path) -> (TestDB, TypesMap, Option<Path>) {
+    let (db, file_id) = TestDB::with_single_file("");
+    let mut types_map = TypesMap::default();
+    let mut types_source_map = TypesSourceMap::default();
+    let mut ctx = LowerCtx::new(&db, file_id.into(), &mut types_map, &mut types_source_map);
+    let lowered_path = ctx.lower_path(path);
+    (db, types_map, lowered_path)
+}
+
+#[track_caller]
+fn check_hir_to_ast(path: &str, ignore_segments: &[&str]) {
+    let path = make::path_from_text(path);
+    SEGMENT_LOWERING_MAP.with_borrow_mut(|map| map.clear());
+    let _ = lower_path(path.clone()).2.expect("failed to lower path");
+    SEGMENT_LOWERING_MAP.with_borrow(|map| {
+        for (segment, segment_idx) in map {
+            if ignore_segments.contains(&&*segment.to_string()) {
+                continue;
+            }
+
+            let restored_segment = hir_segment_to_ast_segment(&path, *segment_idx as u32)
+                .unwrap_or_else(|| {
+                    panic!(
+                        "failed to map back segment `{segment}` \
+                        numbered {segment_idx} in HIR from path `{path}`"
+                    )
+                });
+            assert_eq!(
+                segment, &restored_segment,
+                "mapping back `{segment}` numbered {segment_idx} in HIR \
+                from path `{path}` produced incorrect segment `{restored_segment}`"
+            );
+        }
+    });
+}
+
+#[test]
+fn hir_to_ast_trait_ref() {
+    check_hir_to_ast("<A as B::C::D>::E::F", &["A"]);
+}
+
+#[test]
+fn hir_to_ast_plain_path() {
+    check_hir_to_ast("A::B::C::D::E::F", &[]);
+}
+
+#[test]
+fn hir_to_ast_crate_path() {
+    check_hir_to_ast("crate::A::B::C", &[]);
+    check_hir_to_ast("crate::super::super::A::B::C", &[]);
+}
+
+#[test]
+fn hir_to_ast_self_path() {
+    check_hir_to_ast("self::A::B::C", &[]);
+    check_hir_to_ast("self::super::super::A::B::C", &[]);
+}
+
+#[test]
+fn hir_to_ast_super_path() {
+    check_hir_to_ast("super::A::B::C", &[]);
+    check_hir_to_ast("super::super::super::A::B::C", &[]);
+}
+
+#[test]
+fn hir_to_ast_type_anchor_path() {
+    check_hir_to_ast("<A::B>::C::D", &["A", "B"]);
+}
+
+#[test]
+fn hir_to_ast_path_super_in_middle() {
+    check_hir_to_ast("A::super::B::super::super::C::D", &[]);
+}
+
+#[track_caller]
+fn check_fail_lowering(path: &str) {
+    let (_, _, lowered_path) = lower_path(make::path_from_text(path));
+    assert!(lowered_path.is_none(), "path `{path}` should fail lowering");
+}
+
+#[test]
+fn keywords_in_middle_fail_lowering1() {
+    check_fail_lowering("self::A::self::B::super::C::crate::D");
+}
+
+#[test]
+fn keywords_in_middle_fail_lowering2() {
+    check_fail_lowering("A::super::self::C::D");
+}
+
+#[test]
+fn keywords_in_middle_fail_lowering3() {
+    check_fail_lowering("A::crate::B::C::D");
+}
+
+#[track_caller]
+fn check_path_lowering(path: &str, expected: Expect) {
+    let (db, types_map, lowered_path) = lower_path(make::path_from_text(path));
+    let lowered_path = lowered_path.expect("failed to lower path");
+    let mut buf = String::new();
+    pretty::print_path(&db, &lowered_path, &types_map, &mut buf, Edition::CURRENT)
+        .expect("failed to pretty-print path");
+    expected.assert_eq(&buf);
+}
+
+#[test]
+fn fn_like_path_with_coloncolon() {
+    check_path_lowering("Fn::(A, B) -> C", expect![[r#"Fn::<(A, B), Output = C>"#]]);
+    check_path_lowering("Fn::(A, B)", expect![[r#"Fn::<(A, B), Output = ()>"#]]);
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
index 9ceb82d5fd6..eb9488feaa9 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
@@ -271,7 +271,7 @@ pub(crate) fn print_type_bounds(
                     TraitBoundModifier::None => (),
                     TraitBoundModifier::Maybe => write!(buf, "?")?,
                 }
-                print_path(db, path, map, buf, edition)?;
+                print_path(db, &map[*path], map, buf, edition)?;
             }
             TypeBound::ForLifetime(lifetimes, path) => {
                 write!(
@@ -279,7 +279,7 @@ pub(crate) fn print_type_bounds(
                     "for<{}> ",
                     lifetimes.iter().map(|it| it.display(db.upcast(), edition)).format(", ")
                 )?;
-                print_path(db, path, map, buf, edition)?;
+                print_path(db, &map[*path], map, buf, edition)?;
             }
             TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), edition))?,
             TypeBound::Use(args) => {
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 26655e40ca7..0ca7070fd05 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -576,10 +576,12 @@ impl Resolver {
             match scope {
                 Scope::BlockScope(m) => traits.extend(m.def_map[m.module_id].scope.traits()),
                 &Scope::ImplDefScope(impl_) => {
-                    if let Some(target_trait) = &db.impl_data(impl_).target_trait {
-                        if let Some(TypeNs::TraitId(trait_)) =
-                            self.resolve_path_in_type_ns_fully(db, &target_trait.path)
-                        {
+                    let impl_data = db.impl_data(impl_);
+                    if let Some(target_trait) = impl_data.target_trait {
+                        if let Some(TypeNs::TraitId(trait_)) = self.resolve_path_in_type_ns_fully(
+                            db,
+                            &impl_data.types_map[target_trait.path],
+                        ) {
                             traits.insert(trait_);
                         }
                     }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs
index d41f69812ee..8c04d054029 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs
@@ -180,6 +180,13 @@ impl<FileId: FileIdToSyntax, T> InFileWrapper<FileId, T> {
     }
 }
 
+#[allow(private_bounds)]
+impl<FileId: FileIdToSyntax, N: AstNode> InFileWrapper<FileId, AstPtr<N>> {
+    pub fn to_node(&self, db: &dyn ExpandDatabase) -> N {
+        self.value.to_node(&self.file_syntax(db))
+    }
+}
+
 impl<FileId: Copy, N: AstNode> InFileWrapper<FileId, N> {
     pub fn syntax(&self) -> InFileWrapper<FileId, &SyntaxNode> {
         self.with_value(self.value.syntax())
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
index 3a3a05c369a..6856eaa3e02 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
@@ -22,7 +22,7 @@ use crate::{
     consteval::ConstEvalError,
     dyn_compatibility::DynCompatibilityViolation,
     layout::{Layout, LayoutError},
-    lower::{GenericDefaults, GenericPredicates},
+    lower::{Diagnostics, GenericDefaults, GenericPredicates},
     method_resolution::{InherentImpls, TraitImpls, TyFingerprint},
     mir::{BorrowckResult, MirBody, MirLowerError},
     Binders, ClosureId, Const, FnDefId, ImplTraitId, ImplTraits, InferenceResult, Interner,
@@ -115,21 +115,35 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
     #[ra_salsa::cycle(crate::lower::ty_recover)]
     fn ty(&self, def: TyDefId) -> Binders<Ty>;
 
+    #[ra_salsa::invoke(crate::lower::type_for_type_alias_with_diagnostics_query)]
+    fn type_for_type_alias_with_diagnostics(&self, def: TypeAliasId) -> (Binders<Ty>, Diagnostics);
+
     /// Returns the type of the value of the given constant, or `None` if the `ValueTyDefId` is
     /// a `StructId` or `EnumVariantId` with a record constructor.
     #[ra_salsa::invoke(crate::lower::value_ty_query)]
     fn value_ty(&self, def: ValueTyDefId) -> Option<Binders<Ty>>;
 
+    #[ra_salsa::invoke(crate::lower::impl_self_ty_with_diagnostics_query)]
+    #[ra_salsa::cycle(crate::lower::impl_self_ty_with_diagnostics_recover)]
+    fn impl_self_ty_with_diagnostics(&self, def: ImplId) -> (Binders<Ty>, Diagnostics);
     #[ra_salsa::invoke(crate::lower::impl_self_ty_query)]
-    #[ra_salsa::cycle(crate::lower::impl_self_ty_recover)]
     fn impl_self_ty(&self, def: ImplId) -> Binders<Ty>;
 
+    #[ra_salsa::invoke(crate::lower::const_param_ty_with_diagnostics_query)]
+    fn const_param_ty_with_diagnostics(&self, def: ConstParamId) -> (Ty, Diagnostics);
     #[ra_salsa::invoke(crate::lower::const_param_ty_query)]
     fn const_param_ty(&self, def: ConstParamId) -> Ty;
 
+    #[ra_salsa::invoke(crate::lower::impl_trait_with_diagnostics_query)]
+    fn impl_trait_with_diagnostics(&self, def: ImplId) -> Option<(Binders<TraitRef>, Diagnostics)>;
     #[ra_salsa::invoke(crate::lower::impl_trait_query)]
     fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>;
 
+    #[ra_salsa::invoke(crate::lower::field_types_with_diagnostics_query)]
+    fn field_types_with_diagnostics(
+        &self,
+        var: VariantId,
+    ) -> (Arc<ArenaMap<LocalFieldId, Binders<Ty>>>, Diagnostics);
     #[ra_salsa::invoke(crate::lower::field_types_query)]
     fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>>;
 
@@ -154,6 +168,11 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
     #[ra_salsa::invoke(crate::lower::generic_predicates_query)]
     fn generic_predicates(&self, def: GenericDefId) -> GenericPredicates;
 
+    #[ra_salsa::invoke(crate::lower::generic_predicates_without_parent_with_diagnostics_query)]
+    fn generic_predicates_without_parent_with_diagnostics(
+        &self,
+        def: GenericDefId,
+    ) -> (GenericPredicates, Diagnostics);
     #[ra_salsa::invoke(crate::lower::generic_predicates_without_parent_query)]
     fn generic_predicates_without_parent(&self, def: GenericDefId) -> GenericPredicates;
 
@@ -164,8 +183,13 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
     #[ra_salsa::invoke(crate::lower::trait_environment_query)]
     fn trait_environment(&self, def: GenericDefId) -> Arc<TraitEnvironment>;
 
+    #[ra_salsa::invoke(crate::lower::generic_defaults_with_diagnostics_query)]
+    #[ra_salsa::cycle(crate::lower::generic_defaults_with_diagnostics_recover)]
+    fn generic_defaults_with_diagnostics(
+        &self,
+        def: GenericDefId,
+    ) -> (GenericDefaults, Diagnostics);
     #[ra_salsa::invoke(crate::lower::generic_defaults_query)]
-    #[ra_salsa::cycle(crate::lower::generic_defaults_recover)]
     fn generic_defaults(&self, def: GenericDefId) -> GenericDefaults;
 
     #[ra_salsa::invoke(InherentImpls::inherent_impls_in_crate_query)]
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
index 4e95bdf219f..94a340fbec2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -2062,12 +2062,12 @@ impl HirDisplayWithTypesMap for TypeBound {
         types_map: &TypesMap,
     ) -> Result<(), HirDisplayError> {
         match self {
-            TypeBound::Path(path, modifier) => {
+            &TypeBound::Path(path, modifier) => {
                 match modifier {
                     TraitBoundModifier::None => (),
                     TraitBoundModifier::Maybe => write!(f, "?")?,
                 }
-                path.hir_fmt(f, types_map)
+                types_map[path].hir_fmt(f, types_map)
             }
             TypeBound::Lifetime(lifetime) => {
                 write!(f, "{}", lifetime.name.display(f.db.upcast(), f.edition()))
@@ -2079,7 +2079,7 @@ impl HirDisplayWithTypesMap for TypeBound {
                     "for<{}> ",
                     lifetimes.iter().map(|it| it.display(f.db.upcast(), edition)).format(", ")
                 )?;
-                path.hir_fmt(f, types_map)
+                types_map[*path].hir_fmt(f, types_map)
             }
             TypeBound::Use(args) => {
                 let edition = f.edition();
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs
index c094bc39512..fe7541d2374 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs
@@ -55,6 +55,10 @@ impl Generics {
         self.def
     }
 
+    pub(crate) fn self_types_map(&self) -> &TypesMap {
+        &self.params.types_map
+    }
+
     pub(crate) fn iter_id(&self) -> impl Iterator<Item = GenericParamId> + '_ {
         self.iter_self_id().chain(self.iter_parent_id())
     }
@@ -86,15 +90,13 @@ impl Generics {
         self.iter_self().chain(self.iter_parent())
     }
 
-    pub(crate) fn iter_with_types_map(
+    pub(crate) fn iter_parents_with_types_map(
         &self,
     ) -> impl Iterator<Item = ((GenericParamId, GenericParamDataRef<'_>), &TypesMap)> + '_ {
-        self.iter_self().zip(std::iter::repeat(&self.params.types_map)).chain(
-            self.iter_parent().zip(
-                self.parent_generics()
-                    .into_iter()
-                    .flat_map(|it| std::iter::repeat(&it.params.types_map)),
-            ),
+        self.iter_parent().zip(
+            self.parent_generics()
+                .into_iter()
+                .flat_map(|it| std::iter::repeat(&it.params.types_map)),
         )
     }
 
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 01e0b635b22..dbee5a1a919 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -58,7 +58,7 @@ use crate::{
     fold_tys,
     generics::Generics,
     infer::{coerce::CoerceMany, expr::ExprIsRead, unify::InferenceTable},
-    lower::ImplTraitLoweringMode,
+    lower::{ImplTraitLoweringMode, TyLoweringDiagnostic},
     mir::MirSpan,
     to_assoc_type_id,
     traits::FnTrait,
@@ -191,6 +191,14 @@ impl<T> InferOk<T> {
     }
 }
 
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub enum InferenceTyDiagnosticSource {
+    /// Diagnostics that come from types in the body.
+    Body,
+    /// Diagnostics that come from types in fn parameters/return type, or static & const types.
+    Signature,
+}
+
 #[derive(Debug)]
 pub(crate) struct TypeError;
 pub(crate) type InferResult<T> = Result<InferOk<T>, TypeError>;
@@ -264,6 +272,10 @@ pub enum InferenceDiagnostic {
         expr_ty: Ty,
         cast_ty: Ty,
     },
+    TyDiagnostic {
+        source: InferenceTyDiagnosticSource,
+        diag: TyLoweringDiagnostic,
+    },
 }
 
 /// A mismatch between an expected and an inferred type.
@@ -858,7 +870,8 @@ impl<'a> InferenceContext<'a> {
     }
 
     fn collect_const(&mut self, data: &ConstData) {
-        let return_ty = self.make_ty(data.type_ref, &data.types_map);
+        let return_ty =
+            self.make_ty(data.type_ref, &data.types_map, InferenceTyDiagnosticSource::Signature);
 
         // Constants might be defining usage sites of TAITs.
         self.make_tait_coercion_table(iter::once(&return_ty));
@@ -867,7 +880,8 @@ impl<'a> InferenceContext<'a> {
     }
 
     fn collect_static(&mut self, data: &StaticData) {
-        let return_ty = self.make_ty(data.type_ref, &data.types_map);
+        let return_ty =
+            self.make_ty(data.type_ref, &data.types_map, InferenceTyDiagnosticSource::Signature);
 
         // Statics might be defining usage sites of TAITs.
         self.make_tait_coercion_table(iter::once(&return_ty));
@@ -877,11 +891,12 @@ impl<'a> InferenceContext<'a> {
 
     fn collect_fn(&mut self, func: FunctionId) {
         let data = self.db.function_data(func);
-        let mut param_tys = self.with_ty_lowering(&data.types_map, |ctx| {
-            ctx.type_param_mode(ParamLoweringMode::Placeholder)
-                .impl_trait_mode(ImplTraitLoweringMode::Param);
-            data.params.iter().map(|&type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>()
-        });
+        let mut param_tys =
+            self.with_ty_lowering(&data.types_map, InferenceTyDiagnosticSource::Signature, |ctx| {
+                ctx.type_param_mode(ParamLoweringMode::Placeholder)
+                    .impl_trait_mode(ImplTraitLoweringMode::Param);
+                data.params.iter().map(|&type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>()
+            });
         // Check if function contains a va_list, if it does then we append it to the parameter types
         // that are collected from the function data
         if data.is_varargs() {
@@ -918,11 +933,12 @@ impl<'a> InferenceContext<'a> {
         }
         let return_ty = data.ret_type;
 
-        let return_ty = self.with_ty_lowering(&data.types_map, |ctx| {
-            ctx.type_param_mode(ParamLoweringMode::Placeholder)
-                .impl_trait_mode(ImplTraitLoweringMode::Opaque)
-                .lower_ty(return_ty)
-        });
+        let return_ty =
+            self.with_ty_lowering(&data.types_map, InferenceTyDiagnosticSource::Signature, |ctx| {
+                ctx.type_param_mode(ParamLoweringMode::Placeholder)
+                    .impl_trait_mode(ImplTraitLoweringMode::Opaque)
+                    .lower_ty(return_ty)
+            });
         let return_ty = self.insert_type_vars(return_ty);
 
         let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) {
@@ -1226,9 +1242,20 @@ impl<'a> InferenceContext<'a> {
         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 with_ty_lowering<R>(
-        &self,
+        &mut self,
         types_map: &TypesMap,
+        types_source: InferenceTyDiagnosticSource,
         f: impl FnOnce(&mut crate::lower::TyLoweringContext<'_>) -> R,
     ) -> R {
         let mut ctx = crate::lower::TyLoweringContext::new(
@@ -1237,32 +1264,41 @@ impl<'a> InferenceContext<'a> {
             types_map,
             self.owner.into(),
         );
-        f(&mut ctx)
+        let result = f(&mut ctx);
+        self.push_ty_diagnostics(types_source, ctx.diagnostics);
+        result
     }
 
     fn with_body_ty_lowering<R>(
-        &self,
+        &mut self,
         f: impl FnOnce(&mut crate::lower::TyLoweringContext<'_>) -> R,
     ) -> R {
-        self.with_ty_lowering(&self.body.types, f)
+        self.with_ty_lowering(&self.body.types, InferenceTyDiagnosticSource::Body, f)
     }
 
-    fn make_ty(&mut self, type_ref: TypeRefId, types_map: &TypesMap) -> Ty {
-        let ty = self.with_ty_lowering(types_map, |ctx| ctx.lower_ty(type_ref));
+    fn make_ty(
+        &mut self,
+        type_ref: TypeRefId,
+        types_map: &TypesMap,
+        type_source: InferenceTyDiagnosticSource,
+    ) -> Ty {
+        let ty = self.with_ty_lowering(types_map, type_source, |ctx| ctx.lower_ty(type_ref));
         let ty = self.insert_type_vars(ty);
         self.normalize_associated_types_in(ty)
     }
 
     fn make_body_ty(&mut self, type_ref: TypeRefId) -> Ty {
-        self.make_ty(type_ref, &self.body.types)
+        self.make_ty(type_ref, &self.body.types, InferenceTyDiagnosticSource::Body)
     }
 
     fn err_ty(&self) -> Ty {
         self.result.standard_types.unknown.clone()
     }
 
-    fn make_lifetime(&mut self, lifetime_ref: &LifetimeRef) -> Lifetime {
-        let lt = self.with_ty_lowering(TypesMap::EMPTY, |ctx| ctx.lower_lifetime(lifetime_ref));
+    fn make_body_lifetime(&mut self, lifetime_ref: &LifetimeRef) -> Lifetime {
+        let lt = self.with_ty_lowering(TypesMap::EMPTY, InferenceTyDiagnosticSource::Body, |ctx| {
+            ctx.lower_lifetime(lifetime_ref)
+        });
         self.insert_type_vars(lt)
     }
 
@@ -1431,12 +1467,20 @@ impl<'a> InferenceContext<'a> {
                 Some(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,
+                        );
                         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,
+                        );
                         let ty = self.db.ty(strukt.into());
                         let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
                         return (ty, Some(strukt.into()));
@@ -1462,18 +1506,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);
                 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);
                 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);
                 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)
@@ -1519,6 +1566,9 @@ impl<'a> InferenceContext<'a> {
                         resolved_segment,
                         current_segment,
                         false,
+                        &mut |_, _reason| {
+                            // FIXME: Report an error.
+                        },
                     );
 
                     ty = self.table.insert_type_vars(ty);
@@ -1532,6 +1582,7 @@ impl<'a> InferenceContext<'a> {
                     remaining_idx += 1;
                     remaining_segments = remaining_segments.skip(1);
                 }
+                self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics);
 
                 let variant = ty.as_adt().and_then(|(id, _)| match id {
                     AdtId::StructId(s) => Some(VariantId::StructId(s)),
@@ -1550,6 +1601,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);
                 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/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
index 32b4ea2f28b..e060b37f154 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
@@ -2155,7 +2155,7 @@ impl InferenceContext<'_> {
                                 DebruijnIndex::INNERMOST,
                             )
                         },
-                        |this, lt_ref| this.make_lifetime(lt_ref),
+                        |this, lt_ref| this.make_body_lifetime(lt_ref),
                     ),
                 };
 
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 7550d197a3b..a6296c3af23 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
@@ -19,7 +19,7 @@ use crate::{
     TyBuilder, TyExt, TyKind, ValueTyDefId,
 };
 
-use super::{ExprOrPatId, InferenceContext};
+use super::{ExprOrPatId, InferenceContext, InferenceTyDiagnosticSource};
 
 impl InferenceContext<'_> {
     pub(super) fn infer_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<Ty> {
@@ -163,6 +163,7 @@ impl InferenceContext<'_> {
 
             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);
             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)))?
@@ -265,6 +266,9 @@ impl InferenceContext<'_> {
                         resolved_segment,
                         remaining_segments_for_ty,
                         true,
+                        &mut |_, _reason| {
+                            // FIXME: Report an error.
+                        },
                     )
                 });
                 if ty.is_unknown() {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
index fdc65797632..8bb90ca31e4 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -84,12 +84,14 @@ pub use infer::{
     cast::CastError,
     closure::{CaptureKind, CapturedItem},
     could_coerce, could_unify, could_unify_deeply, Adjust, Adjustment, AutoBorrow, BindingMode,
-    InferenceDiagnostic, InferenceResult, OverloadedDeref, PointerCast,
+    InferenceDiagnostic, InferenceResult, InferenceTyDiagnosticSource, OverloadedDeref,
+    PointerCast,
 };
 pub use interner::Interner;
 pub use lower::{
-    associated_type_shorthand_candidates, ImplTraitLoweringMode, ParamLoweringMode, TyDefId,
-    TyLoweringContext, ValueTyDefId,
+    associated_type_shorthand_candidates, GenericArgsProhibitedReason, ImplTraitLoweringMode,
+    ParamLoweringMode, TyDefId, TyLoweringContext, TyLoweringDiagnostic, TyLoweringDiagnosticKind,
+    ValueTyDefId,
 };
 pub use mapping::{
     from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
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 b868ea95f85..b23f2749ab2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -33,8 +33,8 @@ use hir_def::{
     path::{GenericArg, GenericArgs, ModPath, Path, PathKind, PathSegment, PathSegments},
     resolver::{HasResolver, LifetimeNs, Resolver, TypeNs},
     type_ref::{
-        ConstRef, LifetimeRef, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef,
-        TypeRefId, TypesMap, TypesSourceMap,
+        ConstRef, LifetimeRef, PathId, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound,
+        TypeRef, TypeRefId, TypesMap, TypesSourceMap,
     },
     AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId,
     FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstLoc, ItemContainerId,
@@ -48,7 +48,7 @@ use rustc_pattern_analysis::Captures;
 use smallvec::SmallVec;
 use stdx::{impl_from, never};
 use syntax::ast;
-use triomphe::Arc;
+use triomphe::{Arc, ThinArc};
 
 use crate::{
     all_super_traits,
@@ -102,6 +102,31 @@ impl ImplTraitLoweringState {
     }
 }
 
+type TypeSource = Either<TypeRefId, hir_def::type_ref::TypeSource>;
+
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub struct TyLoweringDiagnostic {
+    pub source: TypeSource,
+    pub kind: TyLoweringDiagnosticKind,
+}
+
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub enum TyLoweringDiagnosticKind {
+    GenericArgsProhibited { segment: u32, reason: GenericArgsProhibitedReason },
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum GenericArgsProhibitedReason {
+    Module,
+    TyParam,
+    SelfTy,
+    PrimitiveTy,
+    /// 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)]
 pub struct TyLoweringContext<'a> {
     pub db: &'a dyn HirDatabase,
@@ -125,6 +150,7 @@ pub struct TyLoweringContext<'a> {
     expander: Option<Expander>,
     /// Tracks types with explicit `?Sized` bounds.
     pub(crate) unsized_types: FxHashSet<Ty>,
+    pub(crate) diagnostics: Vec<TyLoweringDiagnostic>,
 }
 
 impl<'a> TyLoweringContext<'a> {
@@ -159,6 +185,7 @@ impl<'a> TyLoweringContext<'a> {
             type_param_mode,
             expander: None,
             unsized_types: FxHashSet::default(),
+            diagnostics: Vec::new(),
         }
     }
 
@@ -198,6 +225,20 @@ impl<'a> TyLoweringContext<'a> {
         self.type_param_mode = type_param_mode;
         self
     }
+
+    pub fn push_diagnostic(&mut self, type_ref: TypeRefId, kind: TyLoweringDiagnosticKind) {
+        let source = match self.types_source_map {
+            Some(source_map) => {
+                let Ok(source) = source_map.type_syntax(type_ref) else {
+                    stdx::never!("error in synthetic type");
+                    return;
+                };
+                Either::Right(source)
+            }
+            None => Either::Left(type_ref),
+        };
+        self.diagnostics.push(TyLoweringDiagnostic { source, kind });
+    }
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
@@ -264,7 +305,8 @@ impl<'a> TyLoweringContext<'a> {
                     .intern(Interner)
             }
             TypeRef::Path(path) => {
-                let (ty, res_) = self.lower_path(path);
+                let (ty, res_) =
+                    self.lower_path(path, PathId::from_type_ref_unchecked(type_ref_id));
                 res = res_;
                 ty
             }
@@ -463,6 +505,7 @@ impl<'a> TyLoweringContext<'a> {
                                 impl_trait_mode: mem::take(&mut self.impl_trait_mode),
                                 expander: self.expander.take(),
                                 unsized_types: mem::take(&mut self.unsized_types),
+                                diagnostics: mem::take(&mut self.diagnostics),
                             };
 
                             let ty = inner_ctx.lower_ty(type_ref);
@@ -470,6 +513,7 @@ impl<'a> TyLoweringContext<'a> {
                             self.impl_trait_mode = inner_ctx.impl_trait_mode;
                             self.expander = inner_ctx.expander;
                             self.unsized_types = inner_ctx.unsized_types;
+                            self.diagnostics = inner_ctx.diagnostics;
 
                             self.expander.as_mut().unwrap().exit(mark);
                             Some(ty)
@@ -541,6 +585,10 @@ impl<'a> TyLoweringContext<'a> {
         resolved_segment: PathSegment<'_>,
         remaining_segments: PathSegments<'_>,
         infer_args: bool,
+        on_prohibited_generics_for_resolved_segment: &mut dyn FnMut(
+            &mut Self,
+            GenericArgsProhibitedReason,
+        ),
     ) -> (Ty, Option<TypeNs>) {
         let ty = match resolution {
             TypeNs::TraitId(trait_) => {
@@ -607,28 +655,44 @@ impl<'a> TyLoweringContext<'a> {
                 // FIXME(trait_alias): Implement trait alias.
                 return (TyKind::Error.intern(Interner), None);
             }
-            TypeNs::GenericParam(param_id) => match self.type_param_mode {
-                ParamLoweringMode::Placeholder => {
-                    TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into()))
+            TypeNs::GenericParam(param_id) => {
+                if resolved_segment.args_and_bindings.is_some() {
+                    on_prohibited_generics_for_resolved_segment(
+                        self,
+                        GenericArgsProhibitedReason::TyParam,
+                    );
                 }
-                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))
+                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))
+                    }
                 }
+                .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 {
@@ -654,6 +718,13 @@ 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),
@@ -666,6 +737,12 @@ 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) => {
@@ -677,7 +754,7 @@ impl<'a> TyLoweringContext<'a> {
         self.lower_ty_relative_path(ty, Some(resolution), remaining_segments)
     }
 
-    pub(crate) fn lower_path(&mut self, path: &Path) -> (Ty, Option<TypeNs>) {
+    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() {
             let (ty, res) = self.lower_ty_ext(type_ref);
@@ -692,19 +769,44 @@ impl<'a> TyLoweringContext<'a> {
 
         if matches!(resolution, TypeNs::TraitId(_)) && remaining_index.is_none() {
             // trait object type without dyn
-            let bound = TypeBound::Path(path.clone(), TraitBoundModifier::None);
+            let bound = TypeBound::Path(path_id, TraitBoundModifier::None);
             let ty = self.lower_dyn_trait(&[bound]);
             return (ty, None);
         }
 
-        let (resolved_segment, remaining_segments) = match remaining_index {
-            None => (
-                path.segments().last().expect("resolved path has at least one element"),
-                PathSegments::EMPTY,
-            ),
-            Some(i) => (path.segments().get(i - 1).unwrap(), path.segments().skip(i)),
-        };
-        self.lower_partly_resolved_path(resolution, resolved_segment, remaining_segments, false)
+        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);
+
+        self.lower_partly_resolved_path(
+            resolution,
+            resolved_segment,
+            remaining_segments,
+            false,
+            &mut |this, reason| {
+                this.push_diagnostic(
+                    path_id.type_ref(),
+                    TyLoweringDiagnosticKind::GenericArgsProhibited {
+                        segment: resolved_segment_idx as u32,
+                        reason,
+                    },
+                )
+            },
+        )
     }
 
     fn select_associated_type(&mut self, res: Option<TypeNs>, segment: PathSegment<'_>) -> Ty {
@@ -741,12 +843,8 @@ impl<'a> TyLoweringContext<'a> {
                 // generic params. It's inefficient to splice the `Substitution`s, so we may want
                 // that method to optionally take parent `Substitution` as we already know them at
                 // this point (`t.substitution`).
-                let substs = self.substs_from_path_segment(
-                    segment.clone(),
-                    Some(associated_ty.into()),
-                    false,
-                    None,
-                );
+                let substs =
+                    self.substs_from_path_segment(segment, Some(associated_ty.into()), false, None);
 
                 let len_self =
                     crate::generics::generics(self.db.upcast(), associated_ty.into()).len_self();
@@ -998,12 +1096,41 @@ impl<'a> TyLoweringContext<'a> {
         TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs }
     }
 
-    fn lower_trait_ref_from_path(&mut self, path: &Path, explicit_self_ty: Ty) -> Option<TraitRef> {
+    fn prohibit_generics(
+        &mut self,
+        path_id: PathId,
+        idx: u32,
+        segments: PathSegments<'_>,
+        reason: GenericArgsProhibitedReason,
+    ) {
+        segments.iter().zip(idx..).for_each(|(segment, idx)| {
+            if segment.args_and_bindings.is_some() {
+                self.push_diagnostic(
+                    path_id.type_ref(),
+                    TyLoweringDiagnosticKind::GenericArgsProhibited { segment: idx, reason },
+                );
+            }
+        });
+    }
+
+    fn lower_trait_ref_from_path(
+        &mut self,
+        path_id: PathId,
+        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)? {
             // FIXME(trait_alias): We need to handle trait alias here.
             TypeNs::TraitId(tr) => tr,
             _ => return None,
         };
+        // Do this after we verify it's indeed a trait to not confuse the user if they're not modules.
+        self.prohibit_generics(
+            path_id,
+            0,
+            path.segments().strip_last(),
+            GenericArgsProhibitedReason::Module,
+        );
         let segment = path.segments().last().expect("path should have at least one segment");
         Some(self.lower_trait_ref_from_resolved_path(resolved, segment, explicit_self_ty))
     }
@@ -1013,7 +1140,7 @@ impl<'a> TyLoweringContext<'a> {
         trait_ref: &HirTraitRef,
         explicit_self_ty: Ty,
     ) -> Option<TraitRef> {
-        self.lower_trait_ref_from_path(&trait_ref.path, explicit_self_ty)
+        self.lower_trait_ref_from_path(trait_ref.path, explicit_self_ty)
     }
 
     fn trait_ref_substs_from_path(
@@ -1072,11 +1199,11 @@ impl<'a> TyLoweringContext<'a> {
     ) -> impl Iterator<Item = QuantifiedWhereClause> + use<'b, 'a> {
         let mut trait_ref = None;
         let clause = match bound {
-            TypeBound::Path(path, TraitBoundModifier::None) => {
+            &TypeBound::Path(path, TraitBoundModifier::None) => {
                 trait_ref = self.lower_trait_ref_from_path(path, self_ty);
                 trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
             }
-            TypeBound::Path(path, TraitBoundModifier::Maybe) => {
+            &TypeBound::Path(path, TraitBoundModifier::Maybe) => {
                 let sized_trait = self
                     .db
                     .lang_item(self.resolver.krate(), LangItem::Sized)
@@ -1092,7 +1219,7 @@ impl<'a> TyLoweringContext<'a> {
                 }
                 None
             }
-            TypeBound::ForLifetime(_, path) => {
+            &TypeBound::ForLifetime(_, path) => {
                 // FIXME Don't silently drop the hrtb lifetimes here
                 trait_ref = self.lower_trait_ref_from_path(path, self_ty);
                 trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
@@ -1121,8 +1248,8 @@ impl<'a> TyLoweringContext<'a> {
         trait_ref: TraitRef,
     ) -> impl Iterator<Item = QuantifiedWhereClause> + use<'b, 'a> {
         let last_segment = match bound {
-            TypeBound::Path(path, TraitBoundModifier::None) | TypeBound::ForLifetime(_, path) => {
-                path.segments().last()
+            &TypeBound::Path(path, TraitBoundModifier::None) | &TypeBound::ForLifetime(_, path) => {
+                self.types_map[path].segments().last()
             }
             TypeBound::Path(_, TraitBoundModifier::Maybe)
             | TypeBound::Use(_)
@@ -1227,7 +1354,9 @@ impl<'a> TyLoweringContext<'a> {
                                     }
                                     _ => unreachable!(),
                                 }
-                                ext.lower_ty(type_ref)
+                                let ty = ext.lower_ty(type_ref);
+                                self.diagnostics.extend(ext.diagnostics);
+                                ty
                             } else {
                                 self.lower_ty(type_ref)
                             };
@@ -1523,11 +1652,24 @@ fn named_associated_type_shorthand_candidates<R>(
     }
 }
 
-/// Build the type of all specific fields of a struct or enum variant.
+pub(crate) type Diagnostics = Option<ThinArc<(), TyLoweringDiagnostic>>;
+
+fn create_diagnostics(diagnostics: Vec<TyLoweringDiagnostic>) -> Diagnostics {
+    (!diagnostics.is_empty()).then(|| ThinArc::from_header_and_iter((), diagnostics.into_iter()))
+}
+
 pub(crate) fn field_types_query(
     db: &dyn HirDatabase,
     variant_id: VariantId,
 ) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>> {
+    db.field_types_with_diagnostics(variant_id).0
+}
+
+/// Build the type of all specific fields of a struct or enum variant.
+pub(crate) fn field_types_with_diagnostics_query(
+    db: &dyn HirDatabase,
+    variant_id: VariantId,
+) -> (Arc<ArenaMap<LocalFieldId, Binders<Ty>>>, Diagnostics) {
     let var_data = variant_id.variant_data(db.upcast());
     let (resolver, def): (_, GenericDefId) = match variant_id {
         VariantId::StructId(it) => (it.resolver(db.upcast()), it.into()),
@@ -1543,7 +1685,7 @@ pub(crate) fn field_types_query(
     for (field_id, field_data) in var_data.fields().iter() {
         res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(field_data.type_ref)));
     }
-    Arc::new(res)
+    (Arc::new(res), create_diagnostics(ctx.diagnostics))
 }
 
 /// This query exists only to be used when resolving short-hand associated types
@@ -1593,9 +1735,10 @@ pub(crate) fn generic_predicates_for_param_query(
             }
 
             match bound {
-                TypeBound::ForLifetime(_, path) | TypeBound::Path(path, _) => {
+                &TypeBound::ForLifetime(_, path) | &TypeBound::Path(path, _) => {
                     // Only lower the bound if the trait could possibly define the associated
                     // type we're looking for.
+                    let path = &ctx.types_map[path];
 
                     let Some(assoc_name) = &assoc_name else { return true };
                     let Some(TypeNs::TraitId(tr)) =
@@ -1743,15 +1886,22 @@ pub(crate) fn generic_predicates_query(
     db: &dyn HirDatabase,
     def: GenericDefId,
 ) -> GenericPredicates {
-    generic_predicates_filtered_by(db, def, |_, _| true)
+    generic_predicates_filtered_by(db, def, |_, _| true).0
 }
 
-/// Resolve the where clause(s) of an item with generics,
-/// except the ones inherited from the parent
 pub(crate) fn generic_predicates_without_parent_query(
     db: &dyn HirDatabase,
     def: GenericDefId,
 ) -> GenericPredicates {
+    db.generic_predicates_without_parent_with_diagnostics(def).0
+}
+
+/// Resolve the where clause(s) of an item with generics,
+/// except the ones inherited from the parent
+pub(crate) fn generic_predicates_without_parent_with_diagnostics_query(
+    db: &dyn HirDatabase,
+    def: GenericDefId,
+) -> (GenericPredicates, Diagnostics) {
     generic_predicates_filtered_by(db, def, |_, d| *d == def)
 }
 
@@ -1761,7 +1911,7 @@ fn generic_predicates_filtered_by<F>(
     db: &dyn HirDatabase,
     def: GenericDefId,
     filter: F,
-) -> GenericPredicates
+) -> (GenericPredicates, Diagnostics)
 where
     F: Fn(&WherePredicate, &GenericDefId) -> bool,
 {
@@ -1802,7 +1952,10 @@ where
             );
         };
     }
-    GenericPredicates(predicates.is_empty().not().then(|| predicates.into()))
+    (
+        GenericPredicates(predicates.is_empty().not().then(|| predicates.into())),
+        create_diagnostics(ctx.diagnostics),
+    )
 }
 
 /// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound.
@@ -1855,75 +2008,110 @@ impl ops::Deref for GenericDefaults {
     }
 }
 
-/// Resolve the default type params from generics
 pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) -> GenericDefaults {
+    db.generic_defaults_with_diagnostics(def).0
+}
+
+/// Resolve the default type params from generics.
+///
+/// Diagnostics are only returned for this `GenericDefId` (returned defaults include parents).
+pub(crate) fn generic_defaults_with_diagnostics_query(
+    db: &dyn HirDatabase,
+    def: GenericDefId,
+) -> (GenericDefaults, Diagnostics) {
     let generic_params = generics(db.upcast(), def);
     if generic_params.len() == 0 {
-        return GenericDefaults(None);
+        return (GenericDefaults(None), None);
     }
     let resolver = def.resolver(db.upcast());
     let parent_start_idx = generic_params.len_self();
 
-    let mut ctx = TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
-        .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed)
-        .with_type_param_mode(ParamLoweringMode::Variable);
-    GenericDefaults(Some(Arc::from_iter(generic_params.iter_with_types_map().enumerate().map(
-        |(idx, ((id, p), types_map))| {
-            ctx.types_map = types_map;
-            match p {
-                GenericParamDataRef::TypeParamData(p) => {
-                    let ty = p.default.as_ref().map_or(TyKind::Error.intern(Interner), |ty| {
-                        // Each default can only refer to previous parameters.
-                        // Type variable default referring to parameter coming
-                        // after it is forbidden (FIXME: report diagnostic)
-                        fallback_bound_vars(ctx.lower_ty(*ty), idx, parent_start_idx)
-                    });
-                    crate::make_binders(db, &generic_params, ty.cast(Interner))
-                }
-                GenericParamDataRef::ConstParamData(p) => {
-                    let GenericParamId::ConstParamId(id) = id else {
-                        unreachable!("Unexpected lifetime or type argument")
-                    };
+    let mut ctx =
+        TyLoweringContext::new(db, &resolver, generic_params.self_types_map(), def.into())
+            .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed)
+            .with_type_param_mode(ParamLoweringMode::Variable);
+    let mut idx = 0;
+    let mut defaults = generic_params
+        .iter_self()
+        .map(|(id, p)| {
+            let result =
+                handle_generic_param(&mut ctx, idx, id, p, parent_start_idx, &generic_params);
+            idx += 1;
+            result
+        })
+        .collect::<Vec<_>>();
+    let diagnostics = create_diagnostics(mem::take(&mut ctx.diagnostics));
+    defaults.extend(generic_params.iter_parents_with_types_map().map(|((id, p), types_map)| {
+        ctx.types_map = types_map;
+        let result = handle_generic_param(&mut ctx, idx, id, p, parent_start_idx, &generic_params);
+        idx += 1;
+        result
+    }));
+    let defaults = GenericDefaults(Some(Arc::from_iter(defaults)));
+    return (defaults, diagnostics);
+
+    fn handle_generic_param(
+        ctx: &mut TyLoweringContext<'_>,
+        idx: usize,
+        id: GenericParamId,
+        p: GenericParamDataRef<'_>,
+        parent_start_idx: usize,
+        generic_params: &Generics,
+    ) -> Binders<crate::GenericArg> {
+        match p {
+            GenericParamDataRef::TypeParamData(p) => {
+                let ty = p.default.as_ref().map_or(TyKind::Error.intern(Interner), |ty| {
+                    // Each default can only refer to previous parameters.
+                    // Type variable default referring to parameter coming
+                    // after it is forbidden (FIXME: report diagnostic)
+                    fallback_bound_vars(ctx.lower_ty(*ty), idx, parent_start_idx)
+                });
+                crate::make_binders(ctx.db, generic_params, ty.cast(Interner))
+            }
+            GenericParamDataRef::ConstParamData(p) => {
+                let GenericParamId::ConstParamId(id) = id else {
+                    unreachable!("Unexpected lifetime or type argument")
+                };
 
-                    let mut val = p.default.as_ref().map_or_else(
-                        || unknown_const_as_generic(db.const_param_ty(id)),
-                        |c| {
-                            let param_ty = ctx.lower_ty(p.ty);
-                            let c = ctx.lower_const(c, param_ty);
-                            c.cast(Interner)
-                        },
-                    );
-                    // Each default can only refer to previous parameters, see above.
-                    val = fallback_bound_vars(val, idx, parent_start_idx);
-                    make_binders(db, &generic_params, val)
-                }
-                GenericParamDataRef::LifetimeParamData(_) => {
-                    make_binders(db, &generic_params, error_lifetime().cast(Interner))
-                }
+                let mut val = p.default.as_ref().map_or_else(
+                    || unknown_const_as_generic(ctx.db.const_param_ty(id)),
+                    |c| {
+                        let param_ty = ctx.lower_ty(p.ty);
+                        let c = ctx.lower_const(c, param_ty);
+                        c.cast(Interner)
+                    },
+                );
+                // Each default can only refer to previous parameters, see above.
+                val = fallback_bound_vars(val, idx, parent_start_idx);
+                make_binders(ctx.db, generic_params, val)
             }
-        },
-    ))))
+            GenericParamDataRef::LifetimeParamData(_) => {
+                make_binders(ctx.db, generic_params, error_lifetime().cast(Interner))
+            }
+        }
+    }
 }
 
-pub(crate) fn generic_defaults_recover(
+pub(crate) fn generic_defaults_with_diagnostics_recover(
     db: &dyn HirDatabase,
     _cycle: &Cycle,
     def: &GenericDefId,
-) -> GenericDefaults {
+) -> (GenericDefaults, Diagnostics) {
     let generic_params = generics(db.upcast(), *def);
     if generic_params.len() == 0 {
-        return GenericDefaults(None);
+        return (GenericDefaults(None), None);
     }
     // FIXME: this code is not covered in tests.
     // we still need one default per parameter
-    GenericDefaults(Some(Arc::from_iter(generic_params.iter_id().map(|id| {
+    let defaults = GenericDefaults(Some(Arc::from_iter(generic_params.iter_id().map(|id| {
         let val = match id {
             GenericParamId::TypeParamId(_) => TyKind::Error.intern(Interner).cast(Interner),
             GenericParamId::ConstParamId(id) => unknown_const_as_generic(db.const_param_ty(id)),
             GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner),
         };
         crate::make_binders(db, &generic_params, val)
-    }))))
+    }))));
+    (defaults, None)
 }
 
 fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
@@ -2066,7 +2254,10 @@ fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
     make_binders(db, &generics, ty)
 }
 
-fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
+pub(crate) fn type_for_type_alias_with_diagnostics_query(
+    db: &dyn HirDatabase,
+    t: TypeAliasId,
+) -> (Binders<Ty>, Diagnostics) {
     let generics = generics(db.upcast(), t.into());
     let resolver = t.resolver(db.upcast());
     let type_alias_data = db.type_alias_data(t);
@@ -2081,7 +2272,7 @@ fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
             .map(|type_ref| ctx.lower_ty(type_ref))
             .unwrap_or_else(|| TyKind::Error.intern(Interner))
     };
-    make_binders(db, &generics, inner)
+    (make_binders(db, &generics, inner), create_diagnostics(ctx.diagnostics))
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -2124,7 +2315,7 @@ pub(crate) fn ty_query(db: &dyn HirDatabase, def: TyDefId) -> Binders<Ty> {
     match def {
         TyDefId::BuiltinType(it) => Binders::empty(Interner, TyBuilder::builtin(it)),
         TyDefId::AdtId(it) => type_for_adt(db, it),
-        TyDefId::TypeAliasId(it) => type_for_type_alias(db, it),
+        TyDefId::TypeAliasId(it) => db.type_for_type_alias_with_diagnostics(it).0,
     }
 }
 
@@ -2149,47 +2340,73 @@ pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Option<
 }
 
 pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binders<Ty> {
+    db.impl_self_ty_with_diagnostics(impl_id).0
+}
+
+pub(crate) fn impl_self_ty_with_diagnostics_query(
+    db: &dyn HirDatabase,
+    impl_id: ImplId,
+) -> (Binders<Ty>, Diagnostics) {
     let impl_data = db.impl_data(impl_id);
     let resolver = impl_id.resolver(db.upcast());
     let generics = generics(db.upcast(), impl_id.into());
     let mut ctx = TyLoweringContext::new(db, &resolver, &impl_data.types_map, impl_id.into())
         .with_type_param_mode(ParamLoweringMode::Variable);
-    make_binders(db, &generics, ctx.lower_ty(impl_data.self_ty))
+    (
+        make_binders(db, &generics, ctx.lower_ty(impl_data.self_ty)),
+        create_diagnostics(ctx.diagnostics),
+    )
 }
 
-// returns None if def is a type arg
 pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty {
+    db.const_param_ty_with_diagnostics(def).0
+}
+
+// returns None if def is a type arg
+pub(crate) fn const_param_ty_with_diagnostics_query(
+    db: &dyn HirDatabase,
+    def: ConstParamId,
+) -> (Ty, Diagnostics) {
     let parent_data = db.generic_params(def.parent());
     let data = &parent_data[def.local_id()];
     let resolver = def.parent().resolver(db.upcast());
     let mut ctx =
         TyLoweringContext::new(db, &resolver, &parent_data.types_map, def.parent().into());
-    match data {
+    let ty = match data {
         TypeOrConstParamData::TypeParamData(_) => {
             never!();
             Ty::new(Interner, TyKind::Error)
         }
         TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(d.ty),
-    }
+    };
+    (ty, create_diagnostics(ctx.diagnostics))
 }
 
-pub(crate) fn impl_self_ty_recover(
+pub(crate) fn impl_self_ty_with_diagnostics_recover(
     db: &dyn HirDatabase,
     _cycle: &Cycle,
     impl_id: &ImplId,
-) -> Binders<Ty> {
+) -> (Binders<Ty>, Diagnostics) {
     let generics = generics(db.upcast(), (*impl_id).into());
-    make_binders(db, &generics, TyKind::Error.intern(Interner))
+    (make_binders(db, &generics, TyKind::Error.intern(Interner)), None)
 }
 
 pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> {
+    db.impl_trait_with_diagnostics(impl_id).map(|it| it.0)
+}
+
+pub(crate) fn impl_trait_with_diagnostics_query(
+    db: &dyn HirDatabase,
+    impl_id: ImplId,
+) -> Option<(Binders<TraitRef>, Diagnostics)> {
     let impl_data = db.impl_data(impl_id);
     let resolver = impl_id.resolver(db.upcast());
     let mut ctx = TyLoweringContext::new(db, &resolver, &impl_data.types_map, impl_id.into())
         .with_type_param_mode(ParamLoweringMode::Variable);
     let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders();
     let target_trait = impl_data.target_trait.as_ref()?;
-    Some(Binders::new(binders, ctx.lower_trait_ref(target_trait, self_ty)?))
+    let trait_ref = Binders::new(binders, ctx.lower_trait_ref(target_trait, self_ty)?);
+    Some((trait_ref, create_diagnostics(ctx.diagnostics)))
 }
 
 pub(crate) fn return_type_impl_traits(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
index bcf9d5ceff0..cabeeea2bd8 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
@@ -18,13 +18,13 @@ use std::sync::LazyLock;
 use base_db::SourceDatabaseFileInputExt as _;
 use expect_test::Expect;
 use hir_def::{
-    body::{Body, BodySourceMap, SyntheticSyntax},
+    body::{Body, BodySourceMap},
     db::DefDatabase,
     hir::{ExprId, Pat, PatId},
     item_scope::ItemScope,
     nameres::DefMap,
     src::HasSource,
-    AssocItemId, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleDefId,
+    AssocItemId, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleDefId, SyntheticSyntax,
 };
 use hir_expand::{db::ExpandDatabase, FileRange, InFile};
 use itertools::Itertools;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
index 28bda1e10e5..06719b09f73 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
@@ -185,7 +185,7 @@ fn direct_super_traits_cb(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(
                     }
                 };
                 match is_trait {
-                    true => bound.as_path(),
+                    true => bound.as_path(&generic_params.types_map),
                     false => None,
                 }
             }
diff --git a/src/tools/rust-analyzer/crates/hir/Cargo.toml b/src/tools/rust-analyzer/crates/hir/Cargo.toml
index 26666d6feb0..6aadc5c4f7e 100644
--- a/src/tools/rust-analyzer/crates/hir/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir/Cargo.toml
@@ -33,6 +33,14 @@ syntax.workspace = true
 tt.workspace = true
 span.workspace = true
 
+[dev-dependencies]
+expect-test.workspace = true
+
+# local deps
+test-utils.workspace = true
+test-fixture.workspace = true
+syntax-bridge.workspace = true
+
 [features]
 in-rust-tree = ["hir-expand/in-rust-tree"]
 
diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
index 9ca021027d5..612c6adb207 100644
--- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
@@ -3,23 +3,35 @@
 //!
 //! This probably isn't the best way to do this -- ideally, diagnostics should
 //! be expressed in terms of hir types themselves.
-pub use hir_ty::diagnostics::{CaseType, IncorrectCase};
+use cfg::{CfgExpr, CfgOptions};
+use either::Either;
+use hir_def::{
+    hir::ExprOrPatId,
+    path::{hir_segment_to_ast_segment, ModPath},
+    type_ref::TypesSourceMap,
+    AssocItemId, DefWithBodyId, SyntheticSyntax,
+};
+use hir_expand::{name::Name, HirFileId, InFile};
 use hir_ty::{
     db::HirDatabase,
     diagnostics::{BodyValidationDiagnostic, UnsafetyReason},
-    CastError, InferenceDiagnostic,
+    CastError, InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringDiagnostic,
+    TyLoweringDiagnosticKind,
+};
+use syntax::{
+    ast::{self, HasGenericArgs},
+    AstPtr, SyntaxError, SyntaxNodePtr, TextRange,
 };
-
-use cfg::{CfgExpr, CfgOptions};
-use either::Either;
-pub use hir_def::VariantId;
-use hir_def::{body::SyntheticSyntax, hir::ExprOrPatId, path::ModPath, AssocItemId, DefWithBodyId};
-use hir_expand::{name::Name, HirFileId, InFile};
-use syntax::{ast, AstPtr, SyntaxError, SyntaxNodePtr, TextRange};
 use triomphe::Arc;
 
 use crate::{AssocItem, Field, Local, Trait, Type};
 
+pub use hir_def::VariantId;
+pub use hir_ty::{
+    diagnostics::{CaseType, IncorrectCase},
+    GenericArgsProhibitedReason,
+};
+
 macro_rules! diagnostics {
     ($($diag:ident,)*) => {
         #[derive(Debug)]
@@ -98,6 +110,7 @@ diagnostics![
     UnresolvedIdent,
     UnusedMut,
     UnusedVariable,
+    GenericArgsProhibited,
 ];
 
 #[derive(Debug)]
@@ -388,6 +401,12 @@ pub struct InvalidCast {
     pub cast_ty: Type,
 }
 
+#[derive(Debug)]
+pub struct GenericArgsProhibited {
+    pub args: InFile<AstPtr<Either<ast::GenericArgList, ast::ParenthesizedArgList>>>,
+    pub reason: GenericArgsProhibitedReason,
+}
+
 impl AnyDiagnostic {
     pub(crate) fn body_validation_diagnostic(
         db: &dyn HirDatabase,
@@ -527,6 +546,7 @@ impl AnyDiagnostic {
         db: &dyn HirDatabase,
         def: DefWithBodyId,
         d: &InferenceDiagnostic,
+        outer_types_source_map: &TypesSourceMap,
         source_map: &hir_def::body::BodySourceMap,
     ) -> Option<AnyDiagnostic> {
         let expr_syntax = |expr| {
@@ -640,6 +660,44 @@ impl AnyDiagnostic {
                 let cast_ty = Type::new(db, def, cast_ty.clone());
                 InvalidCast { expr, error: *error, expr_ty, cast_ty }.into()
             }
+            InferenceDiagnostic::TyDiagnostic { source, diag } => {
+                let source_map = match source {
+                    InferenceTyDiagnosticSource::Body => &source_map.types,
+                    InferenceTyDiagnosticSource::Signature => outer_types_source_map,
+                };
+                Self::ty_diagnostic(diag, source_map, db)?
+            }
+        })
+    }
+
+    pub(crate) fn ty_diagnostic(
+        diag: &TyLoweringDiagnostic,
+        source_map: &TypesSourceMap,
+        db: &dyn HirDatabase,
+    ) -> Option<AnyDiagnostic> {
+        let source = match diag.source {
+            Either::Left(type_ref_id) => {
+                let Ok(source) = source_map.type_syntax(type_ref_id) else {
+                    stdx::never!("error on synthetic type syntax");
+                    return None;
+                };
+                source
+            }
+            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 } => {
+                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()
+            }
         })
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs
index 9275f45d881..959d62d5951 100644
--- a/src/tools/rust-analyzer/crates/hir/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/display.rs
@@ -132,12 +132,18 @@ impl HirDisplay for Function {
         } else {
             match &data.types_map[data.ret_type] {
                 TypeRef::ImplTrait(bounds) => match &bounds[0] {
-                    TypeBound::Path(path, _) => Some(
-                        *path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings
-                            [0]
-                        .type_ref
-                        .as_ref()
-                        .unwrap(),
+                    &TypeBound::Path(path, _) => Some(
+                        *data.types_map[path]
+                            .segments()
+                            .iter()
+                            .last()
+                            .unwrap()
+                            .args_and_bindings
+                            .unwrap()
+                            .bindings[0]
+                            .type_ref
+                            .as_ref()
+                            .unwrap(),
                     ),
                     _ => None,
                 },
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index 0b2ba56b1ff..10365ba0028 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -20,12 +20,11 @@
 #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
 #![recursion_limit = "512"]
 
-mod semantics;
-mod source_analyzer;
-
 mod attrs;
 mod from_id;
 mod has_source;
+mod semantics;
+mod source_analyzer;
 
 pub mod db;
 pub mod diagnostics;
@@ -43,7 +42,7 @@ use arrayvec::ArrayVec;
 use base_db::{CrateDisplayName, CrateId, CrateOrigin};
 use either::Either;
 use hir_def::{
-    body::{BodyDiagnostic, SyntheticSyntax},
+    body::BodyDiagnostic,
     data::adt::VariantData,
     generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance},
     hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, Pat},
@@ -54,11 +53,12 @@ use hir_def::{
     path::ImportAlias,
     per_ns::PerNs,
     resolver::{HasResolver, Resolver},
+    type_ref::TypesSourceMap,
     AssocItemId, AssocItemLoc, AttrDefId, CallableDefId, ConstId, ConstParamId, CrateRootModuleId,
     DefWithBodyId, EnumId, EnumVariantId, ExternCrateId, FunctionId, GenericDefId, GenericParamId,
     HasModule, ImplId, InTypeConstId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup,
-    MacroExpander, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TupleId, TypeAliasId,
-    TypeOrConstParamId, TypeParamId, UnionId,
+    MacroExpander, ModuleId, StaticId, StructId, SyntheticSyntax, TraitAliasId, TraitId, TupleId,
+    TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId,
 };
 use hir_expand::{
     attrs::collect_attrs, proc_macro::ProcMacroKind, AstId, MacroCallKind, RenderedExpandError,
@@ -76,8 +76,8 @@ use hir_ty::{
     traits::FnTrait,
     AliasTy, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArg,
     GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution,
-    TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, ValueTyDefId,
-    WhereClause,
+    TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, TyLoweringDiagnostic,
+    ValueTyDefId, WhereClause,
 };
 use itertools::Itertools;
 use nameres::diagnostics::DefDiagnosticKind;
@@ -89,7 +89,7 @@ use syntax::{
     ast::{self, HasAttrs as _, HasGenericParams, HasName},
     format_smolstr, AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, TextRange, ToSmolStr, T,
 };
-use triomphe::Arc;
+use triomphe::{Arc, ThinArc};
 
 use crate::db::{DefDatabase, HirDatabase};
 
@@ -411,6 +411,10 @@ impl ModuleDef {
             }
         }
 
+        if let Some(def) = self.as_self_generic_def() {
+            def.diagnostics(db, &mut acc);
+        }
+
         acc
     }
 
@@ -431,6 +435,23 @@ impl ModuleDef {
         }
     }
 
+    /// Returns only defs that have generics from themselves, not their parent.
+    pub fn as_self_generic_def(self) -> Option<GenericDef> {
+        match self {
+            ModuleDef::Function(it) => Some(it.into()),
+            ModuleDef::Adt(it) => Some(it.into()),
+            ModuleDef::Trait(it) => Some(it.into()),
+            ModuleDef::TraitAlias(it) => Some(it.into()),
+            ModuleDef::TypeAlias(it) => Some(it.into()),
+            ModuleDef::Module(_)
+            | ModuleDef::Variant(_)
+            | ModuleDef::Static(_)
+            | ModuleDef::Const(_)
+            | ModuleDef::BuiltinType(_)
+            | ModuleDef::Macro(_) => None,
+        }
+    }
+
     pub fn attrs(&self, db: &dyn HirDatabase) -> Option<AttrsWithOwner> {
         Some(match self {
             ModuleDef::Module(it) => it.attrs(db),
@@ -605,17 +626,42 @@ impl Module {
                 ModuleDef::Adt(adt) => {
                     match adt {
                         Adt::Struct(s) => {
+                            let tree_id = s.id.lookup(db.upcast()).id;
+                            let tree_source_maps = tree_id.item_tree_with_source_map(db.upcast()).1;
+                            push_ty_diagnostics(
+                                db,
+                                acc,
+                                db.field_types_with_diagnostics(s.id.into()).1,
+                                tree_source_maps.strukt(tree_id.value).item(),
+                            );
                             for diag in db.struct_data_with_diagnostics(s.id).1.iter() {
                                 emit_def_diagnostic(db, acc, diag, edition);
                             }
                         }
                         Adt::Union(u) => {
+                            let tree_id = u.id.lookup(db.upcast()).id;
+                            let tree_source_maps = tree_id.item_tree_with_source_map(db.upcast()).1;
+                            push_ty_diagnostics(
+                                db,
+                                acc,
+                                db.field_types_with_diagnostics(u.id.into()).1,
+                                tree_source_maps.union(tree_id.value).item(),
+                            );
                             for diag in db.union_data_with_diagnostics(u.id).1.iter() {
                                 emit_def_diagnostic(db, acc, diag, edition);
                             }
                         }
                         Adt::Enum(e) => {
                             for v in e.variants(db) {
+                                let tree_id = v.id.lookup(db.upcast()).id;
+                                let tree_source_maps =
+                                    tree_id.item_tree_with_source_map(db.upcast()).1;
+                                push_ty_diagnostics(
+                                    db,
+                                    acc,
+                                    db.field_types_with_diagnostics(v.id.into()).1,
+                                    tree_source_maps.variant(tree_id.value),
+                                );
                                 acc.extend(ModuleDef::Variant(v).diagnostics(db, style_lints));
                                 for diag in db.enum_variant_data_with_diagnostics(v.id).1.iter() {
                                     emit_def_diagnostic(db, acc, diag, edition);
@@ -626,6 +672,17 @@ impl Module {
                     acc.extend(def.diagnostics(db, style_lints))
                 }
                 ModuleDef::Macro(m) => emit_macro_def_diagnostics(db, acc, m),
+                ModuleDef::TypeAlias(type_alias) => {
+                    let tree_id = type_alias.id.lookup(db.upcast()).id;
+                    let tree_source_maps = tree_id.item_tree_with_source_map(db.upcast()).1;
+                    push_ty_diagnostics(
+                        db,
+                        acc,
+                        db.type_for_type_alias_with_diagnostics(type_alias.id).1,
+                        tree_source_maps.type_alias(tree_id.value).item(),
+                    );
+                    acc.extend(def.diagnostics(db, style_lints));
+                }
                 _ => acc.extend(def.diagnostics(db, style_lints)),
             }
         }
@@ -635,8 +692,11 @@ impl Module {
 
         let mut impl_assoc_items_scratch = vec![];
         for impl_def in self.impl_defs(db) {
+            GenericDef::Impl(impl_def).diagnostics(db, acc);
+
             let loc = impl_def.id.lookup(db.upcast());
-            let tree = loc.id.item_tree(db.upcast());
+            let (tree, tree_source_maps) = loc.id.item_tree_with_source_map(db.upcast());
+            let source_map = tree_source_maps.impl_(loc.id.value).item();
             let node = &tree[loc.id.value];
             let file_id = loc.id.file_id();
             if file_id.macro_file().map_or(false, |it| it.is_builtin_derive(db.upcast())) {
@@ -771,6 +831,19 @@ impl Module {
                 impl_assoc_items_scratch.clear();
             }
 
+            push_ty_diagnostics(
+                db,
+                acc,
+                db.impl_self_ty_with_diagnostics(impl_def.id).1,
+                source_map,
+            );
+            push_ty_diagnostics(
+                db,
+                acc,
+                db.impl_trait_with_diagnostics(impl_def.id).and_then(|it| it.1),
+                source_map,
+            );
+
             for &item in db.impl_data(impl_def.id).items.iter() {
                 AssocItem::from(item).diagnostics(db, acc, style_lints);
             }
@@ -1802,6 +1875,25 @@ impl DefWithBody {
         let krate = self.module(db).id.krate();
 
         let (body, source_map) = db.body_with_source_map(self.into());
+        let item_tree_source_maps;
+        let outer_types_source_map = match self {
+            DefWithBody::Function(function) => {
+                let function = function.id.lookup(db.upcast()).id;
+                item_tree_source_maps = function.item_tree_with_source_map(db.upcast()).1;
+                item_tree_source_maps.function(function.value).item()
+            }
+            DefWithBody::Static(statik) => {
+                let statik = statik.id.lookup(db.upcast()).id;
+                item_tree_source_maps = statik.item_tree_with_source_map(db.upcast()).1;
+                item_tree_source_maps.statik(statik.value)
+            }
+            DefWithBody::Const(konst) => {
+                let konst = konst.id.lookup(db.upcast()).id;
+                item_tree_source_maps = konst.item_tree_with_source_map(db.upcast()).1;
+                item_tree_source_maps.konst(konst.value)
+            }
+            DefWithBody::Variant(_) | DefWithBody::InTypeConst(_) => &TypesSourceMap::EMPTY,
+        };
 
         for (_, def_map) in body.blocks(db.upcast()) {
             Module { id: def_map.module_id(DefMap::ROOT) }.diagnostics(db, acc, style_lints);
@@ -1861,7 +1953,13 @@ impl DefWithBody {
 
         let infer = db.infer(self.into());
         for d in &infer.diagnostics {
-            acc.extend(AnyDiagnostic::inference_diagnostic(db, self.into(), d, &source_map));
+            acc.extend(AnyDiagnostic::inference_diagnostic(
+                db,
+                self.into(),
+                d,
+                outer_types_source_map,
+                &source_map,
+            ));
         }
 
         for (pat_or_expr, mismatch) in infer.type_mismatches() {
@@ -3325,12 +3423,22 @@ impl AssocItem {
     ) {
         match self {
             AssocItem::Function(func) => {
+                GenericDef::Function(func).diagnostics(db, acc);
                 DefWithBody::from(func).diagnostics(db, acc, style_lints);
             }
             AssocItem::Const(const_) => {
                 DefWithBody::from(const_).diagnostics(db, acc, style_lints);
             }
             AssocItem::TypeAlias(type_alias) => {
+                GenericDef::TypeAlias(type_alias).diagnostics(db, acc);
+                let tree_id = type_alias.id.lookup(db.upcast()).id;
+                let tree_source_maps = tree_id.item_tree_with_source_map(db.upcast()).1;
+                push_ty_diagnostics(
+                    db,
+                    acc,
+                    db.type_for_type_alias_with_diagnostics(type_alias.id).1,
+                    tree_source_maps.type_alias(tree_id.value).item(),
+                );
                 for diag in hir_ty::diagnostics::incorrect_case(db, type_alias.id.into()) {
                     acc.push(diag.into());
                 }
@@ -3417,6 +3525,97 @@ impl GenericDef {
             })
             .collect()
     }
+
+    fn id(self) -> GenericDefId {
+        match self {
+            GenericDef::Function(it) => it.id.into(),
+            GenericDef::Adt(it) => it.into(),
+            GenericDef::Trait(it) => it.id.into(),
+            GenericDef::TraitAlias(it) => it.id.into(),
+            GenericDef::TypeAlias(it) => it.id.into(),
+            GenericDef::Impl(it) => it.id.into(),
+            GenericDef::Const(it) => it.id.into(),
+        }
+    }
+
+    pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
+        let def = self.id();
+
+        let item_tree_source_maps;
+        let (generics, generics_source_map) = db.generic_params_with_source_map(def);
+
+        if generics.is_empty() && generics.no_predicates() {
+            return;
+        }
+
+        let source_map = match &generics_source_map {
+            Some(it) => it,
+            None => match def {
+                GenericDefId::FunctionId(it) => {
+                    let id = it.lookup(db.upcast()).id;
+                    item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1;
+                    item_tree_source_maps.function(id.value).generics()
+                }
+                GenericDefId::AdtId(AdtId::EnumId(it)) => {
+                    let id = it.lookup(db.upcast()).id;
+                    item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1;
+                    item_tree_source_maps.enum_generic(id.value)
+                }
+                GenericDefId::AdtId(AdtId::StructId(it)) => {
+                    let id = it.lookup(db.upcast()).id;
+                    item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1;
+                    item_tree_source_maps.strukt(id.value).generics()
+                }
+                GenericDefId::AdtId(AdtId::UnionId(it)) => {
+                    let id = it.lookup(db.upcast()).id;
+                    item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1;
+                    item_tree_source_maps.union(id.value).generics()
+                }
+                GenericDefId::TraitId(it) => {
+                    let id = it.lookup(db.upcast()).id;
+                    item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1;
+                    item_tree_source_maps.trait_generic(id.value)
+                }
+                GenericDefId::TraitAliasId(it) => {
+                    let id = it.lookup(db.upcast()).id;
+                    item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1;
+                    item_tree_source_maps.trait_alias_generic(id.value)
+                }
+                GenericDefId::TypeAliasId(it) => {
+                    let id = it.lookup(db.upcast()).id;
+                    item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1;
+                    item_tree_source_maps.type_alias(id.value).generics()
+                }
+                GenericDefId::ImplId(it) => {
+                    let id = it.lookup(db.upcast()).id;
+                    item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1;
+                    item_tree_source_maps.impl_(id.value).generics()
+                }
+                GenericDefId::ConstId(_) => return,
+            },
+        };
+
+        push_ty_diagnostics(db, acc, db.generic_defaults_with_diagnostics(def).1, source_map);
+        push_ty_diagnostics(
+            db,
+            acc,
+            db.generic_predicates_without_parent_with_diagnostics(def).1,
+            source_map,
+        );
+        for (param_id, param) in generics.iter_type_or_consts() {
+            if let TypeOrConstParamData::ConstParamData(_) = param {
+                push_ty_diagnostics(
+                    db,
+                    acc,
+                    db.const_param_ty_with_diagnostics(ConstParamId::from_unchecked(
+                        TypeOrConstParamId { parent: def, local_id: param_id },
+                    ))
+                    .1,
+                    source_map,
+                );
+            }
+        }
+    }
 }
 
 /// A single local definition.
@@ -5800,3 +5999,19 @@ pub enum DocLinkDef {
     Field(Field),
     SelfType(Trait),
 }
+
+fn push_ty_diagnostics(
+    db: &dyn HirDatabase,
+    acc: &mut Vec<AnyDiagnostic>,
+    diagnostics: Option<ThinArc<(), TyLoweringDiagnostic>>,
+    source_map: &TypesSourceMap,
+) {
+    if let Some(diagnostics) = diagnostics {
+        acc.extend(
+            diagnostics
+                .slice
+                .iter()
+                .filter_map(|diagnostic| AnyDiagnostic::ty_diagnostic(diagnostic, source_map, db)),
+        );
+    }
+}
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
new file mode 100644
index 00000000000..a319a0bcf6d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs
@@ -0,0 +1,442 @@
+use either::Either;
+use hir::GenericArgsProhibitedReason;
+use ide_db::assists::Assist;
+use ide_db::source_change::SourceChange;
+use ide_db::text_edit::TextEdit;
+use syntax::{ast, AstNode, TextRange};
+
+use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext};
+
+// Diagnostic: generic-args-prohibited
+//
+// This diagnostic is shown when generic arguments are provided for a type that does not accept
+// generic arguments.
+pub(crate) fn generic_args_prohibited(
+    ctx: &DiagnosticsContext<'_>,
+    d: &hir::GenericArgsProhibited,
+) -> Diagnostic {
+    Diagnostic::new_with_syntax_node_ptr(
+        ctx,
+        DiagnosticCode::RustcHardError("E0109"),
+        describe_reason(d.reason),
+        d.args.map(Into::into),
+    )
+    .with_fixes(fixes(ctx, d))
+}
+
+fn describe_reason(reason: GenericArgsProhibitedReason) -> String {
+    let kind = match reason {
+        GenericArgsProhibitedReason::Module => "modules",
+        GenericArgsProhibitedReason::TyParam => "type parameters",
+        GenericArgsProhibitedReason::SelfTy => "`Self`",
+        GenericArgsProhibitedReason::PrimitiveTy => "builtin types",
+        GenericArgsProhibitedReason::EnumVariant => {
+            return "you can specify generic arguments on either the enum or the variant, but not both"
+                .to_owned();
+        }
+    };
+    format!("generic arguments are not allowed on {kind}")
+}
+
+fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::GenericArgsProhibited) -> Option<Vec<Assist>> {
+    let file_id = d.args.file_id.file_id()?;
+    let syntax = d.args.to_node(ctx.sema.db);
+    let range = match &syntax {
+        Either::Left(_) => syntax.syntax().text_range(),
+        Either::Right(param_list) => {
+            let path_segment = ast::PathSegment::cast(param_list.syntax().parent()?)?;
+            let start = if let Some(coloncolon) = path_segment.coloncolon_token() {
+                coloncolon.text_range().start()
+            } else {
+                param_list.syntax().text_range().start()
+            };
+            let end = if let Some(ret_type) = path_segment.ret_type() {
+                ret_type.syntax().text_range().end()
+            } else {
+                param_list.syntax().text_range().end()
+            };
+            TextRange::new(start, end)
+        }
+    };
+    Some(vec![fix(
+        "remove_generic_args",
+        "Remove these generics",
+        SourceChange::from_text_edit(file_id, TextEdit::delete(range)),
+        syntax.syntax().text_range(),
+    )])
+}
+
+#[cfg(test)]
+mod tests {
+    // This diagnostic was the first to be emitted in ty lowering, so the tests here also test
+    // diagnostics in ty lowering in general (which is why there are so many of them).
+
+    use crate::tests::{check_diagnostics, check_fix};
+
+    #[test]
+    fn primitives() {
+        check_diagnostics(
+            r#"
+//- /core.rs crate:core library
+#![rustc_coherence_is_core]
+impl str {
+    pub fn trim() {}
+}
+
+//- /lib.rs crate:foo deps:core
+fn bar<T>() {}
+
+fn foo() {
+    let _: (bool<()>, ());
+             // ^^^^ 💡 error: generic arguments are not allowed on builtin types
+    let _ = <str<'_>>::trim;
+             // ^^^^ 💡 error: generic arguments are not allowed on builtin types
+    bar::<u32<{ const { 1 + 1 } }>>();
+          // ^^^^^^^^^^^^^^^^^^^^^ 💡 error: generic arguments are not allowed on builtin types
+}
+            "#,
+        );
+    }
+
+    #[test]
+    fn modules() {
+        check_diagnostics(
+            r#"
+pub mod foo {
+    pub mod bar {
+        pub struct Baz;
+
+        impl Baz {
+            pub fn qux() {}
+        }
+    }
+}
+
+fn foo() {
+    let _: foo::<'_>::bar::Baz;
+           // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+    let _ = <foo::bar<()>::Baz>::qux;
+                  // ^^^^ 💡 error: generic arguments are not allowed on modules
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn type_parameters() {
+        check_diagnostics(
+            r#"
+fn foo<T, U>() {
+    let _: T<'a>;
+         // ^^^^ 💡 error: generic arguments are not allowed on type parameters
+    let _: U::<{ 1 + 2 }>;
+         // ^^^^^^^^^^^^^ 💡 error: generic arguments are not allowed on type parameters
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn fn_like_generic_args() {
+        check_diagnostics(
+            r#"
+fn foo() {
+    let _: bool(bool, i32) -> ();
+            // ^^^^^^^^^^^ 💡 error: generic arguments are not allowed on builtin types
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn fn_signature() {
+        check_diagnostics(
+            r#"
+fn foo(
+    _a: bool<'_>,
+         // ^^^^ 💡 error: generic arguments are not allowed on builtin types
+    _b: i32::<i64>,
+        // ^^^^^^^ 💡 error: generic arguments are not allowed on builtin types
+    _c: &(&str<1>)
+           // ^^^ 💡 error: generic arguments are not allowed on builtin types
+) -> ((), i32<bool>) {
+          // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types
+    ((), 0)
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn const_static_type() {
+        check_diagnostics(
+            r#"
+const A: i32<bool> = 0;
+         // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types
+static A: i32::<{ 1 + 3 }> = 0;
+          // ^^^^^^^^^^^^^ 💡 error: generic arguments are not allowed on builtin types
+        "#,
+        );
+    }
+
+    #[test]
+    fn fix() {
+        check_fix(
+            r#"
+fn foo() {
+    let _: bool<'_, (), { 1 + 1 }>$0;
+}"#,
+            r#"
+fn foo() {
+    let _: bool;
+}"#,
+        );
+        check_fix(
+            r#"
+fn foo() {
+    let _: bool::$0<'_, (), { 1 + 1 }>;
+}"#,
+            r#"
+fn foo() {
+    let _: bool;
+}"#,
+        );
+        check_fix(
+            r#"
+fn foo() {
+    let _: bool(i$032);
+}"#,
+            r#"
+fn foo() {
+    let _: bool;
+}"#,
+        );
+        check_fix(
+            r#"
+fn foo() {
+    let _: bool$0(i32) -> i64;
+}"#,
+            r#"
+fn foo() {
+    let _: bool;
+}"#,
+        );
+        check_fix(
+            r#"
+fn foo() {
+    let _: bool::(i$032) -> i64;
+}"#,
+            r#"
+fn foo() {
+    let _: bool;
+}"#,
+        );
+        check_fix(
+            r#"
+fn foo() {
+    let _: bool::(i32)$0;
+}"#,
+            r#"
+fn foo() {
+    let _: bool;
+}"#,
+        );
+    }
+
+    #[test]
+    fn in_fields() {
+        check_diagnostics(
+            r#"
+struct A(bool<i32>);
+          // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+struct B { v: bool<(), 1> }
+               // ^^^^^^^ 💡 error: generic arguments are not allowed on builtin types
+union C {
+    a: bool<i32>,
+        // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+    b: i32<bool>,
+       // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types
+       }
+enum D {
+    A(bool<i32>),
+       // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+    B { v: i32<bool> },
+           // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn in_generics() {
+        check_diagnostics(
+            r#"
+mod foo {
+    pub trait Trait {}
+}
+
+struct A<A: foo::<()>::Trait>(A)
+            // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+    where bool<i32>: foo::Trait;
+           // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+union B<A: foo::<()>::Trait>
+           // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+    where bool<i32>: foo::Trait
+           // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+{ a: A }
+enum C<A: foo::<()>::Trait>
+          // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+    where bool<i32>: foo::Trait
+           // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+{}
+
+fn f<A: foo::<()>::Trait>()
+        // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+    where bool<i32>: foo::Trait
+           // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+{}
+
+type D<A: foo::<()>::Trait> = A
+          // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+    where bool<i32>: foo::Trait;
+           // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+
+trait E<A: foo::<()>::Trait>
+           // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+    where bool<i32>: foo::Trait
+           // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+{
+    fn f<B: foo::<()>::Trait>()
+            // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+        where bool<i32>: foo::Trait
+               // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+    {}
+
+    type D<B: foo::<()>::Trait> = A
+              // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+        where bool<i32>: foo::Trait;
+               // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+}
+
+impl<A: foo::<()>::Trait> E for ()
+        // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+    where bool<i32>: foo::Trait
+           // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+{
+    fn f<B: foo::<()>::Trait>()
+            // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+        where bool<i32>: foo::Trait
+               // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+    {}
+
+    type D<B: foo::<()>::Trait> = A
+              // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+        where bool<i32>: foo::Trait;
+               // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn assoc_items() {
+        check_diagnostics(
+            r#"
+struct Foo;
+
+trait Trait {
+    fn f() -> bool<i32> { true }
+               // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+    type T = i32<bool>;
+             // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types
+}
+
+impl Trait for Foo {
+    fn f() -> bool<i32> { true }
+               // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+    type T = i32<bool>;
+             // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types
+}
+
+impl Foo {
+    fn f() -> bool<i32> { true }
+               // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+    type T = i32<bool>;
+             // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn const_param_ty() {
+        check_diagnostics(
+            r#"
+fn foo<
+    const A: bool<i32>,
+              // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+    B,
+    C,
+    const D: bool<i32>,
+              // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+    const E: bool<i32>,
+              // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+>() {}
+        "#,
+        );
+    }
+
+    #[test]
+    fn generic_defaults() {
+        check_diagnostics(
+            r#"
+struct Foo<A = bool<i32>>(A);
+                // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+        "#,
+        );
+    }
+
+    #[test]
+    fn impl_self_ty() {
+        check_diagnostics(
+            r#"
+struct Foo<A>(A);
+trait Trait {}
+impl Foo<bool<i32>> {}
+          // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+impl Trait for Foo<bool<i32>> {}
+                    // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+        "#,
+        );
+    }
+
+    #[test]
+    fn impl_trait() {
+        check_diagnostics(
+            r#"
+mod foo {
+    pub trait Trait {}
+}
+impl foo::<()>::Trait for () {}
+     // ^^^^^^ 💡 error: generic arguments are not allowed on modules
+        "#,
+        );
+    }
+
+    #[test]
+    fn type_alias() {
+        check_diagnostics(
+            r#"
+pub trait Trait {
+    type Assoc;
+}
+type T = bool<i32>;
+          // ^^^^^ 💡 error: generic arguments are not allowed on builtin types
+impl Trait for () {
+    type Assoc = i32<bool>;
+                 // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types
+}
+        "#,
+        );
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
index 81cb4521218..4ab649cc162 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
@@ -167,9 +167,9 @@ fn assoc_func_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) -
         }
 
         let method_name = call.name_ref()?;
-        let assoc_func_call = format!("{receiver_type_adt_name}::{method_name}()");
+        let assoc_func_path = format!("{receiver_type_adt_name}::{method_name}");
 
-        let assoc_func_call = make::expr_path(make::path_from_text(&assoc_func_call));
+        let assoc_func_path = make::expr_path(make::path_from_text(&assoc_func_path));
 
         let args: Vec<_> = if need_to_take_receiver_as_first_arg {
             std::iter::once(receiver).chain(call.arg_list()?.args()).collect()
@@ -178,7 +178,7 @@ fn assoc_func_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) -
         };
         let args = make::arg_list(args);
 
-        let assoc_func_call_expr_string = make::expr_call(assoc_func_call, args).to_string();
+        let assoc_func_call_expr_string = make::expr_call(assoc_func_path, args).to_string();
 
         let file_id = ctx.sema.original_range_opt(call.receiver()?.syntax())?.file_id;
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
index 1f1b6478d36..663fc6a6771 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
@@ -27,6 +27,7 @@ mod handlers {
     pub(crate) mod await_outside_of_async;
     pub(crate) mod break_outside_of_loop;
     pub(crate) mod expected_function;
+    pub(crate) mod generic_args_prohibited;
     pub(crate) mod inactive_code;
     pub(crate) mod incoherent_impl;
     pub(crate) mod incorrect_case;
@@ -468,6 +469,7 @@ pub fn semantic_diagnostics(
                 Some(it) => it,
                 None => continue,
             },
+            AnyDiagnostic::GenericArgsProhibited(d) => handlers::generic_args_prohibited::generic_args_prohibited(&ctx, &d)
         };
         res.push(d)
     }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
index 802d0c69a47..e3ea441f3ab 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -13,8 +13,9 @@ use hir::{
     ModuleDef, Name,
 };
 use hir_def::{
-    body::{BodySourceMap, SyntheticSyntax},
+    body::BodySourceMap,
     hir::{ExprId, PatId},
+    SyntheticSyntax,
 };
 use hir_ty::{Interner, Substitution, TyExt, TypeFlags};
 use ide::{
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
index 2ec83d23b27..7eb3e08f541 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
@@ -402,7 +402,7 @@ pub fn join_paths(paths: impl IntoIterator<Item = ast::Path>) -> ast::Path {
 
 // FIXME: should not be pub
 pub fn path_from_text(text: &str) -> ast::Path {
-    ast_from_text(&format!("fn main() {{ let test = {text}; }}"))
+    ast_from_text(&format!("fn main() {{ let test: {text}; }}"))
 }
 
 pub fn use_tree_glob() -> ast::UseTree {