Repository: rust-lang/rust-analyzer
Pull request #17494 (2024-06-25 16:32:00)

do not normalize `use foo::{self}` to `use foo`
It changes behaviour and can cause collisions. E.g. for the following snippet

```rs
mod foo {

    pub mod bar {}

    pub const bar: i32 = 8;
}

// transforming the below to `use foo::bar;` causes the error:
//
//   the name `bar` is defined multiple times
use foo::bar::{self};

const bar: u32 = 99;

fn main() {
    let local_bar = bar;
}
```

we still normalize

```rs
use foo::bar;
use foo::bar::{self};
```

to `use foo::bar;` because this cannot cause collisions.

See: https://github.com/rust-lang/rust-analyzer/pull/17140#issuecomment-2079189725


harrysarson: cc: @Veykril 

Patch:
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index e11d6e15d1..11014338d7 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -132,7 +132,7 @@ jobs:
         run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats --with-deps $(rustc --print sysroot)/lib/rustlib/src/rust/library/std
 
       - name: Upload artifacts
-        uses: actions/upload-artifact@v4
+        uses: actions/upload-artifact@v1
         with:
           name: dist-${{ matrix.target }}
           path: ./dist
@@ -177,7 +177,7 @@ jobs:
       - run: rm -rf editors/code/server
 
       - name: Upload artifacts
-        uses: actions/upload-artifact@v4
+        uses: actions/upload-artifact@v1
         with:
           name: dist-x86_64-unknown-linux-musl
           path: ./dist
@@ -206,39 +206,39 @@ jobs:
       - run: echo "HEAD_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV
       - run: 'echo "HEAD_SHA: $HEAD_SHA"'
 
-      - uses: actions/download-artifact@v4
+      - uses: actions/download-artifact@v1
         with:
           name: dist-aarch64-apple-darwin
           path: dist
-      - uses: actions/download-artifact@v4
+      - uses: actions/download-artifact@v1
         with:
           name: dist-x86_64-apple-darwin
           path: dist
-      - uses: actions/download-artifact@v4
+      - uses: actions/download-artifact@v1
         with:
           name: dist-x86_64-unknown-linux-gnu
           path: dist
-      - uses: actions/download-artifact@v4
+      - uses: actions/download-artifact@v1
         with:
           name: dist-x86_64-unknown-linux-musl
           path: dist
-      - uses: actions/download-artifact@v4
+      - uses: actions/download-artifact@v1
         with:
           name: dist-aarch64-unknown-linux-gnu
           path: dist
-      - uses: actions/download-artifact@v4
+      - uses: actions/download-artifact@v1
         with:
           name: dist-arm-unknown-linux-gnueabihf
           path: dist
-      - uses: actions/download-artifact@v4
+      - uses: actions/download-artifact@v1
         with:
           name: dist-x86_64-pc-windows-msvc
           path: dist
-      - uses: actions/download-artifact@v4
+      - uses: actions/download-artifact@v1
         with:
           name: dist-i686-pc-windows-msvc
           path: dist
-      - uses: actions/download-artifact@v4
+      - uses: actions/download-artifact@v1
         with:
           name: dist-aarch64-pc-windows-msvc
           path: dist
diff --git a/Cargo.lock b/Cargo.lock
index 94734da9d3..57d43dad3f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1046,7 +1046,6 @@ checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5"
 name = "mbe"
 version = "0.0.0"
 dependencies = [
- "arrayvec",
  "cov-mark",
  "parser",
  "rustc-hash",
@@ -2252,7 +2251,6 @@ dependencies = [
 name = "tt"
 version = "0.0.0"
 dependencies = [
- "arrayvec",
  "smol_str",
  "stdx",
  "text-size",
diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs
index 8cf1e15f31..4338163672 100644
--- a/crates/hir-def/src/data.rs
+++ b/crates/hir-def/src/data.rs
@@ -323,7 +323,7 @@ impl TraitAliasData {
 pub struct ImplData {
     pub target_trait: Option<Interned<TraitRef>>,
     pub self_ty: Interned<TypeRef>,
-    pub items: Box<[AssocItemId]>,
+    pub items: Vec<AssocItemId>,
     pub is_negative: bool,
     pub is_unsafe: bool,
     // box it as the vec is usually empty anyways
diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs
index 0eb9e7d30b..61fed71218 100644
--- a/crates/hir-def/src/db.rs
+++ b/crates/hir-def/src/db.rs
@@ -80,11 +80,9 @@ pub trait InternDatabase: SourceDatabase {
 
 #[salsa::query_group(DefDatabaseStorage)]
 pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDatabase> {
-    /// Whether to expand procedural macros during name resolution.
     #[salsa::input]
     fn expand_proc_attr_macros(&self) -> bool;
 
-    /// Computes an [`ItemTree`] for the given file or macro expansion.
     #[salsa::invoke(ItemTree::file_item_tree_query)]
     fn file_item_tree(&self, file_id: HirFileId) -> Arc<ItemTree>;
 
@@ -98,7 +96,6 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
     #[salsa::invoke(DefMap::block_def_map_query)]
     fn block_def_map(&self, block: BlockId) -> Arc<DefMap>;
 
-    /// Turns a MacroId into a MacroDefId, describing the macro's definition post name resolution.
     fn macro_def(&self, m: MacroId) -> MacroDefId;
 
     // region:data
@@ -193,7 +190,6 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
     #[salsa::invoke(Attrs::fields_attrs_query)]
     fn fields_attrs(&self, def: VariantId) -> Arc<ArenaMap<LocalFieldId, Attrs>>;
 
-    // should this really be a query?
     #[salsa::invoke(crate::attr::fields_attrs_source_map)]
     fn fields_attrs_source_map(
         &self,
diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs
index ca02501567..acead9dc17 100644
--- a/crates/hir-def/src/generics.rs
+++ b/crates/hir-def/src/generics.rs
@@ -11,7 +11,7 @@ use hir_expand::{
     ExpandResult,
 };
 use intern::Interned;
-use la_arena::{Arena, RawIdx};
+use la_arena::Arena;
 use once_cell::unsync::Lazy;
 use stdx::impl_from;
 use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds};
@@ -28,9 +28,6 @@ use crate::{
     LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
 };
 
-const SELF_PARAM_ID_IN_SELF: la_arena::Idx<TypeOrConstParamData> =
-    LocalTypeOrConstParamId::from_raw(RawIdx::from_u32(0));
-
 /// Data about a generic type parameter (to a function, struct, impl, ...).
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub struct TypeParamData {
@@ -444,18 +441,15 @@ impl GenericParamsCollector {
 
 impl GenericParams {
     /// Number of Generic parameters (type_or_consts + lifetimes)
-    #[inline]
     pub fn len(&self) -> usize {
         self.type_or_consts.len() + self.lifetimes.len()
     }
 
-    #[inline]
     pub fn is_empty(&self) -> bool {
         self.len() == 0
     }
 
     /// Iterator of type_or_consts field
-    #[inline]
     pub fn iter_type_or_consts(
         &self,
     ) -> impl DoubleEndedIterator<Item = (LocalTypeOrConstParamId, &TypeOrConstParamData)> {
@@ -463,7 +457,6 @@ impl GenericParams {
     }
 
     /// Iterator of lifetimes field
-    #[inline]
     pub fn iter_lt(
         &self,
     ) -> impl DoubleEndedIterator<Item = (LocalLifetimeParamId, &LifetimeParamData)> {
@@ -582,11 +575,13 @@ impl GenericParams {
             GenericDefId::TraitAliasId(id) => id_to_generics(db, id, enabled_params),
             GenericDefId::TypeAliasId(id) => id_to_generics(db, id, enabled_params),
             GenericDefId::ImplId(id) => id_to_generics(db, id, enabled_params),
-            GenericDefId::ConstId(_) => Interned::new(GenericParams {
-                type_or_consts: Default::default(),
-                lifetimes: Default::default(),
-                where_predicates: Default::default(),
-            }),
+            GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => {
+                Interned::new(GenericParams {
+                    type_or_consts: Default::default(),
+                    lifetimes: Default::default(),
+                    where_predicates: Default::default(),
+                })
+            }
         }
     }
 
@@ -610,18 +605,17 @@ impl GenericParams {
         })
     }
 
-    pub fn trait_self_param(&self) -> Option<LocalTypeOrConstParamId> {
-        if self.type_or_consts.is_empty() {
-            return None;
-        }
-        matches!(
-            self.type_or_consts[SELF_PARAM_ID_IN_SELF],
-            TypeOrConstParamData::TypeParamData(TypeParamData {
-                provenance: TypeParamProvenance::TraitSelf,
-                ..
-            })
-        )
-        .then(|| SELF_PARAM_ID_IN_SELF)
+    pub fn find_trait_self_param(&self) -> Option<LocalTypeOrConstParamId> {
+        self.type_or_consts.iter().find_map(|(id, p)| {
+            matches!(
+                p,
+                TypeOrConstParamData::TypeParamData(TypeParamData {
+                    provenance: TypeParamProvenance::TraitSelf,
+                    ..
+                })
+            )
+            .then(|| id)
+        })
     }
 
     pub fn find_lifetime_by_name(
diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs
index 7650dfe9f3..c3b7a78301 100644
--- a/crates/hir-def/src/item_tree.rs
+++ b/crates/hir-def/src/item_tree.rs
@@ -48,7 +48,6 @@ use either::Either;
 use hir_expand::{attrs::RawAttrs, name::Name, ExpandTo, HirFileId, InFile};
 use intern::Interned;
 use la_arena::{Arena, Idx, IdxRange, RawIdx};
-use once_cell::sync::OnceCell;
 use rustc_hash::FxHashMap;
 use smallvec::SmallVec;
 use span::{AstIdNode, FileAstId, SyntaxContextId};
@@ -101,7 +100,6 @@ pub struct ItemTree {
 impl ItemTree {
     pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
         let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered();
-        static EMPTY: OnceCell<Arc<ItemTree>> = OnceCell::new();
 
         let syntax = db.parse_or_expand(file_id);
 
@@ -133,47 +131,18 @@ impl ItemTree {
         if let Some(attrs) = top_attrs {
             item_tree.attrs.insert(AttrOwner::TopLevel, attrs);
         }
-        if item_tree.data.is_none() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty()
-        {
-            EMPTY
-                .get_or_init(|| {
-                    Arc::new(ItemTree {
-                        top_level: SmallVec::new_const(),
-                        attrs: FxHashMap::default(),
-                        data: None,
-                    })
-                })
-                .clone()
-        } else {
-            item_tree.shrink_to_fit();
-            Arc::new(item_tree)
-        }
+        item_tree.shrink_to_fit();
+        Arc::new(item_tree)
     }
 
     pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc<ItemTree> {
-        let _p = tracing::info_span!("block_item_tree_query", ?block).entered();
-        static EMPTY: OnceCell<Arc<ItemTree>> = OnceCell::new();
-
         let loc = block.lookup(db);
         let block = loc.ast_id.to_node(db.upcast());
 
         let ctx = lower::Ctx::new(db, loc.ast_id.file_id);
         let mut item_tree = ctx.lower_block(&block);
-        if item_tree.data.is_none() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty()
-        {
-            EMPTY
-                .get_or_init(|| {
-                    Arc::new(ItemTree {
-                        top_level: SmallVec::new_const(),
-                        attrs: FxHashMap::default(),
-                        data: None,
-                    })
-                })
-                .clone()
-        } else {
-            item_tree.shrink_to_fit();
-            Arc::new(item_tree)
-        }
+        item_tree.shrink_to_fit();
+        Arc::new(item_tree)
     }
 
     /// Returns an iterator over all items located at the top level of the `HirFileId` this
@@ -616,30 +585,24 @@ impl Index<RawVisibilityId> for ItemTree {
     type Output = RawVisibility;
     fn index(&self, index: RawVisibilityId) -> &Self::Output {
         static VIS_PUB: RawVisibility = RawVisibility::Public;
-        static VIS_PRIV_IMPLICIT: OnceCell<RawVisibility> = OnceCell::new();
-        static VIS_PRIV_EXPLICIT: OnceCell<RawVisibility> = OnceCell::new();
-        static VIS_PUB_CRATE: OnceCell<RawVisibility> = OnceCell::new();
+        static VIS_PRIV_IMPLICIT: RawVisibility = RawVisibility::Module(
+            ModPath::from_kind(PathKind::SELF),
+            VisibilityExplicitness::Implicit,
+        );
+        static VIS_PRIV_EXPLICIT: RawVisibility = RawVisibility::Module(
+            ModPath::from_kind(PathKind::SELF),
+            VisibilityExplicitness::Explicit,
+        );
+        static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(
+            ModPath::from_kind(PathKind::Crate),
+            VisibilityExplicitness::Explicit,
+        );
 
         match index {
-            RawVisibilityId::PRIV_IMPLICIT => VIS_PRIV_IMPLICIT.get_or_init(|| {
-                RawVisibility::Module(
-                    Interned::new(ModPath::from_kind(PathKind::SELF)),
-                    VisibilityExplicitness::Implicit,
-                )
-            }),
-            RawVisibilityId::PRIV_EXPLICIT => VIS_PRIV_EXPLICIT.get_or_init(|| {
-                RawVisibility::Module(
-                    Interned::new(ModPath::from_kind(PathKind::SELF)),
-                    VisibilityExplicitness::Explicit,
-                )
-            }),
+            RawVisibilityId::PRIV_IMPLICIT => &VIS_PRIV_IMPLICIT,
+            RawVisibilityId::PRIV_EXPLICIT => &VIS_PRIV_EXPLICIT,
             RawVisibilityId::PUB => &VIS_PUB,
-            RawVisibilityId::PUB_CRATE => VIS_PUB_CRATE.get_or_init(|| {
-                RawVisibility::Module(
-                    Interned::new(ModPath::from_kind(PathKind::Crate)),
-                    VisibilityExplicitness::Explicit,
-                )
-            }),
+            RawVisibilityId::PUB_CRATE => &VIS_PUB_CRATE,
             _ => &self.data().vis.arena[Idx::from_raw(index.0.into())],
         }
     }
diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs
index 3fa98efbb5..0dcd9129d6 100644
--- a/crates/hir-def/src/lib.rs
+++ b/crates/hir-def/src/lib.rs
@@ -689,7 +689,7 @@ pub enum TypeOwnerId {
 }
 
 impl TypeOwnerId {
-    fn as_generic_def_id(self, db: &dyn DefDatabase) -> Option<GenericDefId> {
+    fn as_generic_def_id(self) -> Option<GenericDefId> {
         Some(match self {
             TypeOwnerId::FunctionId(it) => GenericDefId::FunctionId(it),
             TypeOwnerId::ConstId(it) => GenericDefId::ConstId(it),
@@ -698,9 +698,7 @@ impl TypeOwnerId {
             TypeOwnerId::TraitAliasId(it) => GenericDefId::TraitAliasId(it),
             TypeOwnerId::TypeAliasId(it) => GenericDefId::TypeAliasId(it),
             TypeOwnerId::ImplId(it) => GenericDefId::ImplId(it),
-            TypeOwnerId::EnumVariantId(it) => {
-                GenericDefId::AdtId(AdtId::EnumId(it.lookup(db).parent))
-            }
+            TypeOwnerId::EnumVariantId(it) => GenericDefId::EnumVariantId(it),
             TypeOwnerId::InTypeConstId(_) | TypeOwnerId::StaticId(_) => return None,
         })
     }
@@ -742,6 +740,7 @@ impl From<GenericDefId> for TypeOwnerId {
             GenericDefId::TraitAliasId(it) => it.into(),
             GenericDefId::TypeAliasId(it) => it.into(),
             GenericDefId::ImplId(it) => it.into(),
+            GenericDefId::EnumVariantId(it) => it.into(),
             GenericDefId::ConstId(it) => it.into(),
         }
     }
@@ -850,8 +849,8 @@ impl GeneralConstId {
     pub fn generic_def(self, db: &dyn DefDatabase) -> Option<GenericDefId> {
         match self {
             GeneralConstId::ConstId(it) => Some(it.into()),
-            GeneralConstId::ConstBlockId(it) => it.lookup(db).parent.as_generic_def_id(db),
-            GeneralConstId::InTypeConstId(it) => it.lookup(db).owner.as_generic_def_id(db),
+            GeneralConstId::ConstBlockId(it) => it.lookup(db).parent.as_generic_def_id(),
+            GeneralConstId::InTypeConstId(it) => it.lookup(db).owner.as_generic_def_id(),
         }
     }
 
@@ -889,12 +888,12 @@ impl From<EnumVariantId> for DefWithBodyId {
 }
 
 impl DefWithBodyId {
-    pub fn as_generic_def_id(self, db: &dyn DefDatabase) -> Option<GenericDefId> {
+    pub fn as_generic_def_id(self) -> Option<GenericDefId> {
         match self {
             DefWithBodyId::FunctionId(f) => Some(f.into()),
             DefWithBodyId::StaticId(_) => None,
             DefWithBodyId::ConstId(c) => Some(c.into()),
-            DefWithBodyId::VariantId(c) => Some(c.lookup(db).parent.into()),
+            DefWithBodyId::VariantId(c) => Some(c.into()),
             // FIXME: stable rust doesn't allow generics in constants, but we should
             // use `TypeOwnerId::as_generic_def_id` when it does.
             DefWithBodyId::InTypeConstId(_) => None,
@@ -922,6 +921,9 @@ pub enum GenericDefId {
     TraitAliasId(TraitAliasId),
     TypeAliasId(TypeAliasId),
     ImplId(ImplId),
+    // enum variants cannot have generics themselves, but their parent enums
+    // can, and this makes some code easier to write
+    EnumVariantId(EnumVariantId),
     // consts can have type parameters from their parents (i.e. associated consts of traits)
     ConstId(ConstId),
 }
@@ -932,6 +934,7 @@ impl_from!(
     TraitAliasId,
     TypeAliasId,
     ImplId,
+    EnumVariantId,
     ConstId
     for GenericDefId
 );
@@ -963,6 +966,7 @@ impl GenericDefId {
             GenericDefId::TraitAliasId(it) => file_id_and_params_of_item_loc(db, it),
             GenericDefId::ImplId(it) => file_id_and_params_of_item_loc(db, it),
             GenericDefId::ConstId(it) => (it.lookup(db).id.file_id(), None),
+            GenericDefId::EnumVariantId(it) => (it.lookup(db).id.file_id(), None),
         }
     }
 
@@ -977,14 +981,6 @@ impl GenericDefId {
             _ => None,
         }
     }
-
-    pub fn from_callable(db: &dyn DefDatabase, def: CallableDefId) -> GenericDefId {
-        match def {
-            CallableDefId::FunctionId(f) => f.into(),
-            CallableDefId::StructId(s) => s.into(),
-            CallableDefId::EnumVariantId(e) => e.lookup(db).parent.into(),
-        }
-    }
 }
 
 impl From<AssocItemId> for GenericDefId {
@@ -997,36 +993,6 @@ impl From<AssocItemId> for GenericDefId {
     }
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-pub enum CallableDefId {
-    FunctionId(FunctionId),
-    StructId(StructId),
-    EnumVariantId(EnumVariantId),
-}
-
-impl InternValueTrivial for CallableDefId {}
-
-impl_from!(FunctionId, StructId, EnumVariantId for CallableDefId);
-impl From<CallableDefId> for ModuleDefId {
-    fn from(def: CallableDefId) -> ModuleDefId {
-        match def {
-            CallableDefId::FunctionId(f) => ModuleDefId::FunctionId(f),
-            CallableDefId::StructId(s) => ModuleDefId::AdtId(AdtId::StructId(s)),
-            CallableDefId::EnumVariantId(e) => ModuleDefId::EnumVariantId(e),
-        }
-    }
-}
-
-impl CallableDefId {
-    pub fn krate(self, db: &dyn DefDatabase) -> CrateId {
-        match self {
-            CallableDefId::FunctionId(f) => f.krate(db),
-            CallableDefId::StructId(s) => s.krate(db),
-            CallableDefId::EnumVariantId(e) => e.krate(db),
-        }
-    }
-}
-
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 pub enum AttrDefId {
     ModuleId(ModuleId),
@@ -1343,6 +1309,7 @@ impl HasModule for GenericDefId {
             GenericDefId::TraitAliasId(it) => it.module(db),
             GenericDefId::TypeAliasId(it) => it.module(db),
             GenericDefId::ImplId(it) => it.module(db),
+            GenericDefId::EnumVariantId(it) => it.module(db),
             GenericDefId::ConstId(it) => it.module(db),
         }
     }
diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs
index 8e7ef48112..162b6429c3 100644
--- a/crates/hir-def/src/nameres.rs
+++ b/crates/hir-def/src/nameres.rs
@@ -103,13 +103,12 @@ const PREDEFINED_TOOLS: &[SmolStr] = &[
 /// is computed by the `block_def_map` query.
 #[derive(Debug, PartialEq, Eq)]
 pub struct DefMap {
-    /// The crate this `DefMap` belongs to.
-    krate: CrateId,
     /// When this is a block def map, this will hold the block id of the block and module that
     /// contains this block.
     block: Option<BlockInfo>,
     /// The modules and their data declared in this crate.
     pub modules: Arena<ModuleData>,
+    krate: CrateId,
     /// The prelude module for this crate. This either comes from an import
     /// marked with the `prelude_import` attribute, or (in the normal case) from
     /// a dependency (`std` or `core`).
@@ -125,7 +124,6 @@ pub struct DefMap {
 
     /// Tracks which custom derives are in scope for an item, to allow resolution of derive helper
     /// attributes.
-    // FIXME: Figure out a better way for the IDE layer to resolve these?
     derive_helpers_in_scope: FxHashMap<AstId<ast::Item>, Vec<(Name, MacroId, MacroCallId)>>,
 
     /// The diagnostics that need to be emitted for this crate.
diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs
index a83157415c..9794963203 100644
--- a/crates/hir-def/src/resolver.rs
+++ b/crates/hir-def/src/resolver.rs
@@ -1164,6 +1164,7 @@ impl HasResolver for GenericDefId {
             GenericDefId::TraitAliasId(inner) => inner.resolver(db),
             GenericDefId::TypeAliasId(inner) => inner.resolver(db),
             GenericDefId::ImplId(inner) => inner.resolver(db),
+            GenericDefId::EnumVariantId(inner) => inner.resolver(db),
             GenericDefId::ConstId(inner) => inner.resolver(db),
         }
     }
diff --git a/crates/hir-def/src/visibility.rs b/crates/hir-def/src/visibility.rs
index 11d91513f1..e08718fc83 100644
--- a/crates/hir-def/src/visibility.rs
+++ b/crates/hir-def/src/visibility.rs
@@ -2,7 +2,6 @@
 
 use std::iter;
 
-use intern::Interned;
 use la_arena::ArenaMap;
 use span::SyntaxContextId;
 use syntax::ast;
@@ -21,17 +20,14 @@ use crate::{
 pub enum RawVisibility {
     /// `pub(in module)`, `pub(crate)` or `pub(super)`. Also private, which is
     /// equivalent to `pub(self)`.
-    Module(Interned<ModPath>, VisibilityExplicitness),
+    Module(ModPath, VisibilityExplicitness),
     /// `pub`.
     Public,
 }
 
 impl RawVisibility {
-    pub(crate) fn private() -> RawVisibility {
-        RawVisibility::Module(
-            Interned::new(ModPath::from_kind(PathKind::SELF)),
-            VisibilityExplicitness::Implicit,
-        )
+    pub(crate) const fn private() -> RawVisibility {
+        RawVisibility::Module(ModPath::from_kind(PathKind::SELF), VisibilityExplicitness::Implicit)
     }
 
     pub(crate) fn from_ast(
@@ -64,7 +60,7 @@ impl RawVisibility {
             ast::VisibilityKind::PubSelf => ModPath::from_kind(PathKind::SELF),
             ast::VisibilityKind::Pub => return RawVisibility::Public,
         };
-        RawVisibility::Module(Interned::new(path), VisibilityExplicitness::Explicit)
+        RawVisibility::Module(path, VisibilityExplicitness::Explicit)
     }
 
     pub fn resolve(
diff --git a/crates/hir-expand/src/change.rs b/crates/hir-expand/src/change.rs
index 08491db372..1a3dd0e7dd 100644
--- a/crates/hir-expand/src/change.rs
+++ b/crates/hir-expand/src/change.rs
@@ -25,8 +25,7 @@ impl ChangeWithProcMacros {
 
     pub fn apply(self, db: &mut (impl ExpandDatabase + SourceDatabaseExt)) {
         self.source_change.apply(db);
-        if let Some(mut proc_macros) = self.proc_macros {
-            proc_macros.shrink_to_fit();
+        if let Some(proc_macros) = self.proc_macros {
             db.set_proc_macros_with_durability(Arc::new(proc_macros), Durability::HIGH);
         }
         if let Some(target_data_layouts) = self.target_data_layouts {
diff --git a/crates/hir-ty/src/builder.rs b/crates/hir-ty/src/builder.rs
index bccdc9a6c5..d6374658f1 100644
--- a/crates/hir-ty/src/builder.rs
+++ b/crates/hir-ty/src/builder.rs
@@ -14,10 +14,10 @@ use hir_def::{
 use smallvec::SmallVec;
 
 use crate::{
-    consteval::unknown_const_as_generic, db::HirDatabase, error_lifetime, generics::generics,
-    infer::unify::InferenceTable, primitive, to_assoc_type_id, to_chalk_trait_id, Binders,
-    BoundVar, CallableSig, GenericArg, GenericArgData, Interner, ProjectionTy, Substitution,
-    TraitRef, Ty, TyDefId, TyExt, TyKind,
+    consteval::unknown_const_as_generic, db::HirDatabase, error_lifetime,
+    infer::unify::InferenceTable, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics,
+    Binders, BoundVar, CallableSig, GenericArg, GenericArgData, Interner, ProjectionTy,
+    Substitution, TraitRef, Ty, TyDefId, TyExt, TyKind,
 };
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -252,9 +252,8 @@ impl TyBuilder<()> {
     /// This method prepopulates the builder with placeholder substitution of `parent`, so you
     /// should only push exactly 3 `GenericArg`s before building.
     pub fn subst_for_coroutine(db: &dyn HirDatabase, parent: DefWithBodyId) -> TyBuilder<()> {
-        let parent_subst = parent
-            .as_generic_def_id(db.upcast())
-            .map(|p| generics(db.upcast(), p).placeholder_subst(db));
+        let parent_subst =
+            parent.as_generic_def_id().map(|p| generics(db.upcast(), p).placeholder_subst(db));
         // These represent resume type, yield type, and return type of coroutine.
         let params = std::iter::repeat(ParamKind::Type).take(3).collect();
         TyBuilder::new((), params, parent_subst)
@@ -267,7 +266,7 @@ impl TyBuilder<()> {
     ) -> Substitution {
         let sig_ty = sig_ty.cast(Interner);
         let self_subst = iter::once(&sig_ty);
-        let Some(parent) = parent.as_generic_def_id(db.upcast()) else {
+        let Some(parent) = parent.as_generic_def_id() else {
             return Substitution::from_iter(Interner, self_subst);
         };
         Substitution::from_iter(
diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs
index 3ac8cbaaf8..149e4dbaa5 100644
--- a/crates/hir-ty/src/chalk_db.rs
+++ b/crates/hir-ty/src/chalk_db.rs
@@ -13,25 +13,23 @@ use hir_def::{
     data::adt::StructFlags,
     hir::Movability,
     lang_item::{LangItem, LangItemTarget},
-    AssocItemId, BlockId, CallableDefId, GenericDefId, HasModule, ItemContainerId, Lookup,
-    TypeAliasId, VariantId,
+    AssocItemId, BlockId, GenericDefId, HasModule, ItemContainerId, Lookup, TypeAliasId, VariantId,
 };
 use hir_expand::name::name;
 
 use crate::{
     db::{HirDatabase, InternedCoroutine},
     display::HirDisplay,
-    from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
-    generics::generics,
-    make_binders, make_single_type_binders,
+    from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, make_binders,
+    make_single_type_binders,
     mapping::{from_chalk, ToChalk, TypeAliasAsValue},
     method_resolution::{TraitImpls, TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
     to_assoc_type_id, to_chalk_trait_id,
     traits::ChalkContext,
-    utils::ClosureSubst,
-    wrap_empty_binders, AliasEq, AliasTy, BoundVar, DebruijnIndex, FnDefId, Interner, ProjectionTy,
-    ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder,
-    TyExt, TyKind, WhereClause,
+    utils::{generics, ClosureSubst},
+    wrap_empty_binders, AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId,
+    Interner, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef,
+    TraitRefExt, Ty, TyBuilder, TyExt, TyKind, WhereClause,
 };
 
 pub(crate) type AssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum<Interner>;
@@ -103,7 +101,7 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
         &self,
         fn_def_id: chalk_ir::FnDefId<Interner>,
     ) -> Arc<rust_ir::FnDefDatum<Interner>> {
-        self.db.fn_def_datum(fn_def_id)
+        self.db.fn_def_datum(self.krate, fn_def_id)
     }
 
     fn impls_for_trait(
@@ -605,6 +603,7 @@ pub(crate) fn associated_ty_data_query(
     // Lower bounds -- we could/should maybe move this to a separate query in `lower`
     let type_alias_data = db.type_alias_data(type_alias);
     let generic_params = generics(db.upcast(), type_alias.into());
+    // let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST);
     let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
     let ctx = crate::TyLoweringContext::new(db, &resolver, type_alias.into())
         .with_type_param_mode(crate::lower::ParamLoweringMode::Variable);
@@ -913,13 +912,16 @@ fn type_alias_associated_ty_value(
     Arc::new(value)
 }
 
-pub(crate) fn fn_def_datum_query(db: &dyn HirDatabase, fn_def_id: FnDefId) -> Arc<FnDefDatum> {
+pub(crate) fn fn_def_datum_query(
+    db: &dyn HirDatabase,
+    _krate: CrateId,
+    fn_def_id: FnDefId,
+) -> Arc<FnDefDatum> {
     let callable_def: CallableDefId = from_chalk(db, fn_def_id);
-    let generic_def = GenericDefId::from_callable(db.upcast(), callable_def);
-    let generic_params = generics(db.upcast(), generic_def);
+    let generic_params = generics(db.upcast(), callable_def.into());
     let (sig, binders) = db.callable_item_signature(callable_def).into_value_and_skipped_binders();
     let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST);
-    let where_clauses = convert_where_clauses(db, generic_def, &bound_vars);
+    let where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars);
     let bound = rust_ir::FnDefDatumBound {
         // Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway
         inputs_and_output: chalk_ir::Binders::empty(
@@ -946,8 +948,7 @@ pub(crate) fn fn_def_datum_query(db: &dyn HirDatabase, fn_def_id: FnDefId) -> Ar
 
 pub(crate) fn fn_def_variance_query(db: &dyn HirDatabase, fn_def_id: FnDefId) -> Variances {
     let callable_def: CallableDefId = from_chalk(db, fn_def_id);
-    let generic_params =
-        generics(db.upcast(), GenericDefId::from_callable(db.upcast(), callable_def));
+    let generic_params = generics(db.upcast(), callable_def.into());
     Variances::from_iter(
         Interner,
         std::iter::repeat(chalk_ir::Variance::Invariant).take(generic_params.len()),
diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs
index 320e5bd8a2..d99ef6679e 100644
--- a/crates/hir-ty/src/chalk_ext.rs
+++ b/crates/hir-ty/src/chalk_ext.rs
@@ -12,10 +12,12 @@ use hir_def::{
 };
 
 use crate::{
-    db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
-    from_placeholder_idx, generics::generics, to_chalk_trait_id, utils::ClosureSubst, AdtId,
-    AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, ClosureId,
-    DynTy, FnPointer, ImplTraitId, InEnvironment, Interner, Lifetime, ProjectionTy,
+    db::HirDatabase,
+    from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
+    to_chalk_trait_id,
+    utils::{generics, ClosureSubst},
+    AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Canonical, CanonicalVarKinds,
+    ClosureId, DynTy, FnPointer, ImplTraitId, InEnvironment, Interner, Lifetime, ProjectionTy,
     QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyKind, TypeFlags, WhereClause,
 };
 
@@ -188,10 +190,9 @@ impl TyExt for Ty {
     fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId> {
         match *self.kind(Interner) {
             TyKind::Adt(AdtId(adt), ..) => Some(adt.into()),
-            TyKind::FnDef(callable, ..) => Some(GenericDefId::from_callable(
-                db.upcast(),
-                db.lookup_intern_callable_def(callable.into()),
-            )),
+            TyKind::FnDef(callable, ..) => {
+                Some(db.lookup_intern_callable_def(callable.into()).into())
+            }
             TyKind::AssociatedType(type_alias, ..) => Some(from_assoc_type_id(type_alias).into()),
             TyKind::Foreign(type_alias, ..) => Some(from_foreign_def_id(type_alias).into()),
             _ => None,
diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs
index 8b6cde975f..f09277a92e 100644
--- a/crates/hir-ty/src/consteval.rs
+++ b/crates/hir-ty/src/consteval.rs
@@ -15,9 +15,10 @@ use stdx::never;
 use triomphe::Arc;
 
 use crate::{
-    db::HirDatabase, generics::Generics, infer::InferenceContext, lower::ParamLoweringMode,
-    mir::monomorphize_mir_body_bad, to_placeholder_idx, Const, ConstData, ConstScalar, ConstValue,
-    GenericArg, Interner, MemoryMap, Substitution, TraitEnvironment, Ty, TyBuilder,
+    db::HirDatabase, infer::InferenceContext, lower::ParamLoweringMode,
+    mir::monomorphize_mir_body_bad, to_placeholder_idx, utils::Generics, Const, ConstData,
+    ConstScalar, ConstValue, GenericArg, Interner, MemoryMap, Substitution, TraitEnvironment, Ty,
+    TyBuilder,
 };
 
 use super::mir::{interpret_mir, lower_to_mir, pad16, MirEvalError, MirLowerError};
@@ -71,12 +72,12 @@ impl From<MirEvalError> for ConstEvalError {
     }
 }
 
-pub(crate) fn path_to_const<'g>(
+pub(crate) fn path_to_const(
     db: &dyn HirDatabase,
     resolver: &Resolver,
     path: &Path,
     mode: ParamLoweringMode,
-    args: impl FnOnce() -> Option<&'g Generics>,
+    args: impl FnOnce() -> Option<Generics>,
     debruijn: DebruijnIndex,
     expected_ty: Ty,
 ) -> Option<Const> {
@@ -89,7 +90,7 @@ pub(crate) fn path_to_const<'g>(
                 }
                 ParamLoweringMode::Variable => {
                     let args = args();
-                    match args.and_then(|args| args.type_or_const_param_idx(p.into())) {
+                    match args.as_ref().and_then(|args| args.type_or_const_param_idx(p.into())) {
                         Some(it) => ConstValue::BoundVar(BoundVar::new(debruijn, it)),
                         None => {
                             never!(
diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs
index 734aad4945..000871ed52 100644
--- a/crates/hir-ty/src/db.rs
+++ b/crates/hir-ty/src/db.rs
@@ -9,8 +9,8 @@ use base_db::{
     CrateId, Upcast,
 };
 use hir_def::{
-    db::DefDatabase, hir::ExprId, layout::TargetDataLayout, AdtId, BlockId, CallableDefId,
-    ConstParamId, DefWithBodyId, EnumVariantId, FunctionId, GeneralConstId, GenericDefId, ImplId,
+    db::DefDatabase, hir::ExprId, layout::TargetDataLayout, AdtId, BlockId, ConstParamId,
+    DefWithBodyId, EnumVariantId, FunctionId, GeneralConstId, GenericDefId, ImplId,
     LifetimeParamId, LocalFieldId, StaticId, TypeAliasId, TypeOrConstParamId, VariantId,
 };
 use la_arena::ArenaMap;
@@ -21,11 +21,11 @@ use crate::{
     chalk_db,
     consteval::ConstEvalError,
     layout::{Layout, LayoutError},
-    lower::{GenericDefaults, GenericPredicates},
     method_resolution::{InherentImpls, TraitImpls, TyFingerprint},
     mir::{BorrowckResult, MirBody, MirLowerError},
-    Binders, ClosureId, Const, FnDefId, ImplTraitId, ImplTraits, InferenceResult, Interner,
-    PolyFnSig, Substitution, TraitEnvironment, TraitRef, Ty, TyDefId, ValueTyDefId,
+    Binders, CallableDefId, ClosureId, Const, FnDefId, GenericArg, ImplTraitId, ImplTraits,
+    InferenceResult, Interner, PolyFnSig, QuantifiedWhereClause, Substitution, TraitEnvironment,
+    TraitRef, Ty, TyDefId, ValueTyDefId,
 };
 use hir_expand::name::Name;
 
@@ -80,32 +80,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
     #[salsa::cycle(crate::consteval::const_eval_discriminant_recover)]
     fn const_eval_discriminant(&self, def: EnumVariantId) -> Result<i128, ConstEvalError>;
 
-    #[salsa::invoke(crate::method_resolution::lookup_impl_method_query)]
-    fn lookup_impl_method(
-        &self,
-        env: Arc<TraitEnvironment>,
-        func: FunctionId,
-        fn_subst: Substitution,
-    ) -> (FunctionId, Substitution);
-
     // endregion:mir
 
-    #[salsa::invoke(crate::layout::layout_of_adt_query)]
-    #[salsa::cycle(crate::layout::layout_of_adt_recover)]
-    fn layout_of_adt(
-        &self,
-        def: AdtId,
-        subst: Substitution,
-        env: Arc<TraitEnvironment>,
-    ) -> Result<Arc<Layout>, LayoutError>;
-
-    #[salsa::invoke(crate::layout::layout_of_ty_query)]
-    #[salsa::cycle(crate::layout::layout_of_ty_recover)]
-    fn layout_of_ty(&self, ty: Ty, env: Arc<TraitEnvironment>) -> Result<Arc<Layout>, LayoutError>;
-
-    #[salsa::invoke(crate::layout::target_data_layout_query)]
-    fn target_data_layout(&self, krate: CrateId) -> Result<Arc<TargetDataLayout>, Arc<str>>;
-
     #[salsa::invoke(crate::lower::ty_query)]
     #[salsa::cycle(crate::lower::ty_recover)]
     fn ty(&self, def: TyDefId) -> Binders<Ty>;
@@ -128,6 +104,30 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
     #[salsa::invoke(crate::lower::field_types_query)]
     fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>>;
 
+    #[salsa::invoke(crate::layout::layout_of_adt_query)]
+    #[salsa::cycle(crate::layout::layout_of_adt_recover)]
+    fn layout_of_adt(
+        &self,
+        def: AdtId,
+        subst: Substitution,
+        env: Arc<TraitEnvironment>,
+    ) -> Result<Arc<Layout>, LayoutError>;
+
+    #[salsa::invoke(crate::layout::layout_of_ty_query)]
+    #[salsa::cycle(crate::layout::layout_of_ty_recover)]
+    fn layout_of_ty(&self, ty: Ty, env: Arc<TraitEnvironment>) -> Result<Arc<Layout>, LayoutError>;
+
+    #[salsa::invoke(crate::layout::target_data_layout_query)]
+    fn target_data_layout(&self, krate: CrateId) -> Result<Arc<TargetDataLayout>, Arc<str>>;
+
+    #[salsa::invoke(crate::method_resolution::lookup_impl_method_query)]
+    fn lookup_impl_method(
+        &self,
+        env: Arc<TraitEnvironment>,
+        func: FunctionId,
+        fn_subst: Substitution,
+    ) -> (FunctionId, Substitution);
+
     #[salsa::invoke(crate::lower::callable_item_sig)]
     fn callable_item_signature(&self, def: CallableDefId) -> PolyFnSig;
 
@@ -144,10 +144,10 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
         def: GenericDefId,
         param_id: TypeOrConstParamId,
         assoc_name: Option<Name>,
-    ) -> GenericPredicates;
+    ) -> Arc<[Binders<QuantifiedWhereClause>]>;
 
     #[salsa::invoke(crate::lower::generic_predicates_query)]
-    fn generic_predicates(&self, def: GenericDefId) -> GenericPredicates;
+    fn generic_predicates(&self, def: GenericDefId) -> Arc<[Binders<QuantifiedWhereClause>]>;
 
     #[salsa::invoke(crate::lower::trait_environment_for_body_query)]
     #[salsa::transparent]
@@ -158,7 +158,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
 
     #[salsa::invoke(crate::lower::generic_defaults_query)]
     #[salsa::cycle(crate::lower::generic_defaults_recover)]
-    fn generic_defaults(&self, def: GenericDefId) -> GenericDefaults;
+    fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<GenericArg>]>;
 
     #[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)]
     fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc<InherentImpls>;
@@ -231,7 +231,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
     ) -> sync::Arc<chalk_db::ImplDatum>;
 
     #[salsa::invoke(chalk_db::fn_def_datum_query)]
-    fn fn_def_datum(&self, fn_def_id: FnDefId) -> sync::Arc<chalk_db::FnDefDatum>;
+    fn fn_def_datum(&self, krate: CrateId, fn_def_id: FnDefId) -> sync::Arc<chalk_db::FnDefDatum>;
 
     #[salsa::invoke(chalk_db::fn_def_variance_query)]
     fn fn_def_variance(&self, fn_def_id: FnDefId) -> chalk_db::Variances;
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index 458970aa70..cd31845a51 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -21,8 +21,8 @@ use hir_def::{
     path::{Path, PathKind},
     type_ref::{TraitBoundModifier, TypeBound, TypeRef},
     visibility::Visibility,
-    GenericDefId, HasModule, ImportPathConfig, ItemContainerId, LocalFieldId, Lookup, ModuleDefId,
-    ModuleId, TraitId,
+    HasModule, ImportPathConfig, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, ModuleId,
+    TraitId,
 };
 use hir_expand::name::Name;
 use intern::{Internable, Interned};
@@ -36,13 +36,12 @@ use crate::{
     consteval::try_const_usize,
     db::{HirDatabase, InternedClosure},
     from_assoc_type_id, from_foreign_def_id, from_placeholder_idx,
-    generics::generics,
     layout::Layout,
     lt_from_placeholder_idx,
     mapping::from_chalk,
     mir::pad16,
     primitive, to_assoc_type_id,
-    utils::{self, detect_variant_from_bytes, ClosureSubst},
+    utils::{self, detect_variant_from_bytes, generics, ClosureSubst},
     AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, ConcreteConst, Const,
     ConstScalar, ConstValue, DomainGoal, FnAbi, GenericArg, ImplTraitId, Interner, Lifetime,
     LifetimeData, LifetimeOutlives, MemoryMap, Mutability, OpaqueTy, ProjectionTy, ProjectionTyExt,
@@ -494,7 +493,7 @@ impl HirDisplay for Const {
             ConstValue::Placeholder(idx) => {
                 let id = from_placeholder_idx(f.db, *idx);
                 let generics = generics(f.db.upcast(), id.parent);
-                let param_data = &generics[id.local_id];
+                let param_data = &generics.params[id.local_id];
                 write!(f, "{}", param_data.name().unwrap().display(f.db.upcast()))?;
                 Ok(())
             }
@@ -988,9 +987,8 @@ impl HirDisplay for Ty {
                 f.end_location_link();
 
                 if parameters.len(Interner) > 0 {
-                    let generic_def_id = GenericDefId::from_callable(db.upcast(), def);
-                    let generics = generics(db.upcast(), generic_def_id);
-                    let (parent_len, self_param, type_, const_, impl_, lifetime) =
+                    let generics = generics(db.upcast(), def.into());
+                    let (parent_len, self_, type_, const_, impl_, lifetime) =
                         generics.provenance_split();
                     let parameters = parameters.as_slice(Interner);
                     // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
@@ -998,14 +996,13 @@ impl HirDisplay for Ty {
                         // `parameters` are in the order of fn's params (including impl traits), fn's lifetimes
                         // parent's params (those from enclosing impl or trait, if any).
                         let (fn_params, other) =
-                            parameters.split_at(self_param as usize + type_ + const_ + lifetime);
+                            parameters.split_at(self_ + type_ + const_ + lifetime);
                         let (_impl, parent_params) = other.split_at(impl_);
                         debug_assert_eq!(parent_params.len(), parent_len);
 
                         let parent_params =
-                            generic_args_sans_defaults(f, Some(generic_def_id), parent_params);
-                        let fn_params =
-                            generic_args_sans_defaults(f, Some(generic_def_id), fn_params);
+                            generic_args_sans_defaults(f, Some(def.into()), parent_params);
+                        let fn_params = generic_args_sans_defaults(f, Some(def.into()), fn_params);
 
                         write!(f, "<")?;
                         hir_fmt_generic_arguments(f, parent_params, None)?;
@@ -1218,7 +1215,7 @@ impl HirDisplay for Ty {
             TyKind::Placeholder(idx) => {
                 let id = from_placeholder_idx(db, *idx);
                 let generics = generics(db.upcast(), id.parent);
-                let param_data = &generics[id.local_id];
+                let param_data = &generics.params[id.local_id];
                 match param_data {
                     TypeOrConstParamData::TypeParamData(p) => match p.provenance {
                         TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
@@ -1800,7 +1797,7 @@ impl HirDisplay for LifetimeData {
             LifetimeData::Placeholder(idx) => {
                 let id = lt_from_placeholder_idx(f.db, *idx);
                 let generics = generics(f.db.upcast(), id.parent);
-                let param_data = &generics[id.local_id];
+                let param_data = &generics.params[id.local_id];
                 write!(f, "{}", param_data.name.display(f.db.upcast()))?;
                 Ok(())
             }
diff --git a/crates/hir-ty/src/generics.rs b/crates/hir-ty/src/generics.rs
deleted file mode 100644
index 7f8dd920e6..0000000000
--- a/crates/hir-ty/src/generics.rs
+++ /dev/null
@@ -1,262 +0,0 @@
-//! Utilities for working with generics.
-//!
-//! The layout for generics as expected by chalk are as follows:
-//! - Optional Self parameter
-//! - Type or Const parameters
-//! - Lifetime parameters
-//! - Parent parameters
-//!
-//! where parent follows the same scheme.
-use std::ops;
-
-use chalk_ir::{cast::Cast as _, BoundVar, DebruijnIndex};
-use hir_def::{
-    db::DefDatabase,
-    generics::{
-        GenericParamDataRef, GenericParams, LifetimeParamData, TypeOrConstParamData,
-        TypeParamProvenance,
-    },
-    ConstParamId, GenericDefId, GenericParamId, ItemContainerId, LifetimeParamId,
-    LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
-};
-use intern::Interned;
-
-use crate::{db::HirDatabase, lt_to_placeholder_idx, to_placeholder_idx, Interner, Substitution};
-
-pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
-    let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def)));
-    Generics { def, params: db.generic_params(def), parent_generics }
-}
-#[derive(Clone, Debug)]
-pub(crate) struct Generics {
-    def: GenericDefId,
-    params: Interned<GenericParams>,
-    parent_generics: Option<Box<Generics>>,
-}
-
-impl<T> ops::Index<T> for Generics
-where
-    GenericParams: ops::Index<T>,
-{
-    type Output = <GenericParams as ops::Index<T>>::Output;
-    fn index(&self, index: T) -> &Self::Output {
-        &self.params[index]
-    }
-}
-
-impl Generics {
-    pub(crate) fn def(&self) -> GenericDefId {
-        self.def
-    }
-
-    pub(crate) fn iter_id(&self) -> impl Iterator<Item = GenericParamId> + '_ {
-        self.iter_self_id().chain(self.iter_parent_id())
-    }
-
-    pub(crate) fn iter_self_id(&self) -> impl Iterator<Item = GenericParamId> + '_ {
-        self.iter_self().map(|(id, _)| id)
-    }
-
-    fn iter_parent_id(&self) -> impl Iterator<Item = GenericParamId> + '_ {
-        self.iter_parent().map(|(id, _)| id)
-    }
-
-    pub(crate) fn iter_self_type_or_consts(
-        &self,
-    ) -> impl DoubleEndedIterator<Item = (LocalTypeOrConstParamId, &TypeOrConstParamData)> {
-        self.params.iter_type_or_consts()
-    }
-
-    /// Iterate over the params followed by the parent params.
-    pub(crate) fn iter(
-        &self,
-    ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'_>)> + '_ {
-        self.iter_self().chain(self.iter_parent())
-    }
-
-    /// Iterate over the params without parent params.
-    pub(crate) fn iter_self(
-        &self,
-    ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'_>)> + '_ {
-        self.params
-            .iter_type_or_consts()
-            .map(from_toc_id(self))
-            .chain(self.params.iter_lt().map(from_lt_id(self)))
-    }
-
-    /// Iterator over types and const params of parent.
-    fn iter_parent(
-        &self,
-    ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'_>)> + '_ {
-        self.parent_generics().into_iter().flat_map(|it| {
-            let lt_iter = it.params.iter_lt().map(from_lt_id(it));
-            it.params.iter_type_or_consts().map(from_toc_id(it)).chain(lt_iter)
-        })
-    }
-
-    /// Returns total number of generic parameters in scope, including those from parent.
-    pub(crate) fn len(&self) -> usize {
-        let parent = self.parent_generics().map_or(0, Generics::len);
-        let child = self.params.len();
-        parent + child
-    }
-
-    /// Returns numbers of generic parameters excluding those from parent.
-    pub(crate) fn len_self(&self) -> usize {
-        self.params.len()
-    }
-
-    /// (parent total, self param, type params, const params, impl trait list, lifetimes)
-    pub(crate) fn provenance_split(&self) -> (usize, bool, usize, usize, usize, usize) {
-        let mut self_param = false;
-        let mut type_params = 0;
-        let mut impl_trait_params = 0;
-        let mut const_params = 0;
-        self.params.iter_type_or_consts().for_each(|(_, data)| match data {
-            TypeOrConstParamData::TypeParamData(p) => match p.provenance {
-                TypeParamProvenance::TypeParamList => type_params += 1,
-                TypeParamProvenance::TraitSelf => self_param |= true,
-                TypeParamProvenance::ArgumentImplTrait => impl_trait_params += 1,
-            },
-            TypeOrConstParamData::ConstParamData(_) => const_params += 1,
-        });
-
-        let lifetime_params = self.params.iter_lt().count();
-
-        let parent_len = self.parent_generics().map_or(0, Generics::len);
-        (parent_len, self_param, type_params, const_params, impl_trait_params, lifetime_params)
-    }
-
-    pub(crate) fn type_or_const_param_idx(&self, param: TypeOrConstParamId) -> Option<usize> {
-        self.find_type_or_const_param(param)
-    }
-
-    fn find_type_or_const_param(&self, param: TypeOrConstParamId) -> Option<usize> {
-        if param.parent == self.def {
-            let idx = param.local_id.into_raw().into_u32() as usize;
-            debug_assert!(idx <= self.params.type_or_consts.len());
-            Some(idx)
-        } else {
-            debug_assert_eq!(self.parent_generics().map(|it| it.def), Some(param.parent));
-            self.parent_generics()
-                .and_then(|g| g.find_type_or_const_param(param))
-                // Remember that parent parameters come after parameters for self.
-                .map(|idx| self.len_self() + idx)
-        }
-    }
-
-    pub(crate) fn lifetime_idx(&self, lifetime: LifetimeParamId) -> Option<usize> {
-        self.find_lifetime(lifetime)
-    }
-
-    fn find_lifetime(&self, lifetime: LifetimeParamId) -> Option<usize> {
-        if lifetime.parent == self.def {
-            let idx = lifetime.local_id.into_raw().into_u32() as usize;
-            debug_assert!(idx <= self.params.lifetimes.len());
-            Some(self.params.type_or_consts.len() + idx)
-        } else {
-            debug_assert_eq!(self.parent_generics().map(|it| it.def), Some(lifetime.parent));
-            self.parent_generics()
-                .and_then(|g| g.find_lifetime(lifetime))
-                .map(|idx| self.len_self() + idx)
-        }
-    }
-
-    pub(crate) fn parent_generics(&self) -> Option<&Generics> {
-        self.parent_generics.as_deref()
-    }
-
-    pub(crate) fn parent_or_self(&self) -> &Generics {
-        self.parent_generics.as_deref().unwrap_or(self)
-    }
-
-    /// Returns a Substitution that replaces each parameter by a bound variable.
-    pub(crate) fn bound_vars_subst(
-        &self,
-        db: &dyn HirDatabase,
-        debruijn: DebruijnIndex,
-    ) -> Substitution {
-        Substitution::from_iter(
-            Interner,
-            self.iter_id().enumerate().map(|(idx, id)| match id {
-                GenericParamId::ConstParamId(id) => BoundVar::new(debruijn, idx)
-                    .to_const(Interner, db.const_param_ty(id))
-                    .cast(Interner),
-                GenericParamId::TypeParamId(_) => {
-                    BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner)
-                }
-                GenericParamId::LifetimeParamId(_) => {
-                    BoundVar::new(debruijn, idx).to_lifetime(Interner).cast(Interner)
-                }
-            }),
-        )
-    }
-
-    /// Returns a Substitution that replaces each parameter by itself (i.e. `Ty::Param`).
-    pub(crate) fn placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution {
-        Substitution::from_iter(
-            Interner,
-            self.iter_id().map(|id| match id {
-                GenericParamId::TypeParamId(id) => {
-                    to_placeholder_idx(db, id.into()).to_ty(Interner).cast(Interner)
-                }
-                GenericParamId::ConstParamId(id) => to_placeholder_idx(db, id.into())
-                    .to_const(Interner, db.const_param_ty(id))
-                    .cast(Interner),
-                GenericParamId::LifetimeParamId(id) => {
-                    lt_to_placeholder_idx(db, id).to_lifetime(Interner).cast(Interner)
-                }
-            }),
-        )
-    }
-}
-
-fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option<GenericDefId> {
-    let container = match def {
-        GenericDefId::FunctionId(it) => it.lookup(db).container,
-        GenericDefId::TypeAliasId(it) => it.lookup(db).container,
-        GenericDefId::ConstId(it) => it.lookup(db).container,
-        GenericDefId::AdtId(_)
-        | GenericDefId::TraitId(_)
-        | GenericDefId::ImplId(_)
-        | GenericDefId::TraitAliasId(_) => return None,
-    };
-
-    match container {
-        ItemContainerId::ImplId(it) => Some(it.into()),
-        ItemContainerId::TraitId(it) => Some(it.into()),
-        ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
-    }
-}
-
-fn from_toc_id<'a>(
-    it: &'a Generics,
-) -> impl Fn(
-    (LocalTypeOrConstParamId, &'a TypeOrConstParamData),
-) -> (GenericParamId, GenericParamDataRef<'a>) {
-    move |(local_id, p): (_, _)| {
-        let id = TypeOrConstParamId { parent: it.def, local_id };
-        match p {
-            TypeOrConstParamData::TypeParamData(p) => (
-                GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)),
-                GenericParamDataRef::TypeParamData(p),
-            ),
-            TypeOrConstParamData::ConstParamData(p) => (
-                GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)),
-                GenericParamDataRef::ConstParamData(p),
-            ),
-        }
-    }
-}
-
-fn from_lt_id<'a>(
-    it: &'a Generics,
-) -> impl Fn((LocalLifetimeParamId, &'a LifetimeParamData)) -> (GenericParamId, GenericParamDataRef<'a>)
-{
-    move |(local_id, p): (_, _)| {
-        (
-            GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }),
-            GenericParamDataRef::LifetimeParamData(p),
-        )
-    }
-}
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 96431ba4ce..25bce0b31a 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -49,7 +49,6 @@ use hir_def::{
 use hir_expand::name::{name, Name};
 use indexmap::IndexSet;
 use la_arena::{ArenaMap, Entry};
-use once_cell::unsync::OnceCell;
 use rustc_hash::{FxHashMap, FxHashSet};
 use stdx::{always, never};
 use triomphe::Arc;
@@ -57,15 +56,14 @@ use triomphe::Arc;
 use crate::{
     db::HirDatabase,
     error_lifetime, fold_tys,
-    generics::Generics,
     infer::{coerce::CoerceMany, unify::InferenceTable},
     lower::ImplTraitLoweringMode,
     to_assoc_type_id,
     traits::FnTrait,
-    utils::{InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder},
+    utils::{Generics, InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder},
     AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, Goal, ImplTraitId,
-    ImplTraitIdx, InEnvironment, Interner, Lifetime, OpaqueTyId, ParamLoweringMode, ProjectionTy,
-    Substitution, TraitEnvironment, Ty, TyBuilder, TyExt,
+    ImplTraitIdx, InEnvironment, Interner, Lifetime, OpaqueTyId, ProjectionTy, Substitution,
+    TraitEnvironment, Ty, TyBuilder, TyExt,
 };
 
 // This lint has a false positive here. See the link below for details.
@@ -528,7 +526,6 @@ pub(crate) struct InferenceContext<'a> {
     pub(crate) owner: DefWithBodyId,
     pub(crate) body: &'a Body,
     pub(crate) resolver: Resolver,
-    generics: OnceCell<Option<Generics>>,
     table: unify::InferenceTable<'a>,
     /// The traits in scope, disregarding block modules. This is used for caching purposes.
     traits_in_scope: FxHashSet<TraitId>,
@@ -614,7 +611,6 @@ impl<'a> InferenceContext<'a> {
     ) -> Self {
         let trait_env = db.trait_environment_for_body(owner);
         InferenceContext {
-            generics: OnceCell::new(),
             result: InferenceResult::default(),
             table: unify::InferenceTable::new(db, trait_env),
             tuple_field_accesses_rev: Default::default(),
@@ -636,14 +632,8 @@ impl<'a> InferenceContext<'a> {
         }
     }
 
-    pub(crate) fn generics(&self) -> Option<&Generics> {
-        self.generics
-            .get_or_init(|| {
-                self.resolver
-                    .generic_def()
-                    .map(|def| crate::generics::generics(self.db.upcast(), def))
-            })
-            .as_ref()
+    pub(crate) fn generics(&self) -> Option<Generics> {
+        Some(crate::utils::generics(self.db.upcast(), self.resolver.generic_def()?))
     }
 
     // FIXME: This function should be private in module. It is currently only used in the consteval, since we need
@@ -791,8 +781,7 @@ impl<'a> InferenceContext<'a> {
 
     fn collect_fn(&mut self, func: FunctionId) {
         let data = self.db.function_data(func);
-        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into())
-            .with_type_param_mode(ParamLoweringMode::Placeholder)
+        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, func.into())
             .with_impl_trait_mode(ImplTraitLoweringMode::Param);
         let mut param_tys =
             data.params.iter().map(|type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>();
@@ -827,7 +816,6 @@ impl<'a> InferenceContext<'a> {
         let return_ty = &*data.ret_type;
 
         let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into())
-            .with_type_param_mode(ParamLoweringMode::Placeholder)
             .with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
         let return_ty = ctx.lower_ty(return_ty);
         let return_ty = self.insert_type_vars(return_ty);
@@ -1275,7 +1263,7 @@ impl<'a> InferenceContext<'a> {
                 forbid_unresolved_segments((ty, Some(var.into())), unresolved)
             }
             TypeNs::SelfType(impl_id) => {
-                let generics = crate::generics::generics(self.db.upcast(), impl_id.into());
+                let generics = crate::utils::generics(self.db.upcast(), impl_id.into());
                 let substs = generics.placeholder_subst(self.db);
                 let mut ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs);
 
diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs
index b7c7b66545..a25498eff3 100644
--- a/crates/hir-ty/src/infer/closure.rs
+++ b/crates/hir-ty/src/infer/closure.rs
@@ -22,13 +22,11 @@ use stdx::never;
 
 use crate::{
     db::{HirDatabase, InternedClosure},
-    error_lifetime, from_chalk_trait_id, from_placeholder_idx,
-    generics::Generics,
-    make_binders,
+    error_lifetime, from_chalk_trait_id, from_placeholder_idx, make_binders,
     mir::{BorrowKind, MirSpan, MutBorrowKind, ProjectionElem},
     to_chalk_trait_id,
     traits::FnTrait,
-    utils::{self, elaborate_clause_supertraits},
+    utils::{self, elaborate_clause_supertraits, Generics},
     Adjust, Adjustment, AliasEq, AliasTy, Binders, BindingMode, ChalkTraitId, ClosureId, DynTy,
     DynTyExt, FnAbi, FnPointer, FnSig, Interner, OpaqueTy, ProjectionTyExt, Substitution, Ty,
     TyExt, WhereClause,
@@ -339,7 +337,7 @@ impl CapturedItemWithoutTy {
         fn replace_placeholder_with_binder(ctx: &mut InferenceContext<'_>, ty: Ty) -> Binders<Ty> {
             struct Filler<'a> {
                 db: &'a dyn HirDatabase,
-                generics: &'a Generics,
+                generics: Generics,
             }
             impl FallibleTypeFolder<Interner> for Filler<'_> {
                 type Error = ();
@@ -382,7 +380,7 @@ impl CapturedItemWithoutTy {
             };
             let filler = &mut Filler { db: ctx.db, generics };
             let result = ty.clone().try_fold_with(filler, DebruijnIndex::INNERMOST).unwrap_or(ty);
-            make_binders(ctx.db, filler.generics, result)
+            make_binders(ctx.db, &filler.generics, result)
         }
     }
 }
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index 3647243537..4c12786362 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -13,7 +13,7 @@ use hir_def::{
     },
     lang_item::{LangItem, LangItemTarget},
     path::{GenericArgs, Path},
-    BlockId, FieldId, GenericDefId, GenericParamId, ItemContainerId, Lookup, TupleFieldId, TupleId,
+    BlockId, FieldId, GenericParamId, ItemContainerId, Lookup, TupleFieldId, TupleId,
 };
 use hir_expand::name::{name, Name};
 use stdx::always;
@@ -24,7 +24,6 @@ use crate::{
     consteval,
     db::{InternedClosure, InternedCoroutine},
     error_lifetime,
-    generics::{generics, Generics},
     infer::{
         coerce::{CoerceMany, CoercionCause},
         find_continuable,
@@ -40,6 +39,7 @@ use crate::{
     primitive::{self, UintTy},
     static_lifetime, to_chalk_trait_id,
     traits::FnTrait,
+    utils::{generics, Generics},
     Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, FnAbi, FnPointer, FnSig,
     FnSubst, Interner, Rawness, Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder,
     TyExt, TyKind,
@@ -1830,13 +1830,13 @@ impl InferenceContext<'_> {
     ) -> Substitution {
         let (
             parent_params,
-            has_self_param,
+            self_params,
             type_params,
             const_params,
             impl_trait_params,
             lifetime_params,
         ) = def_generics.provenance_split();
-        assert!(!has_self_param); // method shouldn't have another Self param
+        assert_eq!(self_params, 0); // method shouldn't have another Self param
         let total_len =
             parent_params + type_params + const_params + impl_trait_params + lifetime_params;
         let mut substs = Vec::with_capacity(total_len);
@@ -1844,11 +1844,13 @@ impl InferenceContext<'_> {
         // handle provided arguments
         if let Some(generic_args) = generic_args {
             // if args are provided, it should be all of them, but we can't rely on that
-            let self_params = type_params + const_params + lifetime_params;
-            for (arg, kind_id) in
-                generic_args.args.iter().zip(def_generics.iter_self_id()).take(self_params)
+            for (arg, kind_id) in generic_args
+                .args
+                .iter()
+                .take(type_params + const_params + lifetime_params)
+                .zip(def_generics.iter_id())
             {
-                let arg = generic_arg_to_chalk(
+                if let Some(g) = generic_arg_to_chalk(
                     self.db,
                     kind_id,
                     arg,
@@ -1867,8 +1869,9 @@ impl InferenceContext<'_> {
                         )
                     },
                     |this, lt_ref| this.make_lifetime(lt_ref),
-                );
-                substs.push(arg);
+                ) {
+                    substs.push(g);
+                }
             }
         };
 
@@ -1895,8 +1898,7 @@ impl InferenceContext<'_> {
         let callable_ty = self.resolve_ty_shallow(callable_ty);
         if let TyKind::FnDef(fn_def, parameters) = callable_ty.kind(Interner) {
             let def: CallableDefId = from_chalk(self.db, *fn_def);
-            let generic_predicates =
-                self.db.generic_predicates(GenericDefId::from_callable(self.db.upcast(), def));
+            let generic_predicates = self.db.generic_predicates(def.into());
             for predicate in generic_predicates.iter() {
                 let (predicate, binders) = predicate
                     .clone()
diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs
index 490ecfd7fa..9a1835b625 100644
--- a/crates/hir-ty/src/infer/path.rs
+++ b/crates/hir-ty/src/infer/path.rs
@@ -12,10 +12,11 @@ use stdx::never;
 use crate::{
     builder::ParamKind,
     consteval, error_lifetime,
-    generics::generics,
     method_resolution::{self, VisibleFromModule},
-    to_chalk_trait_id, InferenceDiagnostic, Interner, Substitution, TraitRef, TraitRefExt, Ty,
-    TyBuilder, TyExt, TyKind, ValueTyDefId,
+    to_chalk_trait_id,
+    utils::generics,
+    InferenceDiagnostic, Interner, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt,
+    TyKind, ValueTyDefId,
 };
 
 use super::{ExprOrPatId, InferenceContext};
@@ -41,7 +42,14 @@ impl InferenceContext<'_> {
     fn resolve_value_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<ValuePathResolution> {
         let (value, self_subst) = self.resolve_value_path_inner(path, id)?;
 
-        let value_def: ValueTyDefId = match value {
+        let value_def = match value {
+            ValueNs::LocalBinding(pat) => match self.result.type_of_binding.get(pat) {
+                Some(ty) => return Some(ValuePathResolution::NonGeneric(ty.clone())),
+                None => {
+                    never!("uninferred pattern?");
+                    return None;
+                }
+            },
             ValueNs::FunctionId(it) => it.into(),
             ValueNs::ConstId(it) => it.into(),
             ValueNs::StaticId(it) => it.into(),
@@ -55,79 +63,48 @@ impl InferenceContext<'_> {
 
                 it.into()
             }
-            ValueNs::LocalBinding(pat) => {
-                return match self.result.type_of_binding.get(pat) {
-                    Some(ty) => Some(ValuePathResolution::NonGeneric(ty.clone())),
-                    None => {
-                        never!("uninferred pattern?");
-                        None
-                    }
-                }
-            }
             ValueNs::ImplSelf(impl_id) => {
-                let generics = crate::generics::generics(self.db.upcast(), impl_id.into());
+                let generics = crate::utils::generics(self.db.upcast(), impl_id.into());
                 let substs = generics.placeholder_subst(self.db);
                 let ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs);
-                return if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() {
-                    Some(ValuePathResolution::GenericDef(
+                if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() {
+                    return Some(ValuePathResolution::GenericDef(
                         struct_id.into(),
                         struct_id.into(),
                         substs.clone(),
-                    ))
+                    ));
                 } else {
                     // FIXME: report error, invalid Self reference
-                    None
-                };
+                    return None;
+                }
             }
             ValueNs::GenericParam(it) => {
                 return Some(ValuePathResolution::NonGeneric(self.db.const_param_ty(it)))
             }
         };
 
-        let generic_def_id = value_def.to_generic_def_id(self.db);
-        let Some(generic_def) = generic_def_id else {
-            // `value_def` is the kind of item that can never be generic (i.e. statics, at least
-            // currently). We can just skip the binders to get its type.
-            let (ty, binders) = self.db.value_ty(value_def)?.into_value_and_skipped_binders();
-            stdx::always!(binders.is_empty(Interner), "non-empty binders for non-generic def",);
-            return Some(ValuePathResolution::NonGeneric(ty));
-        };
-
         let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
         let substs = ctx.substs_from_path(path, value_def, true);
         let substs = substs.as_slice(Interner);
-
-        if let ValueNs::EnumVariantId(_) = value {
-            let mut it = self_subst
-                .as_ref()
-                .map_or(&[][..], |s| s.as_slice(Interner))
-                .iter()
-                .chain(substs)
-                .cloned();
-            let builder = TyBuilder::subst_for_def(self.db, generic_def, None);
-            let substs = builder
-                .fill(|x| {
-                    it.next().unwrap_or_else(|| match x {
-                        ParamKind::Type => {
-                            self.result.standard_types.unknown.clone().cast(Interner)
-                        }
-                        ParamKind::Const(ty) => consteval::unknown_const_as_generic(ty.clone()),
-                        ParamKind::Lifetime => error_lifetime().cast(Interner),
-                    })
-                })
-                .build();
-
-            return Some(ValuePathResolution::GenericDef(value_def, generic_def, substs));
-        }
-
         let parent_substs = self_subst.or_else(|| {
-            let generics = generics(self.db.upcast(), generic_def_id?);
+            let generics = generics(self.db.upcast(), value_def.to_generic_def_id()?);
             let parent_params_len = generics.parent_generics()?.len();
             let parent_args = &substs[substs.len() - parent_params_len..];
             Some(Substitution::from_iter(Interner, parent_args))
         });
         let parent_substs_len = parent_substs.as_ref().map_or(0, |s| s.len(Interner));
         let mut it = substs.iter().take(substs.len() - parent_substs_len).cloned();
+
+        let Some(generic_def) = value_def.to_generic_def_id() else {
+            // `value_def` is the kind of item that can never be generic (i.e. statics, at least
+            // currently). We can just skip the binders to get its type.
+            let (ty, binders) = self.db.value_ty(value_def)?.into_value_and_skipped_binders();
+            stdx::always!(
+                parent_substs.is_none() && binders.is_empty(Interner),
+                "non-empty binders for non-generic def",
+            );
+            return Some(ValuePathResolution::NonGeneric(ty));
+        };
         let builder = TyBuilder::subst_for_def(self.db, generic_def, parent_substs);
         let substs = builder
             .fill(|x| {
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index 07c0cf920f..9d596e957b 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -22,7 +22,6 @@ extern crate ra_ap_rustc_pattern_analysis as rustc_pattern_analysis;
 mod builder;
 mod chalk_db;
 mod chalk_ext;
-mod generics;
 mod infer;
 mod inhabitedness;
 mod interner;
@@ -60,7 +59,7 @@ use chalk_ir::{
     NoSolution,
 };
 use either::Either;
-use hir_def::{hir::ExprId, type_ref::Rawness, CallableDefId, GeneralConstId, TypeOrConstParamId};
+use hir_def::{hir::ExprId, type_ref::Rawness, GeneralConstId, TypeOrConstParamId};
 use hir_expand::name;
 use la_arena::{Arena, Idx};
 use mir::{MirEvalError, VTableMap};
@@ -68,10 +67,11 @@ use rustc_hash::{FxHashMap, FxHashSet};
 use syntax::ast::{make, ConstArg};
 use traits::FnTrait;
 use triomphe::Arc;
+use utils::Generics;
 
 use crate::{
-    consteval::unknown_const, db::HirDatabase, display::HirDisplay, generics::Generics,
-    infer::unify::InferenceTable,
+    consteval::unknown_const, db::HirDatabase, display::HirDisplay, infer::unify::InferenceTable,
+    utils::generics,
 };
 
 pub use autoderef::autoderef;
@@ -84,8 +84,8 @@ pub use infer::{
 };
 pub use interner::Interner;
 pub use lower::{
-    associated_type_shorthand_candidates, ImplTraitLoweringMode, ParamLoweringMode, TyDefId,
-    TyLoweringContext, ValueTyDefId,
+    associated_type_shorthand_candidates, CallableDefId, ImplTraitLoweringMode, ParamLoweringMode,
+    TyDefId, TyLoweringContext, ValueTyDefId,
 };
 pub use mapping::{
     from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
@@ -289,7 +289,7 @@ impl Hash for ConstScalar {
 
 /// Return an index of a parameter in the generic type parameter list by it's id.
 pub fn param_idx(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option<usize> {
-    generics::generics(db.upcast(), id.parent).type_or_const_param_idx(id)
+    generics(db.upcast(), id.parent).type_or_const_param_idx(id)
 }
 
 pub(crate) fn wrap_empty_binders<T>(value: T) -> Binders<T>
@@ -330,15 +330,18 @@ pub(crate) fn make_single_type_binders<T: HasInterner<Interner = Interner>>(
     )
 }
 
-pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>(
+pub(crate) fn make_binders_with_count<T: HasInterner<Interner = Interner>>(
     db: &dyn HirDatabase,
+    count: usize,
     generics: &Generics,
     value: T,
 ) -> Binders<T> {
+    let it = generics.iter_id().take(count);
+
     Binders::new(
         VariableKinds::from_iter(
             Interner,
-            generics.iter_id().map(|x| match x {
+            it.map(|x| match x {
                 hir_def::GenericParamId::ConstParamId(id) => {
                     chalk_ir::VariableKind::Const(db.const_param_ty(id))
                 }
@@ -352,6 +355,14 @@ pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>(
     )
 }
 
+pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>(
+    db: &dyn HirDatabase,
+    generics: &Generics,
+    value: T,
+) -> Binders<T> {
+    make_binders_with_count(db, usize::MAX, generics, value)
+}
+
 // FIXME: get rid of this, just replace it by FnPointer
 /// A function signature as seen by type inference: Several parameter types and
 /// one return type.
@@ -513,16 +524,14 @@ pub type PolyFnSig = Binders<CallableSig>;
 
 impl CallableSig {
     pub fn from_params_and_return(
-        params: impl ExactSizeIterator<Item = Ty>,
+        mut params: Vec<Ty>,
         ret: Ty,
         is_varargs: bool,
         safety: Safety,
         abi: FnAbi,
     ) -> CallableSig {
-        let mut params_and_return = Vec::with_capacity(params.len() + 1);
-        params_and_return.extend(params);
-        params_and_return.push(ret);
-        CallableSig { params_and_return: params_and_return.into(), is_varargs, safety, abi }
+        params.push(ret);
+        CallableSig { params_and_return: params.into(), is_varargs, safety, abi }
     }
 
     pub fn from_def(db: &dyn HirDatabase, def: FnDefId, substs: &Substitution) -> CallableSig {
@@ -937,7 +946,8 @@ pub fn callable_sig_from_fn_trait(
                     .as_tuple()?
                     .iter(Interner)
                     .map(|it| it.assert_ty_ref(Interner))
-                    .cloned();
+                    .cloned()
+                    .collect();
 
                 return Some((
                     fn_x,
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index fd215adde2..2e100d5c55 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -8,10 +8,12 @@
 use std::{
     cell::{Cell, RefCell, RefMut},
     iter,
-    ops::{self, Not as _},
 };
 
-use base_db::{salsa::Cycle, CrateId};
+use base_db::{
+    salsa::{Cycle, InternValueTrivial},
+    CrateId,
+};
 use chalk_ir::{
     cast::Cast,
     fold::{Shift, TypeFoldable},
@@ -35,17 +37,15 @@ use hir_def::{
     type_ref::{
         ConstRef, LifetimeRef, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef,
     },
-    AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId,
-    FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstLoc, ItemContainerId,
-    LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId,
-    TypeOwnerId, UnionId, VariantId,
+    AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FunctionId,
+    GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstLoc, ItemContainerId, LocalFieldId,
+    Lookup, ModuleDefId, StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId, TypeOwnerId,
+    UnionId, VariantId,
 };
 use hir_expand::{name::Name, ExpandResult};
 use intern::Interned;
 use la_arena::{Arena, ArenaMap};
-use once_cell::unsync::OnceCell;
 use rustc_hash::FxHashSet;
-use rustc_pattern_analysis::Captures;
 use smallvec::SmallVec;
 use stdx::{impl_from, never};
 use syntax::ast;
@@ -58,13 +58,12 @@ use crate::{
         unknown_const_as_generic,
     },
     db::HirDatabase,
-    error_lifetime,
-    generics::{generics, Generics},
-    make_binders,
+    error_lifetime, make_binders,
     mapping::{from_chalk_trait_id, lt_to_placeholder_idx, ToChalk},
     static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
     utils::{
-        all_super_trait_refs, associated_type_by_name_including_super_traits, InTypeConstIdMetadata,
+        self, all_super_trait_refs, associated_type_by_name_including_super_traits, generics,
+        Generics, InTypeConstIdMetadata,
     },
     AliasEq, AliasTy, Binders, BoundVar, CallableSig, Const, ConstScalar, DebruijnIndex, DynTy,
     FnAbi, FnPointer, FnSig, FnSubst, ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime,
@@ -122,7 +121,6 @@ impl ImplTraitLoweringState {
 pub struct TyLoweringContext<'a> {
     pub db: &'a dyn HirDatabase,
     resolver: &'a Resolver,
-    generics: OnceCell<Option<Generics>>,
     in_binders: DebruijnIndex,
     // FIXME: Should not be an `Option` but `Resolver` currently does not return owners in all cases
     // where expected
@@ -154,7 +152,6 @@ impl<'a> TyLoweringContext<'a> {
         Self {
             db,
             resolver,
-            generics: OnceCell::new(),
             owner,
             in_binders,
             impl_trait_mode,
@@ -177,7 +174,6 @@ impl<'a> TyLoweringContext<'a> {
             impl_trait_mode,
             expander: RefCell::new(expander),
             unsized_types: RefCell::new(unsized_types),
-            generics: self.generics.clone(),
             ..*self
         };
         let result = f(&new_ctx);
@@ -249,10 +245,8 @@ impl<'a> TyLoweringContext<'a> {
         )
     }
 
-    fn generics(&self) -> Option<&Generics> {
-        self.generics
-            .get_or_init(|| self.resolver.generic_def().map(|def| generics(self.db.upcast(), def)))
-            .as_ref()
+    fn generics(&self) -> Option<Generics> {
+        Some(generics(self.db.upcast(), self.resolver.generic_def()?))
     }
 
     pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
@@ -380,7 +374,7 @@ impl<'a> TyLoweringContext<'a> {
                         counter.set(idx + count_impl_traits(type_ref) as u16);
                         let (
                             _parent_params,
-                            self_param,
+                            self_params,
                             type_params,
                             const_params,
                             _impl_trait_params,
@@ -391,7 +385,7 @@ impl<'a> TyLoweringContext<'a> {
                             .provenance_split();
                         TyKind::BoundVar(BoundVar::new(
                             self.in_binders,
-                            idx as usize + self_param as usize + type_params + const_params,
+                            idx as usize + self_params + type_params + const_params,
                         ))
                         .intern(Interner)
                     }
@@ -711,8 +705,7 @@ impl<'a> TyLoweringContext<'a> {
                     None,
                 );
 
-                let len_self =
-                    crate::generics::generics(self.db.upcast(), associated_ty.into()).len_self();
+                let len_self = utils::generics(self.db.upcast(), associated_ty.into()).len_self();
 
                 let substs = Substitution::from_iter(
                     Interner,
@@ -822,14 +815,14 @@ impl<'a> TyLoweringContext<'a> {
         let def_generics = generics(self.db.upcast(), def);
         let (
             parent_params,
-            self_param,
+            self_params,
             type_params,
             const_params,
             impl_trait_params,
             lifetime_params,
         ) = def_generics.provenance_split();
         let item_len =
-            self_param as usize + type_params + const_params + impl_trait_params + lifetime_params;
+            self_params + type_params + const_params + impl_trait_params + lifetime_params;
         let total_len = parent_params + item_len;
 
         let ty_error = TyKind::Error.intern(Interner).cast(Interner);
@@ -837,16 +830,18 @@ impl<'a> TyLoweringContext<'a> {
         let mut def_generic_iter = def_generics.iter_id();
 
         let fill_self_params = || {
-            if self_param {
-                let self_ty =
-                    explicit_self_ty.map(|x| x.cast(Interner)).unwrap_or_else(|| ty_error.clone());
-
+            for x in explicit_self_ty
+                .into_iter()
+                .map(|x| x.cast(Interner))
+                .chain(iter::repeat(ty_error.clone()))
+                .take(self_params)
+            {
                 if let Some(id) = def_generic_iter.next() {
                     assert!(matches!(
                         id,
                         GenericParamId::TypeParamId(_) | GenericParamId::LifetimeParamId(_)
                     ));
-                    substs.push(self_ty);
+                    substs.push(x);
                 }
             }
         };
@@ -857,11 +852,11 @@ impl<'a> TyLoweringContext<'a> {
                 fill_self_params();
             }
             let expected_num = if generic_args.has_self_type {
-                self_param as usize + type_params + const_params
+                self_params + type_params + const_params
             } else {
                 type_params + const_params
             };
-            let skip = if generic_args.has_self_type && !self_param { 1 } else { 0 };
+            let skip = if generic_args.has_self_type && self_params == 0 { 1 } else { 0 };
             // if args are provided, it should be all of them, but we can't rely on that
             for arg in generic_args
                 .args
@@ -871,7 +866,7 @@ impl<'a> TyLoweringContext<'a> {
                 .take(expected_num)
             {
                 if let Some(id) = def_generic_iter.next() {
-                    let arg = generic_arg_to_chalk(
+                    if let Some(x) = generic_arg_to_chalk(
                         self.db,
                         id,
                         arg,
@@ -879,9 +874,13 @@ impl<'a> TyLoweringContext<'a> {
                         |_, type_ref| self.lower_ty(type_ref),
                         |_, const_ref, ty| self.lower_const(const_ref, ty),
                         |_, lifetime_ref| self.lower_lifetime(lifetime_ref),
-                    );
-                    had_explicit_args = true;
-                    substs.push(arg);
+                    ) {
+                        had_explicit_args = true;
+                        substs.push(x);
+                    } else {
+                        // we just filtered them out
+                        never!("Unexpected lifetime argument");
+                    }
                 }
             }
 
@@ -894,7 +893,7 @@ impl<'a> TyLoweringContext<'a> {
                 // Taking into the fact that def_generic_iter will always have lifetimes at the end
                 // Should have some test cases tho to test this behaviour more properly
                 if let Some(id) = def_generic_iter.next() {
-                    let arg = generic_arg_to_chalk(
+                    if let Some(x) = generic_arg_to_chalk(
                         self.db,
                         id,
                         arg,
@@ -902,9 +901,13 @@ impl<'a> TyLoweringContext<'a> {
                         |_, type_ref| self.lower_ty(type_ref),
                         |_, const_ref, ty| self.lower_const(const_ref, ty),
                         |_, lifetime_ref| self.lower_lifetime(lifetime_ref),
-                    );
-                    had_explicit_args = true;
-                    substs.push(arg);
+                    ) {
+                        had_explicit_args = true;
+                        substs.push(x);
+                    } else {
+                        // Never return a None explicitly
+                        never!("Unexpected None by generic_arg_to_chalk");
+                    }
                 }
             }
         } else {
@@ -1173,7 +1176,7 @@ impl<'a> TyLoweringContext<'a> {
                             let ty = if let Some(target_param_idx) = target_param_idx {
                                 let mut counter = 0;
                                 let generics = self.generics().expect("generics in scope");
-                                for (idx, data) in generics.iter_self_type_or_consts() {
+                                for (idx, data) in generics.params.type_or_consts.iter() {
                                     // Count the number of `impl Trait` things that appear before
                                     // the target of our `bound`.
                                     // Our counter within `impl_trait_mode` should be that number
@@ -1475,7 +1478,7 @@ fn named_associated_type_shorthand_candidates<R>(
             // Handle `Self::Type` referring to own associated type in trait definitions
             if let GenericDefId::TraitId(trait_id) = param_id.parent() {
                 let trait_generics = generics(db.upcast(), trait_id.into());
-                if trait_generics[param_id.local_id()].is_trait_self() {
+                if trait_generics.params[param_id.local_id()].is_trait_self() {
                     let def_generics = generics(db.upcast(), def);
                     let starting_idx = match def {
                         GenericDefId::TraitId(_) => 0,
@@ -1532,7 +1535,7 @@ pub(crate) fn generic_predicates_for_param_query(
     def: GenericDefId,
     param_id: TypeOrConstParamId,
     assoc_name: Option<Name>,
-) -> GenericPredicates {
+) -> Arc<[Binders<QuantifiedWhereClause>]> {
     let resolver = def.resolver(db.upcast());
     let ctx = if let GenericDefId::FunctionId(_) = def {
         TyLoweringContext::new(db, &resolver, def.into())
@@ -1593,22 +1596,16 @@ pub(crate) fn generic_predicates_for_param_query(
         .collect();
 
     let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
-    if !subst.is_empty(Interner) {
-        let explicitly_unsized_tys = ctx.unsized_types.into_inner();
-        if let Some(implicitly_sized_predicates) = implicitly_sized_clauses(
-            db,
-            param_id.parent,
-            &explicitly_unsized_tys,
-            &subst,
-            &resolver,
-        ) {
-            predicates.extend(
-                implicitly_sized_predicates
-                    .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))),
-            );
-        };
+    let explicitly_unsized_tys = ctx.unsized_types.into_inner();
+    if let Some(implicitly_sized_predicates) =
+        implicitly_sized_clauses(db, param_id.parent, &explicitly_unsized_tys, &subst, &resolver)
+    {
+        predicates.extend(
+            implicitly_sized_predicates
+                .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))),
+        );
     }
-    GenericPredicates(predicates.is_empty().not().then(|| predicates.into()))
+    predicates.into()
 }
 
 pub(crate) fn generic_predicates_for_param_recover(
@@ -1617,15 +1614,15 @@ pub(crate) fn generic_predicates_for_param_recover(
     _def: &GenericDefId,
     _param_id: &TypeOrConstParamId,
     _assoc_name: &Option<Name>,
-) -> GenericPredicates {
-    GenericPredicates(None)
+) -> Arc<[Binders<QuantifiedWhereClause>]> {
+    Arc::from_iter(None)
 }
 
 pub(crate) fn trait_environment_for_body_query(
     db: &dyn HirDatabase,
     def: DefWithBodyId,
 ) -> Arc<TraitEnvironment> {
-    let Some(def) = def.as_generic_def_id(db.upcast()) else {
+    let Some(def) = def.as_generic_def_id() else {
         let krate = def.module(db.upcast()).krate();
         return TraitEnvironment::empty(krate);
     };
@@ -1669,17 +1666,14 @@ pub(crate) fn trait_environment_query(
     }
 
     let subst = generics(db.upcast(), def).placeholder_subst(db);
-    if !subst.is_empty(Interner) {
-        let explicitly_unsized_tys = ctx.unsized_types.into_inner();
-        if let Some(implicitly_sized_clauses) =
-            implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver)
-        {
-            clauses.extend(
-                implicitly_sized_clauses.map(|pred| {
-                    pred.cast::<ProgramClause>(Interner).into_from_env_clause(Interner)
-                }),
-            );
-        };
+    let explicitly_unsized_tys = ctx.unsized_types.into_inner();
+    if let Some(implicitly_sized_clauses) =
+        implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver)
+    {
+        clauses.extend(
+            implicitly_sized_clauses
+                .map(|pred| pred.cast::<ProgramClause>(Interner).into_from_env_clause(Interner)),
+        );
     }
 
     let env = chalk_ir::Environment::new(Interner).add_clauses(Interner, clauses);
@@ -1687,32 +1681,20 @@ pub(crate) fn trait_environment_query(
     TraitEnvironment::new(resolver.krate(), None, traits_in_scope.into_boxed_slice(), env)
 }
 
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct GenericPredicates(Option<Arc<[Binders<QuantifiedWhereClause>]>>);
-
-impl ops::Deref for GenericPredicates {
-    type Target = [Binders<crate::QuantifiedWhereClause>];
-
-    fn deref(&self) -> &Self::Target {
-        self.0.as_deref().unwrap_or(&[])
-    }
-}
-
 /// Resolve the where clause(s) of an item with generics.
 pub(crate) fn generic_predicates_query(
     db: &dyn HirDatabase,
     def: GenericDefId,
-) -> GenericPredicates {
+) -> Arc<[Binders<QuantifiedWhereClause>]> {
     let resolver = def.resolver(db.upcast());
-    let (impl_trait_lowering, param_lowering) = match def {
-        GenericDefId::FunctionId(_) => {
-            (ImplTraitLoweringMode::Variable, ParamLoweringMode::Variable)
-        }
-        _ => (ImplTraitLoweringMode::Disallowed, ParamLoweringMode::Variable),
+    let ctx = if let GenericDefId::FunctionId(_) = def {
+        TyLoweringContext::new(db, &resolver, def.into())
+            .with_impl_trait_mode(ImplTraitLoweringMode::Variable)
+            .with_type_param_mode(ParamLoweringMode::Variable)
+    } else {
+        TyLoweringContext::new(db, &resolver, def.into())
+            .with_type_param_mode(ParamLoweringMode::Variable)
     };
-    let ctx = TyLoweringContext::new(db, &resolver, def.into())
-        .with_impl_trait_mode(impl_trait_lowering)
-        .with_type_param_mode(param_lowering);
     let generics = generics(db.upcast(), def);
 
     let mut predicates = resolver
@@ -1723,29 +1705,27 @@ pub(crate) fn generic_predicates_query(
         .collect::<Vec<_>>();
 
     let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
-    if !subst.is_empty(Interner) {
-        let explicitly_unsized_tys = ctx.unsized_types.into_inner();
-        if let Some(implicitly_sized_predicates) =
-            implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver)
-        {
-            predicates.extend(
-                implicitly_sized_predicates
-                    .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))),
-            );
-        };
+    let explicitly_unsized_tys = ctx.unsized_types.into_inner();
+    if let Some(implicitly_sized_predicates) =
+        implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver)
+    {
+        predicates.extend(
+            implicitly_sized_predicates
+                .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))),
+        );
     }
-    GenericPredicates(predicates.is_empty().not().then(|| predicates.into()))
+    predicates.into()
 }
 
 /// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound.
 /// Exception is Self of a trait def.
-fn implicitly_sized_clauses<'a, 'subst: 'a>(
+fn implicitly_sized_clauses<'a>(
     db: &dyn HirDatabase,
     def: GenericDefId,
     explicitly_unsized_tys: &'a FxHashSet<Ty>,
-    substitution: &'subst Substitution,
+    substitution: &'a Substitution,
     resolver: &Resolver,
-) -> Option<impl Iterator<Item = WhereClause> + Captures<'a> + Captures<'subst>> {
+) -> Option<impl Iterator<Item = WhereClause> + 'a> {
     let is_trait_def = matches!(def, GenericDefId::TraitId(..));
     let generic_args = &substitution.as_slice(Interner)[is_trait_def as usize..];
     let sized_trait = db
@@ -1766,84 +1746,71 @@ fn implicitly_sized_clauses<'a, 'subst: 'a>(
     })
 }
 
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct GenericDefaults(Option<Arc<[Binders<crate::GenericArg>]>>);
-
-impl ops::Deref for GenericDefaults {
-    type Target = [Binders<crate::GenericArg>];
-
-    fn deref(&self) -> &Self::Target {
-        self.0.as_deref().unwrap_or(&[])
-    }
-}
-
 /// Resolve the default type params from generics
-pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) -> GenericDefaults {
-    let generic_params = generics(db.upcast(), def);
-    if generic_params.len() == 0 {
-        return GenericDefaults(None);
-    }
+pub(crate) fn generic_defaults_query(
+    db: &dyn HirDatabase,
+    def: GenericDefId,
+) -> Arc<[Binders<crate::GenericArg>]> {
     let resolver = def.resolver(db.upcast());
-    let parent_start_idx = generic_params.len_self();
-
     let ctx = TyLoweringContext::new(db, &resolver, def.into())
-        .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed)
         .with_type_param_mode(ParamLoweringMode::Variable);
-    GenericDefaults(Some(Arc::from_iter(generic_params.iter().enumerate().map(
-        |(idx, (id, p))| {
-            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 generic_params = generics(db.upcast(), def);
+    let parent_start_idx = generic_params.len_self();
 
-                    let mut val = p.default.as_ref().map_or_else(
-                        || unknown_const_as_generic(db.const_param_ty(id)),
-                        |c| {
-                            let c = ctx.lower_const(c, ctx.lower_ty(&p.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 defaults = Arc::from_iter(generic_params.iter().enumerate().map(|(idx, (id, p))| {
+        match p {
+            GenericParamDataRef::TypeParamData(p) => {
+                let mut ty =
+                    p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t));
+                // Each default can only refer to previous parameters.
+                // Type variable default referring to parameter coming
+                // after it is forbidden (FIXME: report diagnostic)
+                ty = fallback_bound_vars(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 val = p.default.as_ref().map_or_else(
+                    || unknown_const_as_generic(db.const_param_ty(id)),
+                    |c| {
+                        let c = ctx.lower_const(c, ctx.lower_ty(&p.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))
+            }
+        }
+    }));
+
+    defaults
 }
 
 pub(crate) fn generic_defaults_recover(
     db: &dyn HirDatabase,
     _cycle: &Cycle,
     def: &GenericDefId,
-) -> GenericDefaults {
+) -> Arc<[Binders<crate::GenericArg>]> {
     let generic_params = generics(db.upcast(), *def);
-    if generic_params.len() == 0 {
-        return GenericDefaults(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 = 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
 }
 
 fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
@@ -1852,7 +1819,7 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
     let ctx_params = TyLoweringContext::new(db, &resolver, def.into())
         .with_impl_trait_mode(ImplTraitLoweringMode::Variable)
         .with_type_param_mode(ParamLoweringMode::Variable);
-    let params = data.params.iter().map(|tr| ctx_params.lower_ty(tr));
+    let params = data.params.iter().map(|tr| ctx_params.lower_ty(tr)).collect::<Vec<_>>();
     let ctx_ret = TyLoweringContext::new(db, &resolver, def.into())
         .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
         .with_type_param_mode(ParamLoweringMode::Variable);
@@ -1906,7 +1873,7 @@ fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnS
     let resolver = def.resolver(db.upcast());
     let ctx = TyLoweringContext::new(db, &resolver, AdtId::from(def).into())
         .with_type_param_mode(ParamLoweringMode::Variable);
-    let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref));
+    let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>();
     let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders();
     Binders::new(
         binders,
@@ -1938,7 +1905,7 @@ fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId)
     let resolver = def.resolver(db.upcast());
     let ctx = TyLoweringContext::new(db, &resolver, DefWithBodyId::VariantId(def).into())
         .with_type_param_mode(ParamLoweringMode::Variable);
-    let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref));
+    let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>();
     let (ret, binders) =
         type_for_adt(db, def.lookup(db.upcast()).parent.into()).into_value_and_skipped_binders();
     Binders::new(
@@ -1992,6 +1959,47 @@ fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
     }
 }
 
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub enum CallableDefId {
+    FunctionId(FunctionId),
+    StructId(StructId),
+    EnumVariantId(EnumVariantId),
+}
+
+impl InternValueTrivial for CallableDefId {}
+
+impl_from!(FunctionId, StructId, EnumVariantId for CallableDefId);
+impl From<CallableDefId> for ModuleDefId {
+    fn from(def: CallableDefId) -> ModuleDefId {
+        match def {
+            CallableDefId::FunctionId(f) => ModuleDefId::FunctionId(f),
+            CallableDefId::StructId(s) => ModuleDefId::AdtId(AdtId::StructId(s)),
+            CallableDefId::EnumVariantId(e) => ModuleDefId::EnumVariantId(e),
+        }
+    }
+}
+
+impl CallableDefId {
+    pub fn krate(self, db: &dyn HirDatabase) -> CrateId {
+        let db = db.upcast();
+        match self {
+            CallableDefId::FunctionId(f) => f.krate(db),
+            CallableDefId::StructId(s) => s.krate(db),
+            CallableDefId::EnumVariantId(e) => e.krate(db),
+        }
+    }
+}
+
+impl From<CallableDefId> for GenericDefId {
+    fn from(def: CallableDefId) -> GenericDefId {
+        match def {
+            CallableDefId::FunctionId(f) => f.into(),
+            CallableDefId::StructId(s) => s.into(),
+            CallableDefId::EnumVariantId(e) => e.into(),
+        }
+    }
+}
+
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum TyDefId {
     BuiltinType(BuiltinType),
@@ -2012,12 +2020,12 @@ pub enum ValueTyDefId {
 impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for ValueTyDefId);
 
 impl ValueTyDefId {
-    pub(crate) fn to_generic_def_id(self, db: &dyn HirDatabase) -> Option<GenericDefId> {
+    pub(crate) fn to_generic_def_id(self) -> Option<GenericDefId> {
         match self {
             Self::FunctionId(id) => Some(id.into()),
             Self::StructId(id) => Some(id.into()),
             Self::UnionId(id) => Some(id.into()),
-            Self::EnumVariantId(var) => Some(var.lookup(db.upcast()).parent.into()),
+            Self::EnumVariantId(var) => Some(var.into()),
             Self::ConstId(id) => Some(id.into()),
             Self::StaticId(_) => None,
         }
@@ -2160,6 +2168,7 @@ pub(crate) fn lower_to_chalk_mutability(m: hir_def::type_ref::Mutability) -> Mut
 /// Checks if the provided generic arg matches its expected kind, then lower them via
 /// provided closures. Use unknown if there was kind mismatch.
 ///
+/// Returns `Some` of the lowered generic arg. `None` if the provided arg is a lifetime.
 pub(crate) fn generic_arg_to_chalk<'a, T>(
     db: &dyn HirDatabase,
     kind_id: GenericParamId,
@@ -2168,7 +2177,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
     for_type: impl FnOnce(&mut T, &TypeRef) -> Ty + 'a,
     for_const: impl FnOnce(&mut T, &ConstRef, Ty) -> Const + 'a,
     for_lifetime: impl FnOnce(&mut T, &LifetimeRef) -> Lifetime + 'a,
-) -> crate::GenericArg {
+) -> Option<crate::GenericArg> {
     let kind = match kind_id {
         GenericParamId::TypeParamId(_) => ParamKind::Type,
         GenericParamId::ConstParamId(id) => {
@@ -2177,7 +2186,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
         }
         GenericParamId::LifetimeParamId(_) => ParamKind::Lifetime,
     };
-    match (arg, kind) {
+    Some(match (arg, kind) {
         (GenericArg::Type(type_ref), ParamKind::Type) => for_type(this, type_ref).cast(Interner),
         (GenericArg::Const(c), ParamKind::Const(c_ty)) => for_const(this, c, c_ty).cast(Interner),
         (GenericArg::Lifetime(lifetime_ref), ParamKind::Lifetime) => {
@@ -2190,12 +2199,11 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
             // as types. Maybe here is not the best place to do it, but
             // it works.
             if let TypeRef::Path(p) = t {
-                if let Some(p) = p.mod_path() {
-                    if p.kind == PathKind::Plain {
-                        if let [n] = p.segments() {
-                            let c = ConstRef::Path(n.clone());
-                            return for_const(this, &c, c_ty).cast(Interner);
-                        }
+                let p = p.mod_path()?;
+                if p.kind == PathKind::Plain {
+                    if let [n] = p.segments() {
+                        let c = ConstRef::Path(n.clone());
+                        return Some(for_const(this, &c, c_ty).cast(Interner));
                     }
                 }
             }
@@ -2204,17 +2212,17 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
         (GenericArg::Lifetime(_), ParamKind::Const(c_ty)) => unknown_const_as_generic(c_ty),
         (GenericArg::Type(_), ParamKind::Lifetime) => error_lifetime().cast(Interner),
         (GenericArg::Const(_), ParamKind::Lifetime) => error_lifetime().cast(Interner),
-    }
+    })
 }
 
-pub(crate) fn const_or_path_to_chalk<'g>(
+pub(crate) fn const_or_path_to_chalk(
     db: &dyn HirDatabase,
     resolver: &Resolver,
     owner: TypeOwnerId,
     expected_ty: Ty,
     value: &ConstRef,
     mode: ParamLoweringMode,
-    args: impl FnOnce() -> Option<&'g Generics>,
+    args: impl FnOnce() -> Option<Generics>,
     debruijn: DebruijnIndex,
 ) -> Const {
     match value {
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index ac11da789a..5ce124d6d2 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -1322,7 +1322,7 @@ fn iterate_inherent_methods(
         callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
     ) -> ControlFlow<()> {
         for &impl_id in impls.for_self_ty(self_ty) {
-            for &item in table.db.impl_data(impl_id).items.iter() {
+            for &item in &table.db.impl_data(impl_id).items {
                 let visible = match is_valid_impl_method_candidate(
                     table,
                     self_ty,
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index 0569d06695..6d662959f1 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -28,7 +28,6 @@ use crate::{
     db::{HirDatabase, InternedClosure},
     display::HirDisplay,
     error_lifetime,
-    generics::generics,
     infer::{CaptureKind, CapturedItem, TypeMismatch},
     inhabitedness::is_ty_uninhabited_from,
     layout::LayoutError,
@@ -43,7 +42,7 @@ use crate::{
     },
     static_lifetime,
     traits::FnTrait,
-    utils::ClosureSubst,
+    utils::{generics, ClosureSubst},
     Adjust, Adjustment, AutoBorrow, CallableDefId, TyBuilder, TyExt,
 };
 
@@ -483,7 +482,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
                         Ok(Some(current))
                     }
                     ValueNs::GenericParam(p) => {
-                        let Some(def) = self.owner.as_generic_def_id(self.db.upcast()) else {
+                        let Some(def) = self.owner.as_generic_def_id() else {
                             not_supported!("owner without generic def id");
                         };
                         let gen = generics(self.db.upcast(), def);
@@ -1330,7 +1329,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
     }
 
     fn placeholder_subst(&mut self) -> Substitution {
-        match self.owner.as_generic_def_id(self.db.upcast()) {
+        match self.owner.as_generic_def_id() {
             Some(it) => TyBuilder::placeholder_subst(self.db, it),
             None => Substitution::empty(Interner),
         }
diff --git a/crates/hir-ty/src/mir/monomorphization.rs b/crates/hir-ty/src/mir/monomorphization.rs
index 172dea02e6..a384c9306e 100644
--- a/crates/hir-ty/src/mir/monomorphization.rs
+++ b/crates/hir-ty/src/mir/monomorphization.rs
@@ -21,8 +21,8 @@ use crate::{
     consteval::{intern_const_scalar, unknown_const},
     db::{HirDatabase, InternedClosure},
     from_placeholder_idx,
-    generics::{generics, Generics},
     infer::normalize,
+    utils::{generics, Generics},
     ClosureId, Const, Interner, ProjectionTy, Substitution, TraitEnvironment, Ty, TyKind,
 };
 
@@ -302,7 +302,7 @@ pub fn monomorphized_mir_body_query(
     subst: Substitution,
     trait_env: Arc<crate::TraitEnvironment>,
 ) -> Result<Arc<MirBody>, MirLowerError> {
-    let generics = owner.as_generic_def_id(db.upcast()).map(|g_def| generics(db.upcast(), g_def));
+    let generics = owner.as_generic_def_id().map(|g_def| generics(db.upcast(), g_def));
     let filler = &mut Filler { db, subst: &subst, trait_env, generics, owner };
     let body = db.mir_body(owner)?;
     let mut body = (*body).clone();
@@ -327,7 +327,7 @@ pub fn monomorphized_mir_body_for_closure_query(
     trait_env: Arc<crate::TraitEnvironment>,
 ) -> Result<Arc<MirBody>, MirLowerError> {
     let InternedClosure(owner, _) = db.lookup_intern_closure(closure.into());
-    let generics = owner.as_generic_def_id(db.upcast()).map(|g_def| generics(db.upcast(), g_def));
+    let generics = owner.as_generic_def_id().map(|g_def| generics(db.upcast(), g_def));
     let filler = &mut Filler { db, subst: &subst, trait_env, generics, owner };
     let body = db.mir_body_for_closure(closure)?;
     let mut body = (*body).clone();
@@ -343,7 +343,7 @@ pub fn monomorphize_mir_body_bad(
     trait_env: Arc<crate::TraitEnvironment>,
 ) -> Result<MirBody, MirLowerError> {
     let owner = body.owner;
-    let generics = owner.as_generic_def_id(db.upcast()).map(|g_def| generics(db.upcast(), g_def));
+    let generics = owner.as_generic_def_id().map(|g_def| generics(db.upcast(), g_def));
     let filler = &mut Filler { db, subst: &subst, trait_env, generics, owner };
     filler.fill_body(&mut body)?;
     Ok(body)
diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs
index 969999cdb8..cff8e6b036 100644
--- a/crates/hir-ty/src/utils.rs
+++ b/crates/hir-ty/src/utils.rs
@@ -5,19 +5,25 @@ use std::{hash::Hash, iter};
 
 use base_db::CrateId;
 use chalk_ir::{
+    cast::Cast,
     fold::{FallibleTypeFolder, Shift},
-    DebruijnIndex,
+    BoundVar, DebruijnIndex,
 };
 use hir_def::{
     db::DefDatabase,
-    generics::{WherePredicate, WherePredicateTypeTarget},
+    generics::{
+        GenericParamDataRef, GenericParams, LifetimeParamData, TypeOrConstParamData,
+        TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
+    },
     lang_item::LangItem,
     resolver::{HasResolver, TypeNs},
     type_ref::{TraitBoundModifier, TypeRef},
-    EnumId, EnumVariantId, FunctionId, Lookup, OpaqueInternableThing, TraitId, TypeAliasId,
-    TypeOrConstParamId,
+    ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, GenericParamId, ItemContainerId,
+    LifetimeParamId, Lookup, OpaqueInternableThing, TraitId, TypeAliasId, TypeOrConstParamId,
+    TypeParamId,
 };
 use hir_expand::name::Name;
+use intern::Interned;
 use rustc_abi::TargetDataLayout;
 use rustc_hash::FxHashSet;
 use smallvec::{smallvec, SmallVec};
@@ -155,7 +161,7 @@ impl Iterator for ClauseElaborator<'_> {
 fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) {
     let resolver = trait_.resolver(db);
     let generic_params = db.generic_params(trait_.into());
-    let trait_self = generic_params.trait_self_param();
+    let trait_self = generic_params.find_trait_self_param();
     generic_params
         .where_predicates
         .iter()
@@ -188,7 +194,7 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(Tra
 
 fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef, cb: impl FnMut(TraitRef)) {
     let generic_params = db.generic_params(trait_ref.hir_trait_id().into());
-    let trait_self = match generic_params.trait_self_param() {
+    let trait_self = match generic_params.find_trait_self_param() {
         Some(p) => TypeOrConstParamId { parent: trait_ref.hir_trait_id().into(), local_id: p },
         None => return,
     };
@@ -220,6 +226,11 @@ pub(super) fn associated_type_by_name_including_super_traits(
     })
 }
 
+pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
+    let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def)));
+    Generics { def, params: db.generic_params(def), parent_generics }
+}
+
 /// It is a bit different from the rustc equivalent. Currently it stores:
 /// - 0: the function signature, encoded as a function pointer type
 /// - 1..n: generics of the parent
@@ -251,6 +262,275 @@ impl<'a> ClosureSubst<'a> {
     }
 }
 
+#[derive(Clone, Debug)]
+pub(crate) struct Generics {
+    def: GenericDefId,
+    pub(crate) params: Interned<GenericParams>,
+    parent_generics: Option<Box<Generics>>,
+}
+
+impl Generics {
+    pub(crate) fn iter_id(&self) -> impl Iterator<Item = GenericParamId> + '_ {
+        self.iter().map(|(id, _)| id)
+    }
+
+    pub(crate) fn def(&self) -> GenericDefId {
+        self.def
+    }
+
+    /// Iterator over types and const params of self, then parent.
+    pub(crate) fn iter<'a>(
+        &'a self,
+    ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'a>)> + 'a {
+        let from_toc_id = |it: &'a Generics| {
+            move |(local_id, p): (_, &'a TypeOrConstParamData)| {
+                let id = TypeOrConstParamId { parent: it.def, local_id };
+                match p {
+                    TypeOrConstParamData::TypeParamData(p) => (
+                        GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)),
+                        GenericParamDataRef::TypeParamData(p),
+                    ),
+                    TypeOrConstParamData::ConstParamData(p) => (
+                        GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)),
+                        GenericParamDataRef::ConstParamData(p),
+                    ),
+                }
+            }
+        };
+
+        let from_lt_id = |it: &'a Generics| {
+            move |(local_id, p): (_, &'a LifetimeParamData)| {
+                (
+                    GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }),
+                    GenericParamDataRef::LifetimeParamData(p),
+                )
+            }
+        };
+
+        let lt_iter = self.params.iter_lt().map(from_lt_id(self));
+        self.params
+            .iter_type_or_consts()
+            .map(from_toc_id(self))
+            .chain(lt_iter)
+            .chain(self.iter_parent())
+    }
+
+    /// Iterate over types and const params without parent params.
+    pub(crate) fn iter_self<'a>(
+        &'a self,
+    ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'a>)> + 'a {
+        let from_toc_id = |it: &'a Generics| {
+            move |(local_id, p): (_, &'a TypeOrConstParamData)| {
+                let id = TypeOrConstParamId { parent: it.def, local_id };
+                match p {
+                    TypeOrConstParamData::TypeParamData(p) => (
+                        GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)),
+                        GenericParamDataRef::TypeParamData(p),
+                    ),
+                    TypeOrConstParamData::ConstParamData(p) => (
+                        GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)),
+                        GenericParamDataRef::ConstParamData(p),
+                    ),
+                }
+            }
+        };
+
+        let from_lt_id = |it: &'a Generics| {
+            move |(local_id, p): (_, &'a LifetimeParamData)| {
+                (
+                    GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }),
+                    GenericParamDataRef::LifetimeParamData(p),
+                )
+            }
+        };
+
+        self.params
+            .iter_type_or_consts()
+            .map(from_toc_id(self))
+            .chain(self.params.iter_lt().map(from_lt_id(self)))
+    }
+
+    /// Iterator over types and const params of parent.
+    pub(crate) fn iter_parent(
+        &self,
+    ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'_>)> + '_ {
+        self.parent_generics().into_iter().flat_map(|it| {
+            let from_toc_id = move |(local_id, p)| {
+                let p: &_ = p;
+                let id = TypeOrConstParamId { parent: it.def, local_id };
+                match p {
+                    TypeOrConstParamData::TypeParamData(p) => (
+                        GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)),
+                        GenericParamDataRef::TypeParamData(p),
+                    ),
+                    TypeOrConstParamData::ConstParamData(p) => (
+                        GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)),
+                        GenericParamDataRef::ConstParamData(p),
+                    ),
+                }
+            };
+
+            let from_lt_id = move |(local_id, p): (_, _)| {
+                (
+                    GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }),
+                    GenericParamDataRef::LifetimeParamData(p),
+                )
+            };
+            let lt_iter = it.params.iter_lt().map(from_lt_id);
+            it.params.iter_type_or_consts().map(from_toc_id).chain(lt_iter)
+        })
+    }
+
+    /// Returns total number of generic parameters in scope, including those from parent.
+    pub(crate) fn len(&self) -> usize {
+        let parent = self.parent_generics().map_or(0, Generics::len);
+        let child = self.params.len();
+        parent + child
+    }
+
+    /// Returns numbers of generic parameters and lifetimes excluding those from parent.
+    pub(crate) fn len_self(&self) -> usize {
+        self.params.len()
+    }
+
+    /// Returns number of generic parameter excluding those from parent
+    fn len_type_and_const_params(&self) -> usize {
+        self.params.type_or_consts.len()
+    }
+
+    /// (parent total, self param, type params, const params, impl trait list, lifetimes)
+    pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize, usize, usize) {
+        let mut self_params = 0;
+        let mut type_params = 0;
+        let mut impl_trait_params = 0;
+        let mut const_params = 0;
+        let mut lifetime_params = 0;
+        self.params.iter_type_or_consts().for_each(|(_, data)| match data {
+            TypeOrConstParamData::TypeParamData(p) => match p.provenance {
+                TypeParamProvenance::TypeParamList => type_params += 1,
+                TypeParamProvenance::TraitSelf => self_params += 1,
+                TypeParamProvenance::ArgumentImplTrait => impl_trait_params += 1,
+            },
+            TypeOrConstParamData::ConstParamData(_) => const_params += 1,
+        });
+
+        self.params.iter_lt().for_each(|(_, _)| lifetime_params += 1);
+
+        let parent_len = self.parent_generics().map_or(0, Generics::len);
+        (parent_len, self_params, type_params, const_params, impl_trait_params, lifetime_params)
+    }
+
+    pub(crate) fn type_or_const_param_idx(&self, param: TypeOrConstParamId) -> Option<usize> {
+        Some(self.find_type_or_const_param(param)?.0)
+    }
+
+    fn find_type_or_const_param(
+        &self,
+        param: TypeOrConstParamId,
+    ) -> Option<(usize, &TypeOrConstParamData)> {
+        if param.parent == self.def {
+            let idx = param.local_id.into_raw().into_u32() as usize;
+            if idx >= self.params.type_or_consts.len() {
+                return None;
+            }
+            Some((idx, &self.params.type_or_consts[param.local_id]))
+        } else {
+            self.parent_generics()
+                .and_then(|g| g.find_type_or_const_param(param))
+                // Remember that parent parameters come after parameters for self.
+                .map(|(idx, data)| (self.len_self() + idx, data))
+        }
+    }
+
+    pub(crate) fn lifetime_idx(&self, lifetime: LifetimeParamId) -> Option<usize> {
+        Some(self.find_lifetime(lifetime)?.0)
+    }
+
+    fn find_lifetime(&self, lifetime: LifetimeParamId) -> Option<(usize, &LifetimeParamData)> {
+        if lifetime.parent == self.def {
+            let idx = lifetime.local_id.into_raw().into_u32() as usize;
+            if idx >= self.params.lifetimes.len() {
+                return None;
+            }
+            Some((
+                self.len_type_and_const_params() + idx,
+                &self.params.lifetimes[lifetime.local_id],
+            ))
+        } else {
+            self.parent_generics()
+                .and_then(|g| g.find_lifetime(lifetime))
+                .map(|(idx, data)| (self.len_self() + idx, data))
+        }
+    }
+
+    pub(crate) fn parent_generics(&self) -> Option<&Generics> {
+        self.parent_generics.as_deref()
+    }
+
+    pub(crate) fn parent_or_self(&self) -> &Generics {
+        self.parent_generics.as_deref().unwrap_or(self)
+    }
+
+    /// Returns a Substitution that replaces each parameter by a bound variable.
+    pub(crate) fn bound_vars_subst(
+        &self,
+        db: &dyn HirDatabase,
+        debruijn: DebruijnIndex,
+    ) -> Substitution {
+        Substitution::from_iter(
+            Interner,
+            self.iter_id().enumerate().map(|(idx, id)| match id {
+                GenericParamId::ConstParamId(id) => BoundVar::new(debruijn, idx)
+                    .to_const(Interner, db.const_param_ty(id))
+                    .cast(Interner),
+                GenericParamId::TypeParamId(_) => {
+                    BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner)
+                }
+                GenericParamId::LifetimeParamId(_) => {
+                    BoundVar::new(debruijn, idx).to_lifetime(Interner).cast(Interner)
+                }
+            }),
+        )
+    }
+
+    /// Returns a Substitution that replaces each parameter by itself (i.e. `Ty::Param`).
+    pub(crate) fn placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution {
+        Substitution::from_iter(
+            Interner,
+            self.iter_id().map(|id| match id {
+                GenericParamId::TypeParamId(id) => {
+                    crate::to_placeholder_idx(db, id.into()).to_ty(Interner).cast(Interner)
+                }
+                GenericParamId::ConstParamId(id) => crate::to_placeholder_idx(db, id.into())
+                    .to_const(Interner, db.const_param_ty(id))
+                    .cast(Interner),
+                GenericParamId::LifetimeParamId(id) => {
+                    crate::lt_to_placeholder_idx(db, id).to_lifetime(Interner).cast(Interner)
+                }
+            }),
+        )
+    }
+}
+
+fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option<GenericDefId> {
+    let container = match def {
+        GenericDefId::FunctionId(it) => it.lookup(db).container,
+        GenericDefId::TypeAliasId(it) => it.lookup(db).container,
+        GenericDefId::ConstId(it) => it.lookup(db).container,
+        GenericDefId::EnumVariantId(it) => return Some(it.lookup(db).parent.into()),
+        GenericDefId::AdtId(_)
+        | GenericDefId::TraitId(_)
+        | GenericDefId::ImplId(_)
+        | GenericDefId::TraitAliasId(_) => return None,
+    };
+
+    match container {
+        ItemContainerId::ImplId(it) => Some(it.into()),
+        ItemContainerId::TraitId(it) => Some(it.into()),
+        ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
+    }
+}
+
 pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool {
     let data = db.function_data(func);
     if data.has_unsafe_kw() {
diff --git a/crates/hir/src/from_id.rs b/crates/hir/src/from_id.rs
index 2ad39817b2..887227bf4d 100644
--- a/crates/hir/src/from_id.rs
+++ b/crates/hir/src/from_id.rs
@@ -182,6 +182,7 @@ impl From<GenericDef> for GenericDefId {
             GenericDef::TraitAlias(it) => GenericDefId::TraitAliasId(it.id),
             GenericDef::TypeAlias(it) => GenericDefId::TypeAliasId(it.id),
             GenericDef::Impl(it) => GenericDefId::ImplId(it.id),
+            GenericDef::Variant(it) => GenericDefId::EnumVariantId(it.into()),
             GenericDef::Const(it) => GenericDefId::ConstId(it.id),
         }
     }
@@ -196,6 +197,7 @@ impl From<GenericDefId> for GenericDef {
             GenericDefId::TraitAliasId(it) => GenericDef::TraitAlias(it.into()),
             GenericDefId::TypeAliasId(it) => GenericDef::TypeAlias(it.into()),
             GenericDefId::ImplId(it) => GenericDef::Impl(it.into()),
+            GenericDefId::EnumVariantId(it) => GenericDef::Variant(it.into()),
             GenericDefId::ConstId(it) => GenericDef::Const(it.into()),
         }
     }
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs
index 18e27130f3..929c8b3c09 100644
--- a/crates/hir/src/has_source.rs
+++ b/crates/hir/src/has_source.rs
@@ -5,10 +5,10 @@ use either::Either;
 use hir_def::{
     nameres::{ModuleOrigin, ModuleSource},
     src::{HasChildSource, HasSource as _},
-    CallableDefId, Lookup, MacroId, VariantId,
+    Lookup, MacroId, VariantId,
 };
 use hir_expand::{HirFileId, InFile};
-use hir_ty::db::InternedClosure;
+use hir_ty::{db::InternedClosure, CallableDefId};
 use syntax::ast;
 use tt::TextRange;
 
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index eea25ac18a..05fa7c4964 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -52,11 +52,11 @@ use hir_def::{
     path::ImportAlias,
     per_ns::PerNs,
     resolver::{HasResolver, Resolver},
-    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,
+    AssocItemId, AssocItemLoc, AttrDefId, 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,
 };
 use hir_expand::{
     attrs::collect_attrs, name::name, proc_macro::ProcMacroKind, AstId, MacroCallKind, ValueResult,
@@ -71,7 +71,7 @@ use hir_ty::{
     mir::{interpret_mir, MutBorrowKind},
     primitive::UintTy,
     traits::FnTrait,
-    AliasTy, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArg,
+    AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArg,
     GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution,
     TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, ValueTyDefId,
     WhereClause,
@@ -760,7 +760,7 @@ impl Module {
                 impl_assoc_items_scratch.clear();
             }
 
-            for &item in db.impl_data(impl_def.id).items.iter() {
+            for &item in &db.impl_data(impl_def.id).items {
                 AssocItem::from(item).diagnostics(db, acc, style_lints);
             }
         }
@@ -1144,7 +1144,7 @@ impl Field {
         let generic_def_id: GenericDefId = match self.parent {
             VariantDef::Struct(it) => it.id.into(),
             VariantDef::Union(it) => it.id.into(),
-            VariantDef::Variant(it) => it.id.lookup(db.upcast()).parent.into(),
+            VariantDef::Variant(it) => it.id.into(),
         };
         let substs = TyBuilder::placeholder_subst(db, generic_def_id);
         let ty = db.field_types(var_id)[self.id].clone().substitute(Interner, &substs);
@@ -1177,9 +1177,7 @@ impl Field {
         db.layout_of_ty(
             self.ty(db).ty,
             db.trait_environment(match hir_def::VariantId::from(self.parent) {
-                hir_def::VariantId::EnumVariantId(id) => {
-                    GenericDefId::AdtId(id.lookup(db.upcast()).parent.into())
-                }
+                hir_def::VariantId::EnumVariantId(id) => GenericDefId::EnumVariantId(id),
                 hir_def::VariantId::StructId(id) => GenericDefId::AdtId(id.into()),
                 hir_def::VariantId::UnionId(id) => GenericDefId::AdtId(id.into()),
             }),
@@ -2503,7 +2501,7 @@ impl Trait {
         db: &dyn HirDatabase,
         count_required_only: bool,
     ) -> usize {
-        db.generic_params(self.id.into())
+        db.generic_params(GenericDefId::from(self.id))
             .type_or_consts
             .iter()
             .filter(|(_, ty)| !matches!(ty, TypeOrConstParamData::TypeParamData(ty) if ty.provenance != TypeParamProvenance::TypeParamList))
@@ -2786,7 +2784,6 @@ impl From<ModuleDef> for ItemInNs {
             ModuleDef::Static(_) | ModuleDef::Const(_) | ModuleDef::Function(_) => {
                 ItemInNs::Values(module_def)
             }
-            ModuleDef::Macro(it) => ItemInNs::Macros(it),
             _ => ItemInNs::Types(module_def),
         }
     }
@@ -3109,6 +3106,9 @@ pub enum GenericDef {
     TraitAlias(TraitAlias),
     TypeAlias(TypeAlias),
     Impl(Impl),
+    // enum variants cannot have generics themselves, but their parent enums
+    // can, and this makes some code easier to write
+    Variant(Variant),
     // consts can have type parameters from their parents (i.e. associated consts of traits)
     Const(Const),
 }
@@ -3119,6 +3119,7 @@ impl_from!(
     TraitAlias,
     TypeAlias,
     Impl,
+    Variant,
     Const
     for GenericDef
 );
@@ -4050,9 +4051,7 @@ impl Type {
                 ValueTyDefId::FunctionId(it) => GenericDefId::FunctionId(it),
                 ValueTyDefId::StructId(it) => GenericDefId::AdtId(AdtId::StructId(it)),
                 ValueTyDefId::UnionId(it) => GenericDefId::AdtId(AdtId::UnionId(it)),
-                ValueTyDefId::EnumVariantId(it) => {
-                    GenericDefId::AdtId(AdtId::EnumId(it.lookup(db.upcast()).parent))
-                }
+                ValueTyDefId::EnumVariantId(it) => GenericDefId::EnumVariantId(it),
                 ValueTyDefId::StaticId(_) => return Type::new(db, def, ty.skip_binders().clone()),
             },
         );
diff --git a/crates/hir/src/symbols.rs b/crates/hir/src/symbols.rs
index 02905ca2ce..3b88836c24 100644
--- a/crates/hir/src/symbols.rs
+++ b/crates/hir/src/symbols.rs
@@ -231,7 +231,7 @@ impl<'a> SymbolCollector<'a> {
         let impl_data = self.db.impl_data(impl_id);
         let impl_name = Some(SmolStr::new(impl_data.self_ty.display(self.db).to_string()));
         self.with_container_name(impl_name, |s| {
-            for &assoc_item_id in impl_data.items.iter() {
+            for &assoc_item_id in &impl_data.items {
                 s.push_assoc_item(assoc_item_id)
             }
         })
diff --git a/crates/hir/src/term_search.rs b/crates/hir/src/term_search.rs
index 6f84513708..aa046b02e2 100644
--- a/crates/hir/src/term_search.rs
+++ b/crates/hir/src/term_search.rs
@@ -93,6 +93,12 @@ struct LookupTable {
     data: FxHashMap<Type, AlternativeExprs>,
     /// New types reached since last query by the `NewTypesKey`
     new_types: FxHashMap<NewTypesKey, Vec<Type>>,
+    /// ScopeDefs that are not interesting any more
+    exhausted_scopedefs: FxHashSet<ScopeDef>,
+    /// ScopeDefs that were used in current round
+    round_scopedef_hits: FxHashSet<ScopeDef>,
+    /// Amount of rounds since scopedef was first used.
+    rounds_since_sopedef_hit: FxHashMap<ScopeDef, u32>,
     /// Types queried but not present
     types_wishlist: FxHashSet<Type>,
     /// Threshold to squash trees to `Many`
@@ -206,6 +212,37 @@ impl LookupTable {
         }
     }
 
+    /// Mark `ScopeDef` as exhausted meaning it is not interesting for us any more
+    fn mark_exhausted(&mut self, def: ScopeDef) {
+        self.exhausted_scopedefs.insert(def);
+    }
+
+    /// Mark `ScopeDef` as used meaning we managed to produce something useful from it
+    fn mark_fulfilled(&mut self, def: ScopeDef) {
+        self.round_scopedef_hits.insert(def);
+    }
+
+    /// Start new round (meant to be called at the beginning of iteration in `term_search`)
+    ///
+    /// This functions marks some `ScopeDef`s as exhausted if there have been
+    /// `MAX_ROUNDS_AFTER_HIT` rounds after first using a `ScopeDef`.
+    fn new_round(&mut self) {
+        for def in &self.round_scopedef_hits {
+            let hits =
+                self.rounds_since_sopedef_hit.entry(*def).and_modify(|n| *n += 1).or_insert(0);
+            const MAX_ROUNDS_AFTER_HIT: u32 = 2;
+            if *hits > MAX_ROUNDS_AFTER_HIT {
+                self.exhausted_scopedefs.insert(*def);
+            }
+        }
+        self.round_scopedef_hits.clear();
+    }
+
+    /// Get exhausted `ScopeDef`s
+    fn exhausted_scopedefs(&self) -> &FxHashSet<ScopeDef> {
+        &self.exhausted_scopedefs
+    }
+
     /// Types queried but not found
     fn types_wishlist(&mut self) -> &FxHashSet<Type> {
         &self.types_wishlist
@@ -238,7 +275,7 @@ pub struct TermSearchConfig {
 
 impl Default for TermSearchConfig {
     fn default() -> Self {
-        Self { enable_borrowcheck: true, many_alternatives_threshold: 1, fuel: 1200 }
+        Self { enable_borrowcheck: true, many_alternatives_threshold: 1, fuel: 400 }
     }
 }
 
@@ -291,12 +328,19 @@ pub fn term_search<DB: HirDatabase>(ctx: &TermSearchCtx<'_, DB>) -> Vec<Expr> {
     solutions.extend(tactics::assoc_const(ctx, &defs, &mut lookup));
 
     while should_continue() {
+        lookup.new_round();
+
         solutions.extend(tactics::data_constructor(ctx, &defs, &mut lookup, should_continue));
         solutions.extend(tactics::free_function(ctx, &defs, &mut lookup, should_continue));
         solutions.extend(tactics::impl_method(ctx, &defs, &mut lookup, should_continue));
         solutions.extend(tactics::struct_projection(ctx, &defs, &mut lookup, should_continue));
         solutions.extend(tactics::impl_static_method(ctx, &defs, &mut lookup, should_continue));
         solutions.extend(tactics::make_tuple(ctx, &defs, &mut lookup, should_continue));
+
+        // Discard not interesting `ScopeDef`s for speedup
+        for def in lookup.exhausted_scopedefs() {
+            defs.remove(def);
+        }
     }
 
     solutions.into_iter().filter(|it| !it.is_many()).unique().collect()
diff --git a/crates/hir/src/term_search/expr.rs b/crates/hir/src/term_search/expr.rs
index a6faa97196..bb687f5e73 100644
--- a/crates/hir/src/term_search/expr.rs
+++ b/crates/hir/src/term_search/expr.rs
@@ -209,7 +209,7 @@ impl Expr {
                 }
             }
             Expr::Variant { variant, generics, params } => {
-                let generics = non_default_generics(db, variant.parent_enum(db).into(), generics);
+                let generics = non_default_generics(db, (*variant).into(), generics);
                 let generics_str = match generics.is_empty() {
                     true => String::new(),
                     false => {
diff --git a/crates/hir/src/term_search/tactics.rs b/crates/hir/src/term_search/tactics.rs
index d1fc68d009..b738e6af77 100644
--- a/crates/hir/src/term_search/tactics.rs
+++ b/crates/hir/src/term_search/tactics.rs
@@ -17,11 +17,11 @@ use itertools::Itertools;
 use rustc_hash::FxHashSet;
 
 use crate::{
-    Adt, AssocItem, GenericDef, GenericParam, HasAttrs, HasVisibility, Impl, ModuleDef, ScopeDef,
-    Type, TypeParam,
+    Adt, AssocItem, Enum, GenericDef, GenericParam, HasVisibility, Impl, ModuleDef, ScopeDef, Type,
+    TypeParam, Variant,
 };
 
-use crate::term_search::Expr;
+use crate::term_search::{Expr, TermSearchConfig};
 
 use super::{LookupTable, NewTypesKey, TermSearchCtx};
 
@@ -74,6 +74,8 @@ pub(super) fn trivial<'a, DB: HirDatabase>(
             _ => None,
         }?;
 
+        lookup.mark_exhausted(*def);
+
         let ty = expr.ty(db);
         lookup.insert(ty.clone(), std::iter::once(expr.clone()));
 
@@ -122,10 +124,6 @@ pub(super) fn assoc_const<'a, DB: HirDatabase>(
         .filter(move |it| it.is_visible_from(db, module))
         .filter_map(AssocItem::as_const)
         .filter_map(|it| {
-            if it.attrs(db).is_unstable() {
-                return None;
-            }
-
             let expr = Expr::Const(it);
             let ty = it.ty(db);
 
@@ -153,101 +151,212 @@ pub(super) fn assoc_const<'a, DB: HirDatabase>(
 /// * `should_continue` - Function that indicates when to stop iterating
 pub(super) fn data_constructor<'a, DB: HirDatabase>(
     ctx: &'a TermSearchCtx<'a, DB>,
-    _defs: &'a FxHashSet<ScopeDef>,
+    defs: &'a FxHashSet<ScopeDef>,
     lookup: &'a mut LookupTable,
     should_continue: &'a dyn std::ops::Fn() -> bool,
 ) -> impl Iterator<Item = Expr> + 'a {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
-    lookup
-        .types_wishlist()
-        .clone()
-        .into_iter()
-        .chain(iter::once(ctx.goal.clone()))
-        .filter_map(|ty| ty.as_adt().map(|adt| (adt, ty)))
-        .filter(|_| should_continue())
-        .filter_map(move |(adt, ty)| match adt {
-            Adt::Struct(strukt) => {
-                // Ignore unstable or not visible
-                if strukt.is_unstable(db) || !strukt.is_visible_from(db, module) {
-                    return None;
-                }
+    fn variant_helper(
+        db: &dyn HirDatabase,
+        lookup: &mut LookupTable,
+        should_continue: &dyn std::ops::Fn() -> bool,
+        parent_enum: Enum,
+        variant: Variant,
+        config: &TermSearchConfig,
+    ) -> Vec<(Type, Vec<Expr>)> {
+        // Ignore unstable
+        if variant.is_unstable(db) {
+            return Vec::new();
+        }
 
-                let generics = GenericDef::from(strukt);
+        let generics = GenericDef::from(variant.parent_enum(db));
+        let Some(type_params) = generics
+            .type_or_const_params(db)
+            .into_iter()
+            .map(|it| it.as_type_param(db))
+            .collect::<Option<Vec<TypeParam>>>()
+        else {
+            // Ignore enums with const generics
+            return Vec::new();
+        };
+
+        // We currently do not check lifetime bounds so ignore all types that have something to do
+        // with them
+        if !generics.lifetime_params(db).is_empty() {
+            return Vec::new();
+        }
 
-                // We currently do not check lifetime bounds so ignore all types that have something to do
-                // with them
-                if !generics.lifetime_params(db).is_empty() {
-                    return None;
-                }
+        // Only account for stable type parameters for now, unstable params can be default
+        // tho, for example in `Box<T, #[unstable] A: Allocator>`
+        if type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none()) {
+            return Vec::new();
+        }
 
-                if ty.contains_unknown() {
-                    return None;
-                }
+        let non_default_type_params_len =
+            type_params.iter().filter(|it| it.default(db).is_none()).count();
+
+        let enum_ty_shallow = Adt::from(parent_enum).ty(db);
+        let generic_params = lookup
+            .types_wishlist()
+            .clone()
+            .into_iter()
+            .filter(|ty| ty.could_unify_with(db, &enum_ty_shallow))
+            .map(|it| it.type_arguments().collect::<Vec<Type>>())
+            .chain((non_default_type_params_len == 0).then_some(Vec::new()));
+
+        generic_params
+            .filter(|_| should_continue())
+            .filter_map(move |generics| {
+                // Insert default type params
+                let mut g = generics.into_iter();
+                let generics: Vec<_> = type_params
+                    .iter()
+                    .map(|it| it.default(db).or_else(|| g.next()))
+                    .collect::<Option<_>>()?;
+
+                let enum_ty = Adt::from(parent_enum).ty_with_args(db, generics.iter().cloned());
 
                 // Ignore types that have something to do with lifetimes
-                if ctx.config.enable_borrowcheck && ty.contains_reference(db) {
+                if config.enable_borrowcheck && enum_ty.contains_reference(db) {
                     return None;
                 }
-                let fields = strukt.fields(db);
-                // Check if all fields are visible, otherwise we cannot fill them
-                if fields.iter().any(|it| !it.is_visible_from(db, module)) {
-                    return None;
-                }
-
-                let generics: Vec<_> = ty.type_arguments().collect();
 
                 // Early exit if some param cannot be filled from lookup
-                let param_exprs: Vec<Vec<Expr>> = fields
+                let param_exprs: Vec<Vec<Expr>> = variant
+                    .fields(db)
                     .into_iter()
                     .map(|field| lookup.find(db, &field.ty_with_args(db, generics.iter().cloned())))
                     .collect::<Option<_>>()?;
 
                 // Note that we need special case for 0 param constructors because of multi cartesian
                 // product
-                let exprs: Vec<Expr> = if param_exprs.is_empty() {
-                    vec![Expr::Struct { strukt, generics, params: Vec::new() }]
+                let variant_exprs: Vec<Expr> = if param_exprs.is_empty() {
+                    vec![Expr::Variant { variant, generics, params: Vec::new() }]
                 } else {
                     param_exprs
                         .into_iter()
                         .multi_cartesian_product()
-                        .map(|params| Expr::Struct { strukt, generics: generics.clone(), params })
+                        .map(|params| Expr::Variant { variant, generics: generics.clone(), params })
                         .collect()
                 };
+                lookup.insert(enum_ty.clone(), variant_exprs.iter().cloned());
+
+                Some((enum_ty, variant_exprs))
+            })
+            .collect()
+    }
+    defs.iter()
+        .filter_map(move |def| match def {
+            ScopeDef::ModuleDef(ModuleDef::Variant(it)) => {
+                let variant_exprs = variant_helper(
+                    db,
+                    lookup,
+                    should_continue,
+                    it.parent_enum(db),
+                    *it,
+                    &ctx.config,
+                );
+                if variant_exprs.is_empty() {
+                    return None;
+                }
+                if GenericDef::from(it.parent_enum(db))
+                    .type_or_const_params(db)
+                    .into_iter()
+                    .filter_map(|it| it.as_type_param(db))
+                    .all(|it| it.default(db).is_some())
+                {
+                    lookup.mark_fulfilled(ScopeDef::ModuleDef(ModuleDef::Variant(*it)));
+                }
+                Some(variant_exprs)
+            }
+            ScopeDef::ModuleDef(ModuleDef::Adt(Adt::Enum(enum_))) => {
+                let exprs: Vec<(Type, Vec<Expr>)> = enum_
+                    .variants(db)
+                    .into_iter()
+                    .flat_map(|it| {
+                        variant_helper(db, lookup, should_continue, *enum_, it, &ctx.config)
+                    })
+                    .collect();
+
+                if exprs.is_empty() {
+                    return None;
+                }
 
-                lookup.insert(ty.clone(), exprs.iter().cloned());
-                Some((ty, exprs))
+                if GenericDef::from(*enum_)
+                    .type_or_const_params(db)
+                    .into_iter()
+                    .filter_map(|it| it.as_type_param(db))
+                    .all(|it| it.default(db).is_some())
+                {
+                    lookup.mark_fulfilled(ScopeDef::ModuleDef(ModuleDef::Adt(Adt::Enum(*enum_))));
+                }
+
+                Some(exprs)
             }
-            Adt::Enum(enum_) => {
-                // Ignore unstable or not visible
-                if enum_.is_unstable(db) || !enum_.is_visible_from(db, module) {
+            ScopeDef::ModuleDef(ModuleDef::Adt(Adt::Struct(it))) => {
+                // Ignore unstable and not visible
+                if it.is_unstable(db) || !it.is_visible_from(db, module) {
                     return None;
                 }
 
-                let generics = GenericDef::from(enum_);
+                let generics = GenericDef::from(*it);
+
+                // Ignore const params for now
+                let type_params = generics
+                    .type_or_const_params(db)
+                    .into_iter()
+                    .map(|it| it.as_type_param(db))
+                    .collect::<Option<Vec<TypeParam>>>()?;
+
                 // We currently do not check lifetime bounds so ignore all types that have something to do
                 // with them
                 if !generics.lifetime_params(db).is_empty() {
                     return None;
                 }
 
-                if ty.contains_unknown() {
+                // Only account for stable type parameters for now, unstable params can be default
+                // tho, for example in `Box<T, #[unstable] A: Allocator>`
+                if type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none()) {
                     return None;
                 }
 
-                // Ignore types that have something to do with lifetimes
-                if ctx.config.enable_borrowcheck && ty.contains_reference(db) {
-                    return None;
-                }
+                let non_default_type_params_len =
+                    type_params.iter().filter(|it| it.default(db).is_none()).count();
 
-                let generics: Vec<_> = ty.type_arguments().collect();
-                let exprs = enum_
-                    .variants(db)
+                let struct_ty_shallow = Adt::from(*it).ty(db);
+                let generic_params = lookup
+                    .types_wishlist()
+                    .clone()
                     .into_iter()
-                    .filter_map(|variant| {
+                    .filter(|ty| ty.could_unify_with(db, &struct_ty_shallow))
+                    .map(|it| it.type_arguments().collect::<Vec<Type>>())
+                    .chain((non_default_type_params_len == 0).then_some(Vec::new()));
+
+                let exprs = generic_params
+                    .filter(|_| should_continue())
+                    .filter_map(|generics| {
+                        // Insert default type params
+                        let mut g = generics.into_iter();
+                        let generics: Vec<_> = type_params
+                            .iter()
+                            .map(|it| it.default(db).or_else(|| g.next()))
+                            .collect::<Option<_>>()?;
+
+                        let struct_ty = Adt::from(*it).ty_with_args(db, generics.iter().cloned());
+
+                        // Ignore types that have something to do with lifetimes
+                        if ctx.config.enable_borrowcheck && struct_ty.contains_reference(db) {
+                            return None;
+                        }
+                        let fields = it.fields(db);
+                        // Check if all fields are visible, otherwise we cannot fill them
+                        if fields.iter().any(|it| !it.is_visible_from(db, module)) {
+                            return None;
+                        }
+
                         // Early exit if some param cannot be filled from lookup
-                        let param_exprs: Vec<Vec<Expr>> = variant
-                            .fields(db)
+                        let param_exprs: Vec<Vec<Expr>> = fields
                             .into_iter()
                             .map(|field| {
                                 lookup.find(db, &field.ty_with_args(db, generics.iter().cloned()))
@@ -256,33 +365,36 @@ pub(super) fn data_constructor<'a, DB: HirDatabase>(
 
                         // Note that we need special case for 0 param constructors because of multi cartesian
                         // product
-                        let variant_exprs: Vec<Expr> = if param_exprs.is_empty() {
-                            vec![Expr::Variant {
-                                variant,
-                                generics: generics.clone(),
-                                params: Vec::new(),
-                            }]
+                        let struct_exprs: Vec<Expr> = if param_exprs.is_empty() {
+                            vec![Expr::Struct { strukt: *it, generics, params: Vec::new() }]
                         } else {
                             param_exprs
                                 .into_iter()
                                 .multi_cartesian_product()
-                                .map(|params| Expr::Variant {
-                                    variant,
+                                .map(|params| Expr::Struct {
+                                    strukt: *it,
                                     generics: generics.clone(),
                                     params,
                                 })
                                 .collect()
                         };
-                        lookup.insert(ty.clone(), variant_exprs.iter().cloned());
-                        Some(variant_exprs)
+
+                        if non_default_type_params_len == 0 {
+                            // Fulfilled only if there are no generic parameters
+                            lookup.mark_fulfilled(ScopeDef::ModuleDef(ModuleDef::Adt(
+                                Adt::Struct(*it),
+                            )));
+                        }
+                        lookup.insert(struct_ty.clone(), struct_exprs.iter().cloned());
+
+                        Some((struct_ty, struct_exprs))
                     })
-                    .flatten()
                     .collect();
-
-                Some((ty, exprs))
+                Some(exprs)
             }
-            Adt::Union(_) => None,
+            _ => None,
         })
+        .flatten()
         .filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs))
         .flatten()
 }
@@ -403,6 +515,7 @@ pub(super) fn free_function<'a, DB: HirDatabase>(
                                 .collect()
                         };
 
+                        lookup.mark_fulfilled(ScopeDef::ModuleDef(ModuleDef::Function(*it)));
                         lookup.insert(ret_ty.clone(), fn_exprs.iter().cloned());
                         Some((ret_ty, fn_exprs))
                     })
@@ -442,8 +555,6 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
     lookup
         .new_types(NewTypesKey::ImplMethod)
         .into_iter()
-        .filter(|ty| !ty.type_arguments().any(|it| it.contains_unknown()))
-        .filter(|_| should_continue())
         .flat_map(|ty| {
             Impl::all_for_type(db, ty.clone()).into_iter().map(move |imp| (ty.clone(), imp))
         })
@@ -452,15 +563,26 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
             AssocItem::Function(f) => Some((imp, ty, f)),
             _ => None,
         })
-        .filter(|_| should_continue())
         .filter_map(move |(imp, ty, it)| {
             let fn_generics = GenericDef::from(it);
             let imp_generics = GenericDef::from(imp);
 
+            // Ignore const params for now
+            let imp_type_params = imp_generics
+                .type_or_const_params(db)
+                .into_iter()
+                .map(|it| it.as_type_param(db))
+                .collect::<Option<Vec<TypeParam>>>()?;
+
+            // Ignore const params for now
+            let fn_type_params = fn_generics
+                .type_or_const_params(db)
+                .into_iter()
+                .map(|it| it.as_type_param(db))
+                .collect::<Option<Vec<TypeParam>>>()?;
+
             // Ignore all functions that have something to do with lifetimes as we don't check them
-            if !fn_generics.lifetime_params(db).is_empty()
-                || !imp_generics.lifetime_params(db).is_empty()
-            {
+            if !fn_generics.lifetime_params(db).is_empty() {
                 return None;
             }
 
@@ -474,59 +596,112 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
                 return None;
             }
 
-            // Ignore functions with generics for now as they kill the performance
-            // Also checking bounds for generics is problematic
-            if !fn_generics.type_or_const_params(db).is_empty() {
-                return None;
-            }
-
-            let ret_ty = it.ret_type_with_args(db, ty.type_arguments());
-            // Filter out functions that return references
-            if ctx.config.enable_borrowcheck && ret_ty.contains_reference(db) || ret_ty.is_raw_ptr()
+            // Only account for stable type parameters for now, unstable params can be default
+            // tho, for example in `Box<T, #[unstable] A: Allocator>`
+            if imp_type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none())
+                || fn_type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none())
             {
                 return None;
             }
 
-            // Ignore functions that do not change the type
-            if ty.could_unify_with_deeply(db, &ret_ty) {
+            // Double check that we have fully known type
+            if ty.type_arguments().any(|it| it.contains_unknown()) {
                 return None;
             }
 
-            let self_ty =
-                it.self_param(db).expect("No self param").ty_with_args(db, ty.type_arguments());
+            let non_default_fn_type_params_len =
+                fn_type_params.iter().filter(|it| it.default(db).is_none()).count();
 
-            // Ignore functions that have different self type
-            if !self_ty.autoderef(db).any(|s_ty| ty == s_ty) {
+            // Ignore functions with generics for now as they kill the performance
+            // Also checking bounds for generics is problematic
+            if non_default_fn_type_params_len > 0 {
                 return None;
             }
 
-            let target_type_exprs = lookup.find(db, &ty).expect("Type not in lookup");
-
-            // Early exit if some param cannot be filled from lookup
-            let param_exprs: Vec<Vec<Expr>> = it
-                .params_without_self_with_args(db, ty.type_arguments())
+            let generic_params = lookup
+                .iter_types()
+                .collect::<Vec<_>>() // Force take ownership
                 .into_iter()
-                .map(|field| lookup.find_autoref(db, field.ty()))
-                .collect::<Option<_>>()?;
+                .permutations(non_default_fn_type_params_len);
 
-            let generics: Vec<_> = ty.type_arguments().collect();
-            let fn_exprs: Vec<Expr> = std::iter::once(target_type_exprs)
-                .chain(param_exprs)
-                .multi_cartesian_product()
-                .map(|params| {
-                    let mut params = params.into_iter();
-                    let target = Box::new(params.next().unwrap());
-                    Expr::Method {
-                        func: it,
-                        generics: generics.clone(),
-                        target,
-                        params: params.collect(),
+            let exprs: Vec<_> = generic_params
+                .filter(|_| should_continue())
+                .filter_map(|generics| {
+                    // Insert default type params
+                    let mut g = generics.into_iter();
+                    let generics: Vec<_> = ty
+                        .type_arguments()
+                        .map(Some)
+                        .chain(fn_type_params.iter().map(|it| match it.default(db) {
+                            Some(ty) => Some(ty),
+                            None => {
+                                let generic = g.next().expect("Missing type param");
+                                // Filter out generics that do not unify due to trait bounds
+                                it.ty(db).could_unify_with(db, &generic).then_some(generic)
+                            }
+                        }))
+                        .collect::<Option<_>>()?;
+
+                    let ret_ty = it.ret_type_with_args(
+                        db,
+                        ty.type_arguments().chain(generics.iter().cloned()),
+                    );
+                    // Filter out functions that return references
+                    if ctx.config.enable_borrowcheck && ret_ty.contains_reference(db)
+                        || ret_ty.is_raw_ptr()
+                    {
+                        return None;
+                    }
+
+                    // Ignore functions that do not change the type
+                    if ty.could_unify_with_deeply(db, &ret_ty) {
+                        return None;
+                    }
+
+                    let self_ty = it
+                        .self_param(db)
+                        .expect("No self param")
+                        .ty_with_args(db, ty.type_arguments().chain(generics.iter().cloned()));
+
+                    // Ignore functions that have different self type
+                    if !self_ty.autoderef(db).any(|s_ty| ty == s_ty) {
+                        return None;
                     }
+
+                    let target_type_exprs = lookup.find(db, &ty).expect("Type not in lookup");
+
+                    // Early exit if some param cannot be filled from lookup
+                    let param_exprs: Vec<Vec<Expr>> = it
+                        .params_without_self_with_args(
+                            db,
+                            ty.type_arguments().chain(generics.iter().cloned()),
+                        )
+                        .into_iter()
+                        .map(|field| lookup.find_autoref(db, field.ty()))
+                        .collect::<Option<_>>()?;
+
+                    let fn_exprs: Vec<Expr> = std::iter::once(target_type_exprs)
+                        .chain(param_exprs)
+                        .multi_cartesian_product()
+                        .map(|params| {
+                            let mut params = params.into_iter();
+                            let target = Box::new(params.next().unwrap());
+                            Expr::Method {
+                                func: it,
+                                generics: generics.clone(),
+                                target,
+                                params: params.collect(),
+                            }
+                        })
+                        .collect();
+
+                    lookup.insert(ret_ty.clone(), fn_exprs.iter().cloned());
+                    Some((ret_ty, fn_exprs))
                 })
                 .collect();
-
-            Some((ret_ty, fn_exprs))
+            Some(exprs)
         })
+        .flatten()
         .filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs))
         .flatten()
 }
@@ -630,7 +805,6 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
         .clone()
         .into_iter()
         .chain(iter::once(ctx.goal.clone()))
-        .filter(|ty| !ty.type_arguments().any(|it| it.contains_unknown()))
         .filter(|_| should_continue())
         .flat_map(|ty| {
             Impl::all_for_type(db, ty.clone()).into_iter().map(move |imp| (ty.clone(), imp))
@@ -641,11 +815,24 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
             AssocItem::Function(f) => Some((imp, ty, f)),
             _ => None,
         })
-        .filter(|_| should_continue())
         .filter_map(move |(imp, ty, it)| {
             let fn_generics = GenericDef::from(it);
             let imp_generics = GenericDef::from(imp);
 
+            // Ignore const params for now
+            let imp_type_params = imp_generics
+                .type_or_const_params(db)
+                .into_iter()
+                .map(|it| it.as_type_param(db))
+                .collect::<Option<Vec<TypeParam>>>()?;
+
+            // Ignore const params for now
+            let fn_type_params = fn_generics
+                .type_or_const_params(db)
+                .into_iter()
+                .map(|it| it.as_type_param(db))
+                .collect::<Option<Vec<TypeParam>>>()?;
+
             // Ignore all functions that have something to do with lifetimes as we don't check them
             if !fn_generics.lifetime_params(db).is_empty()
                 || !imp_generics.lifetime_params(db).is_empty()
@@ -663,43 +850,104 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
                 return None;
             }
 
-            // Ignore functions with generics for now as they kill the performance
-            // Also checking bounds for generics is problematic
-            if !fn_generics.type_or_const_params(db).is_empty() {
+            // Only account for stable type parameters for now, unstable params can be default
+            // tho, for example in `Box<T, #[unstable] A: Allocator>`
+            if imp_type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none())
+                || fn_type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none())
+            {
                 return None;
             }
 
-            let ret_ty = it.ret_type_with_args(db, ty.type_arguments());
-            // Filter out functions that return references
-            if ctx.config.enable_borrowcheck && ret_ty.contains_reference(db) || ret_ty.is_raw_ptr()
-            {
+            // Double check that we have fully known type
+            if ty.type_arguments().any(|it| it.contains_unknown()) {
                 return None;
             }
 
-            // Early exit if some param cannot be filled from lookup
-            let param_exprs: Vec<Vec<Expr>> = it
-                .params_without_self_with_args(db, ty.type_arguments())
+            let non_default_fn_type_params_len =
+                fn_type_params.iter().filter(|it| it.default(db).is_none()).count();
+
+            // Ignore functions with generics for now as they kill the performance
+            // Also checking bounds for generics is problematic
+            if non_default_fn_type_params_len > 0 {
+                return None;
+            }
+
+            let generic_params = lookup
+                .iter_types()
+                .collect::<Vec<_>>() // Force take ownership
                 .into_iter()
-                .map(|field| lookup.find_autoref(db, field.ty()))
-                .collect::<Option<_>>()?;
-
-            // Note that we need special case for 0 param constructors because of multi cartesian
-            // product
-            let generics = ty.type_arguments().collect();
-            let fn_exprs: Vec<Expr> = if param_exprs.is_empty() {
-                vec![Expr::Function { func: it, generics, params: Vec::new() }]
-            } else {
-                param_exprs
-                    .into_iter()
-                    .multi_cartesian_product()
-                    .map(|params| Expr::Function { func: it, generics: generics.clone(), params })
-                    .collect()
-            };
+                .permutations(non_default_fn_type_params_len);
+
+            let exprs: Vec<_> = generic_params
+                .filter(|_| should_continue())
+                .filter_map(|generics| {
+                    // Insert default type params
+                    let mut g = generics.into_iter();
+                    let generics: Vec<_> = ty
+                        .type_arguments()
+                        .map(Some)
+                        .chain(fn_type_params.iter().map(|it| match it.default(db) {
+                            Some(ty) => Some(ty),
+                            None => {
+                                let generic = g.next().expect("Missing type param");
+                                it.trait_bounds(db)
+                                    .into_iter()
+                                    .all(|bound| generic.impls_trait(db, bound, &[]));
+                                // Filter out generics that do not unify due to trait bounds
+                                it.ty(db).could_unify_with(db, &generic).then_some(generic)
+                            }
+                        }))
+                        .collect::<Option<_>>()?;
+
+                    let ret_ty = it.ret_type_with_args(
+                        db,
+                        ty.type_arguments().chain(generics.iter().cloned()),
+                    );
+                    // Filter out functions that return references
+                    if ctx.config.enable_borrowcheck && ret_ty.contains_reference(db)
+                        || ret_ty.is_raw_ptr()
+                    {
+                        return None;
+                    }
 
-            lookup.insert(ret_ty.clone(), fn_exprs.iter().cloned());
+                    // Ignore functions that do not change the type
+                    // if ty.could_unify_with_deeply(db, &ret_ty) {
+                    //     return None;
+                    // }
+
+                    // Early exit if some param cannot be filled from lookup
+                    let param_exprs: Vec<Vec<Expr>> = it
+                        .params_without_self_with_args(
+                            db,
+                            ty.type_arguments().chain(generics.iter().cloned()),
+                        )
+                        .into_iter()
+                        .map(|field| lookup.find_autoref(db, field.ty()))
+                        .collect::<Option<_>>()?;
+
+                    // Note that we need special case for 0 param constructors because of multi cartesian
+                    // product
+                    let fn_exprs: Vec<Expr> = if param_exprs.is_empty() {
+                        vec![Expr::Function { func: it, generics, params: Vec::new() }]
+                    } else {
+                        param_exprs
+                            .into_iter()
+                            .multi_cartesian_product()
+                            .map(|params| Expr::Function {
+                                func: it,
+                                generics: generics.clone(),
+                                params,
+                            })
+                            .collect()
+                    };
 
-            Some((ret_ty, fn_exprs))
+                    lookup.insert(ret_ty.clone(), fn_exprs.iter().cloned());
+                    Some((ret_ty, fn_exprs))
+                })
+                .collect();
+            Some(exprs)
         })
+        .flatten()
         .filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs))
         .flatten()
 }
diff --git a/crates/ide-assists/src/handlers/merge_imports.rs b/crates/ide-assists/src/handlers/merge_imports.rs
index 797c5c0653..7f751c93e4 100644
--- a/crates/ide-assists/src/handlers/merge_imports.rs
+++ b/crates/ide-assists/src/handlers/merge_imports.rs
@@ -489,6 +489,25 @@ use foo::bar;
         );
     }
 
+    #[test]
+    fn test_merge_nested_empty_and_self_with_other() {
+        check_assist(
+            merge_imports,
+            r"
+use foo::$0{bar};
+use foo::{bar::{self, other}};
+",
+            r"
+use foo::bar::{self, other};
+",
+        );
+        check_assist_import_one_variations!(
+            "foo::$0{bar}",
+            "foo::{bar::{self, other}}",
+            "use {foo::bar::{self, other}};"
+        );
+    }
+
     #[test]
     fn test_merge_nested_list_self_and_glob() {
         check_assist(
diff --git a/crates/ide-assists/src/handlers/normalize_import.rs b/crates/ide-assists/src/handlers/normalize_import.rs
index 7d003efe72..0b91eb676d 100644
--- a/crates/ide-assists/src/handlers/normalize_import.rs
+++ b/crates/ide-assists/src/handlers/normalize_import.rs
@@ -119,10 +119,39 @@ mod tests {
         );
     }
 
+    #[test]
+    fn test_braces_kept() {
+        check_assist_not_applicable_variations!("foo::bar::{$0self}");
+
+        // This code compiles but transforming "bar::{self}" into "bar" causes a
+        // compilation error (the name `bar` is defined multiple times).
+        // Therefore, the normalize_input assist must not apply here.
+        check_assist_not_applicable(
+            normalize_import,
+            r"
+mod foo {
+
+    pub mod bar {}
+
+    pub const bar: i32 = 8;
+}
+
+use foo::bar::{$0self};
+
+const bar: u32 = 99;
+
+fn main() {
+    let local_bar = bar;
+}
+
+",
+        );
+    }
+
     #[test]
     fn test_redundant_braces() {
         check_assist_variations!("foo::{bar::{baz, Qux}}", "foo::bar::{baz, Qux}");
-        check_assist_variations!("foo::{bar::{self}}", "foo::bar");
+        check_assist_variations!("foo::{bar::{self}}", "foo::bar::{self}");
         check_assist_variations!("foo::{bar::{*}}", "foo::bar::*");
         check_assist_variations!("foo::{bar::{Qux as Quux}}", "foo::bar::Qux as Quux");
         check_assist_variations!(
diff --git a/crates/ide-assists/src/handlers/remove_parentheses.rs b/crates/ide-assists/src/handlers/remove_parentheses.rs
index f74fc26112..799d36be93 100644
--- a/crates/ide-assists/src/handlers/remove_parentheses.rs
+++ b/crates/ide-assists/src/handlers/remove_parentheses.rs
@@ -239,33 +239,4 @@ mod tests {
 
         check_assist_not_applicable(remove_parentheses, r#"fn f() { $0(return 2) + 2 }"#);
     }
-
-    #[test]
-    fn remove_parens_indirect_calls() {
-        check_assist(
-            remove_parentheses,
-            r#"fn f(call: fn(usize), arg: usize) { $0(call)(arg); }"#,
-            r#"fn f(call: fn(usize), arg: usize) { call(arg); }"#,
-        );
-        check_assist(
-            remove_parentheses,
-            r#"fn f<F>(call: F, arg: usize) where F: Fn(usize) { $0(call)(arg); }"#,
-            r#"fn f<F>(call: F, arg: usize) where F: Fn(usize) { call(arg); }"#,
-        );
-
-        // Parentheses are necessary when calling a function-like pointer that is a member of a struct or union.
-        check_assist_not_applicable(
-            remove_parentheses,
-            r#"
-struct Foo<T> {
-    t: T,
-}
-
-impl Foo<fn(usize)> {
-    fn foo(&self, arg: usize) {
-        $0(self.t)(arg);
-    }
-}"#,
-        );
-    }
 }
diff --git a/crates/ide-assists/src/handlers/term_search.rs b/crates/ide-assists/src/handlers/term_search.rs
index b62c3b3323..8a9229c549 100644
--- a/crates/ide-assists/src/handlers/term_search.rs
+++ b/crates/ide-assists/src/handlers/term_search.rs
@@ -144,7 +144,7 @@ fn f() { let a = A { x: 1, y: true }; let b: i32 = a.x; }"#,
             term_search,
             r#"//- minicore: todo, unimplemented, option
 fn f() { let a: i32 = 1; let b: Option<i32> = todo$0!(); }"#,
-            r#"fn f() { let a: i32 = 1; let b: Option<i32> = Some::<i32>(a); }"#,
+            r#"fn f() { let a: i32 = 1; let b: Option<i32> = None; }"#,
         )
     }
 
@@ -156,7 +156,7 @@ fn f() { let a: i32 = 1; let b: Option<i32> = todo$0!(); }"#,
 enum Option<T> { None, Some(T) }
 fn f() { let a: i32 = 1; let b: Option<i32> = todo$0!(); }"#,
             r#"enum Option<T> { None, Some(T) }
-fn f() { let a: i32 = 1; let b: Option<i32> = Option::Some::<i32>(a); }"#,
+fn f() { let a: i32 = 1; let b: Option<i32> = Option::Some(a); }"#,
         )
     }
 
@@ -168,7 +168,7 @@ fn f() { let a: i32 = 1; let b: Option<i32> = Option::Some::<i32>(a); }"#,
 enum Option<T> { None, Some(T) }
 fn f() { let a: Option<i32> = Option::None; let b: Option<Option<i32>> = todo$0!(); }"#,
             r#"enum Option<T> { None, Some(T) }
-fn f() { let a: Option<i32> = Option::None; let b: Option<Option<i32>> = Option::Some::<Option<i32>>(a); }"#,
+fn f() { let a: Option<i32> = Option::None; let b: Option<Option<i32>> = Option::Some(a); }"#,
         )
     }
 
@@ -180,7 +180,7 @@ fn f() { let a: Option<i32> = Option::None; let b: Option<Option<i32>> = Option:
 enum Foo<T = i32> { Foo(T) }
 fn f() { let a = 0; let b: Foo = todo$0!(); }"#,
             r#"enum Foo<T = i32> { Foo(T) }
-fn f() { let a = 0; let b: Foo = Foo::Foo::<i32>(a); }"#,
+fn f() { let a = 0; let b: Foo = Foo::Foo(a); }"#,
         );
 
         check_assist(
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index 743aa00570..80ce5bd4cf 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -1334,7 +1334,7 @@ fn pattern_context_for(
         .map_or((PatternRefutability::Irrefutable, false), |node| {
             let refutability = match_ast! {
                 match node {
-                    ast::LetStmt(let_) => return (PatternRefutability::Refutable, let_.ty().is_some()),
+                    ast::LetStmt(let_) => return (PatternRefutability::Irrefutable, let_.ty().is_some()),
                     ast::Param(param) => {
                         let has_type_ascription = param.ty().is_some();
                         param_ctx = (|| {
diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs
index ff60a7669e..ebdc813f3d 100644
--- a/crates/ide-completion/src/render.rs
+++ b/crates/ide-completion/src/render.rs
@@ -764,7 +764,6 @@ fn main() {
 "#,
             expect![[r#"
                 st dep::test_mod_b::Struct {…} [type_could_unify]
-                ex dep::test_mod_b::Struct {  } [type_could_unify]
                 st Struct (use dep::test_mod_b::Struct) [type_could_unify+requires_import]
                 fn main() []
                 fn test(…) []
@@ -840,7 +839,6 @@ fn main() {
 "#,
             expect![[r#"
                 ev dep::test_mod_b::Enum::variant [type_could_unify]
-                ex dep::test_mod_b::Enum::variant [type_could_unify]
                 en Enum (use dep::test_mod_b::Enum) [type_could_unify+requires_import]
                 fn main() []
                 fn test(…) []
@@ -878,7 +876,6 @@ fn main() {
 "#,
             expect![[r#"
                 ev dep::test_mod_b::Enum::Variant [type_could_unify]
-                ex dep::test_mod_b::Enum::Variant [type_could_unify]
                 fn main() []
                 fn test(…) []
                 md dep []
@@ -1842,6 +1839,7 @@ fn f() { A { bar: b$0 }; }
                 fn baz() [type]
                 ex baz() [type]
                 ex bar() [type]
+                ex A { bar: ... }.bar [type]
                 st A []
                 fn f() []
             "#]],
@@ -1980,6 +1978,7 @@ fn main() {
             "#,
             expect![[r#"
                 ex core::ops::Deref::deref(&t) (use core::ops::Deref) [type_could_unify]
+                ex core::ops::Deref::deref(&T(S)) (use core::ops::Deref) [type_could_unify]
                 lc m [local]
                 lc t [local]
                 lc &t [type+local]
@@ -2029,6 +2028,7 @@ fn main() {
             "#,
             expect![[r#"
                 ex core::ops::DerefMut::deref_mut(&mut t) (use core::ops::DerefMut) [type_could_unify]
+                ex core::ops::DerefMut::deref_mut(&mut T(S)) (use core::ops::DerefMut) [type_could_unify]
                 lc m [local]
                 lc t [local]
                 lc &mut t [type+local]
@@ -2132,6 +2132,7 @@ fn main() {
 }
 "#,
             expect![[r#"
+                ex core::ops::Deref::deref(&T(S)) (use core::ops::Deref) [type_could_unify]
                 ex core::ops::Deref::deref(&bar()) (use core::ops::Deref) [type_could_unify]
                 st S []
                 st &S [type]
@@ -2641,7 +2642,7 @@ fn foo() {
             expect![[r#"
                 lc foo [type+local]
                 ex foo [type]
-                ex Foo::B::<u32> [type]
+                ex Foo::B [type]
                 ev Foo::A(…) [type_could_unify]
                 ev Foo::B [type_could_unify]
                 en Foo [type_could_unify]
diff --git a/crates/ide-db/src/active_parameter.rs b/crates/ide-db/src/active_parameter.rs
index 42a80d63b1..088d2ec5e3 100644
--- a/crates/ide-db/src/active_parameter.rs
+++ b/crates/ide-db/src/active_parameter.rs
@@ -79,9 +79,8 @@ pub fn generic_def_for_node(
     sema: &Semantics<'_, RootDatabase>,
     generic_arg_list: &ast::GenericArgList,
     token: &SyntaxToken,
-) -> Option<(hir::GenericDef, usize, bool, Option<hir::Variant>)> {
+) -> Option<(hir::GenericDef, usize, bool)> {
     let parent = generic_arg_list.syntax().parent()?;
-    let mut variant = None;
     let def = match_ast! {
         match parent {
             ast::PathSegment(ps) => {
@@ -92,10 +91,7 @@ pub fn generic_def_for_node(
                     hir::PathResolution::Def(hir::ModuleDef::Trait(it)) => it.into(),
                     hir::PathResolution::Def(hir::ModuleDef::TraitAlias(it)) => it.into(),
                     hir::PathResolution::Def(hir::ModuleDef::TypeAlias(it)) => it.into(),
-                    hir::PathResolution::Def(hir::ModuleDef::Variant(it)) => {
-                        variant = Some(it);
-                        it.parent_enum(sema.db).into()
-                    },
+                    hir::PathResolution::Def(hir::ModuleDef::Variant(it)) => it.into(),
                     hir::PathResolution::Def(hir::ModuleDef::BuiltinType(_))
                     | hir::PathResolution::Def(hir::ModuleDef::Const(_))
                     | hir::PathResolution::Def(hir::ModuleDef::Macro(_))
@@ -138,5 +134,5 @@ pub fn generic_def_for_node(
         .next()
         .map_or(false, |arg| !matches!(arg, ast::GenericArg::LifetimeArg(_)));
 
-    Some((def, active_param, first_arg_is_non_lifetime, variant))
+    Some((def, active_param, first_arg_is_non_lifetime))
 }
diff --git a/crates/ide-db/src/imports/merge_imports.rs b/crates/ide-db/src/imports/merge_imports.rs
index b153aafa0e..9cacb6b1a6 100644
--- a/crates/ide-db/src/imports/merge_imports.rs
+++ b/crates/ide-db/src/imports/merge_imports.rs
@@ -157,10 +157,14 @@ fn recursive_merge(lhs: &ast::UseTree, rhs: &ast::UseTree, merge: MergeBehavior)
                     }
 
                     match (tree_contains_self(lhs_t), tree_contains_self(&rhs_t)) {
-                        (Some(true), None) => continue,
+                        (Some(true), None) => {
+                            remove_subtree_if_only_self(lhs_t);
+                            continue;
+                        }
                         (None, Some(true)) => {
                             ted::replace(lhs_t.syntax(), rhs_t.syntax());
                             *lhs_t = rhs_t;
+                            remove_subtree_if_only_self(lhs_t);
                             continue;
                         }
                         _ => (),
@@ -278,14 +282,20 @@ pub fn try_normalize_use_tree_mut(
 fn recursive_normalize(use_tree: &ast::UseTree, style: NormalizationStyle) -> Option<()> {
     let use_tree_list = use_tree.use_tree_list()?;
     let merge_subtree_into_parent_tree = |single_subtree: &ast::UseTree| {
+        let subtree_is_only_self = single_subtree.path().as_ref().map_or(false, path_is_self);
+
         let merged_path = match (use_tree.path(), single_subtree.path()) {
+            // If the subtree is `{self}` then we cannot merge: `use
+            // foo::bar::{self}` is not equivalent to `use foo::bar`. See
+            // https://github.com/rust-lang/rust-analyzer/pull/17140#issuecomment-2079189725.
+            _ if subtree_is_only_self => None,
+
             (None, None) => None,
             (Some(outer), None) => Some(outer),
-            (None, Some(inner)) if path_is_self(&inner) => None,
             (None, Some(inner)) => Some(inner),
-            (Some(outer), Some(inner)) if path_is_self(&inner) => Some(outer),
             (Some(outer), Some(inner)) => Some(make::path_concat(outer, inner).clone_for_update()),
         };
+
         if merged_path.is_some()
             || single_subtree.use_tree_list().is_some()
             || single_subtree.star_token().is_some()
@@ -706,3 +716,20 @@ fn path_is_self(path: &ast::Path) -> bool {
 fn path_len(path: ast::Path) -> usize {
     path.segments().count()
 }
+
+fn get_single_subtree(use_tree: &ast::UseTree) -> Option<ast::UseTree> {
+    use_tree
+        .use_tree_list()
+        .and_then(|tree_list| tree_list.use_trees().collect_tuple())
+        .map(|(single_subtree,)| single_subtree)
+}
+
+fn remove_subtree_if_only_self(use_tree: &ast::UseTree) {
+    let Some(single_subtree) = get_single_subtree(use_tree) else { return };
+    match (use_tree.path(), single_subtree.path()) {
+        (Some(_), Some(inner)) if path_is_self(&inner) => {
+            ted::remove_all_iter(single_subtree.syntax().children_with_tokens());
+        }
+        _ => (),
+    }
+}
diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs
index e1cfe04898..b62f34f415 100644
--- a/crates/ide-db/src/search.rs
+++ b/crates/ide-db/src/search.rs
@@ -320,6 +320,7 @@ impl Definition {
                 hir::GenericDef::TraitAlias(it) => it.source(db).map(|src| src.syntax().cloned()),
                 hir::GenericDef::TypeAlias(it) => it.source(db).map(|src| src.syntax().cloned()),
                 hir::GenericDef::Impl(it) => it.source(db).map(|src| src.syntax().cloned()),
+                hir::GenericDef::Variant(it) => it.source(db).map(|src| src.syntax().cloned()),
                 hir::GenericDef::Const(it) => it.source(db).map(|src| src.syntax().cloned()),
             };
             return match def {
diff --git a/crates/ide-diagnostics/src/handlers/incoherent_impl.rs b/crates/ide-diagnostics/src/handlers/incoherent_impl.rs
index d3f3020775..9f56e10414 100644
--- a/crates/ide-diagnostics/src/handlers/incoherent_impl.rs
+++ b/crates/ide-diagnostics/src/handlers/incoherent_impl.rs
@@ -1,23 +1,16 @@
 use hir::InFile;
-use syntax::{AstNode, TextRange};
 
-use crate::{adjusted_display_range, Diagnostic, DiagnosticCode, DiagnosticsContext};
+use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
 
 // Diagnostic: incoherent-impl
 //
 // This diagnostic is triggered if the targe type of an impl is from a foreign crate.
 pub(crate) fn incoherent_impl(ctx: &DiagnosticsContext<'_>, d: &hir::IncoherentImpl) -> Diagnostic {
-    let display_range = adjusted_display_range(ctx, InFile::new(d.file_id, d.impl_), &|node| {
-        Some(TextRange::new(
-            node.syntax().text_range().start(),
-            node.self_ty()?.syntax().text_range().end(),
-        ))
-    });
-
-    Diagnostic::new(
+    Diagnostic::new_with_syntax_node_ptr(
+        ctx,
         DiagnosticCode::RustcHardError("E0210"),
         "cannot define inherent `impl` for foreign type".to_owned(),
-        display_range,
+        InFile::new(d.file_id, d.impl_.into()),
     )
 }
 
@@ -30,7 +23,7 @@ mod change_case {
         check_diagnostics(
             r#"
   impl bool {}
-//^^^^^^^^^ error: cannot define inherent `impl` for foreign type
+//^^^^^^^^^^^^ error: cannot define inherent `impl` for foreign type
 "#,
         );
     }
@@ -67,7 +60,7 @@ impl foo::S {
 pub struct S;
 //- /main.rs crate:main deps:foo
   impl foo::S { #[rustc_allow_incoherent_impl] fn func(self) {} }
-//^^^^^^^^^^^ error: cannot define inherent `impl` for foreign type
+//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: cannot define inherent `impl` for foreign type
 "#,
         );
         check_diagnostics(
@@ -77,7 +70,7 @@ pub struct S;
 pub struct S;
 //- /main.rs crate:main deps:foo
   impl foo::S { fn func(self) {} }
-//^^^^^^^^^^^ error: cannot define inherent `impl` for foreign type
+//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: cannot define inherent `impl` for foreign type
 "#,
         );
     }
diff --git a/crates/ide-diagnostics/src/handlers/macro_error.rs b/crates/ide-diagnostics/src/handlers/macro_error.rs
index 2cd6a71c00..f8780fc0da 100644
--- a/crates/ide-diagnostics/src/handlers/macro_error.rs
+++ b/crates/ide-diagnostics/src/handlers/macro_error.rs
@@ -13,7 +13,7 @@ pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) ->
     )
 }
 
-// Diagnostic: macro-def-error
+// Diagnostic: macro-error
 //
 // This diagnostic is shown for macro expansion errors.
 pub(crate) fn macro_def_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroDefError) -> Diagnostic {
diff --git a/crates/ide-diagnostics/src/handlers/typed_hole.rs b/crates/ide-diagnostics/src/handlers/typed_hole.rs
index 71917e09f0..9651ce6106 100644
--- a/crates/ide-diagnostics/src/handlers/typed_hole.rs
+++ b/crates/ide-diagnostics/src/handlers/typed_hole.rs
@@ -276,7 +276,7 @@ impl Foo for Baz {
 }
 fn asd() -> Bar {
     let a = Baz;
-    Foo::foo(a)
+    Foo::foo(_)
 }
 ",
         );
@@ -365,7 +365,7 @@ impl Foo for A {
 }
 fn main() {
     let a = A;
-    let c: Bar = Foo::foo(&a);
+    let c: Bar = Foo::foo(_);
 }"#,
         );
     }
diff --git a/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/crates/ide-diagnostics/src/handlers/unlinked_file.rs
index 77ffd0fd96..cbf50d13f5 100644
--- a/crates/ide-diagnostics/src/handlers/unlinked_file.rs
+++ b/crates/ide-diagnostics/src/handlers/unlinked_file.rs
@@ -30,13 +30,11 @@ pub(crate) fn unlinked_file(
     // FIXME: This is a hack for the vscode extension to notice whether there is an autofix or not before having to resolve diagnostics.
     // This is to prevent project linking popups from appearing when there is an autofix. https://github.com/rust-lang/rust-analyzer/issues/14523
     let message = if fixes.is_none() {
-        "This file is not included in any crates, so rust-analyzer can't offer IDE services."
+        "file not included in crate hierarchy"
     } else {
-        "This file is not included anywhere in the module tree, so rust-analyzer can't offer IDE services."
+        "file not included in module tree"
     };
 
-    let message = format!("{message}\n\nIf you're intentionally working on unowned files, you can silence this warning by adding \"unlinked-file\" to rust-analyzer.diagnostics.disabled in your settings.");
-
     let mut range = ctx.sema.db.parse(file_id).syntax_node().text_range();
     let mut unused = true;
 
diff --git a/crates/ide/src/signature_help.rs b/crates/ide/src/signature_help.rs
index c5eaacdb10..89c725a6c4 100644
--- a/crates/ide/src/signature_help.rs
+++ b/crates/ide/src/signature_help.rs
@@ -272,7 +272,7 @@ fn signature_help_for_generics(
     arg_list: ast::GenericArgList,
     token: SyntaxToken,
 ) -> Option<SignatureHelp> {
-    let (generics_def, mut active_parameter, first_arg_is_non_lifetime, variant) =
+    let (mut generics_def, mut active_parameter, first_arg_is_non_lifetime) =
         generic_def_for_node(sema, &arg_list, &token)?;
     let mut res = SignatureHelp {
         doc: None,
@@ -290,12 +290,6 @@ fn signature_help_for_generics(
         hir::GenericDef::Adt(hir::Adt::Enum(it)) => {
             res.doc = it.docs(db);
             format_to!(res.signature, "enum {}", it.name(db).display(db));
-            if let Some(variant) = variant {
-                // In paths, generics of an enum can be specified *after* one of its variants.
-                // eg. `None::<u8>`
-                // We'll use the signature of the enum, but include the docs of the variant.
-                res.doc = variant.docs(db);
-            }
         }
         hir::GenericDef::Adt(hir::Adt::Struct(it)) => {
             res.doc = it.docs(db);
@@ -317,6 +311,15 @@ fn signature_help_for_generics(
             res.doc = it.docs(db);
             format_to!(res.signature, "type {}", it.name(db).display(db));
         }
+        hir::GenericDef::Variant(it) => {
+            // In paths, generics of an enum can be specified *after* one of its variants.
+            // eg. `None::<u8>`
+            // We'll use the signature of the enum, but include the docs of the variant.
+            res.doc = it.docs(db);
+            let enum_ = it.parent_enum(db);
+            format_to!(res.signature, "enum {}", enum_.name(db).display(db));
+            generics_def = enum_.into();
+        }
         // These don't have generic args that can be specified
         hir::GenericDef::Impl(_) | hir::GenericDef::Const(_) => return None,
     }
diff --git a/crates/mbe/Cargo.toml b/crates/mbe/Cargo.toml
index 18444018e1..2046fa943a 100644
--- a/crates/mbe/Cargo.toml
+++ b/crates/mbe/Cargo.toml
@@ -16,7 +16,6 @@ cov-mark = "2.0.0-pre.1"
 rustc-hash.workspace = true
 smallvec.workspace = true
 tracing.workspace = true
-arrayvec.workspace = true
 
 # local deps
 syntax.workspace = true
diff --git a/crates/mbe/src/benchmark.rs b/crates/mbe/src/benchmark.rs
index 27dbc84a2b..19ba5c7a15 100644
--- a/crates/mbe/src/benchmark.rs
+++ b/crates/mbe/src/benchmark.rs
@@ -170,7 +170,7 @@ fn invocation_fixtures(
             Op::Literal(it) => token_trees.push(tt::Leaf::from(it.clone()).into()),
             Op::Ident(it) => token_trees.push(tt::Leaf::from(it.clone()).into()),
             Op::Punct(puncts) => {
-                for punct in puncts.as_slice() {
+                for punct in puncts {
                     token_trees.push(tt::Leaf::from(*punct).into());
                 }
             }
@@ -187,7 +187,7 @@ fn invocation_fixtures(
                     }
                     if i + 1 != cnt {
                         if let Some(sep) = separator {
-                            match &**sep {
+                            match sep {
                                 Separator::Literal(it) => {
                                     token_trees.push(tt::Leaf::Literal(it.clone()).into())
                                 }
diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs
index b20d5579ca..0cec4e70da 100644
--- a/crates/mbe/src/expander/matcher.rs
+++ b/crates/mbe/src/expander/matcher.rs
@@ -59,17 +59,17 @@
 //! eof: [a $( a )* a b ·]
 //! ```
 
-use std::{rc::Rc, sync::Arc};
+use std::rc::Rc;
 
 use smallvec::{smallvec, SmallVec};
 use span::{Edition, Span};
 use syntax::SmolStr;
-use tt::{iter::TtIter, DelimSpan};
+use tt::DelimSpan;
 
 use crate::{
     expander::{Binding, Bindings, ExpandResult, Fragment},
-    expect_fragment,
     parser::{MetaVarKind, Op, RepeatKind, Separator},
+    tt_iter::TtIter,
     ExpandError, MetaTemplate, ValueResult,
 };
 
@@ -315,7 +315,7 @@ struct MatchState<'t> {
     up: Option<Box<MatchState<'t>>>,
 
     /// The separator if we are in a repetition.
-    sep: Option<Arc<Separator>>,
+    sep: Option<Separator>,
 
     /// The KleeneOp of this sequence if we are in a repetition.
     sep_kind: Option<RepeatKind>,
@@ -406,7 +406,7 @@ fn match_loop_inner<'t>(
                     if item.sep.is_some() && !item.sep_matched {
                         let sep = item.sep.as_ref().unwrap();
                         let mut fork = src.clone();
-                        if expect_separator(&mut fork, sep) {
+                        if fork.expect_separator(sep) {
                             // HACK: here we use `meta_result` to pass `TtIter` back to caller because
                             // it might have been advanced multiple times. `ValueResult` is
                             // insignificant.
@@ -746,7 +746,7 @@ fn match_meta_var(
 ) -> ExpandResult<Option<Fragment>> {
     let fragment = match kind {
         MetaVarKind::Path => {
-            return expect_fragment(input, parser::PrefixEntryPoint::Path, edition).map(|it| {
+            return input.expect_fragment(parser::PrefixEntryPoint::Path, edition).map(|it| {
                 it.map(|it| tt::TokenTree::subtree_or_wrap(it, delim_span)).map(Fragment::Path)
             });
         }
@@ -765,7 +765,7 @@ fn match_meta_var(
                 }
                 _ => {}
             };
-            return expect_fragment(input, parser::PrefixEntryPoint::Expr, edition).map(|tt| {
+            return input.expect_fragment(parser::PrefixEntryPoint::Expr, edition).map(|tt| {
                 tt.map(|tt| match tt {
                     tt::TokenTree::Leaf(leaf) => tt::Subtree {
                         delimiter: tt::Delimiter::invisible_spanned(*leaf.span()),
@@ -787,13 +787,14 @@ fn match_meta_var(
                     .expect_ident()
                     .map(|ident| tt::Leaf::from(ident.clone()).into())
                     .map_err(|()| ExpandError::binding_error("expected ident")),
-                MetaVarKind::Tt => {
-                    expect_tt(input).map_err(|()| ExpandError::binding_error("expected token tree"))
-                }
-                MetaVarKind::Lifetime => expect_lifetime(input)
+                MetaVarKind::Tt => input
+                    .expect_tt()
+                    .map_err(|()| ExpandError::binding_error("expected token tree")),
+                MetaVarKind::Lifetime => input
+                    .expect_lifetime()
                     .map_err(|()| ExpandError::binding_error("expected lifetime")),
                 MetaVarKind::Literal => {
-                    let neg = eat_char(input, '-');
+                    let neg = input.eat_char('-');
                     input
                         .expect_literal()
                         .map(|literal| {
@@ -821,7 +822,7 @@ fn match_meta_var(
         MetaVarKind::Item => parser::PrefixEntryPoint::Item,
         MetaVarKind::Vis => parser::PrefixEntryPoint::Vis,
     };
-    expect_fragment(input, fragment, edition).map(|it| it.map(Fragment::Tokens))
+    input.expect_fragment(fragment, edition).map(|it| it.map(Fragment::Tokens))
 }
 
 fn collect_vars(collector_fun: &mut impl FnMut(SmolStr), pattern: &MetaTemplate) {
@@ -904,84 +905,86 @@ impl<'a> Iterator for OpDelimitedIter<'a> {
     }
 }
 
-fn expect_separator<S: Copy>(iter: &mut TtIter<'_, S>, separator: &Separator) -> bool {
-    let mut fork = iter.clone();
-    let ok = match separator {
-        Separator::Ident(lhs) => match fork.expect_ident_or_underscore() {
-            Ok(rhs) => rhs.text == lhs.text,
-            Err(_) => false,
-        },
-        Separator::Literal(lhs) => match fork.expect_literal() {
-            Ok(rhs) => match rhs {
-                tt::Leaf::Literal(rhs) => rhs.text == lhs.text,
-                tt::Leaf::Ident(rhs) => rhs.text == lhs.text,
-                tt::Leaf::Punct(_) => false,
+impl TtIter<'_, Span> {
+    fn expect_separator(&mut self, separator: &Separator) -> bool {
+        let mut fork = self.clone();
+        let ok = match separator {
+            Separator::Ident(lhs) => match fork.expect_ident_or_underscore() {
+                Ok(rhs) => rhs.text == lhs.text,
+                Err(_) => false,
             },
-            Err(_) => false,
-        },
-        Separator::Puncts(lhs) => match fork.expect_glued_punct() {
-            Ok(rhs) => {
-                let lhs = lhs.iter().map(|it| it.char);
-                let rhs = rhs.iter().map(|it| it.char);
-                lhs.eq(rhs)
-            }
-            Err(_) => false,
-        },
-    };
-    if ok {
-        *iter = fork;
+            Separator::Literal(lhs) => match fork.expect_literal() {
+                Ok(rhs) => match rhs {
+                    tt::Leaf::Literal(rhs) => rhs.text == lhs.text,
+                    tt::Leaf::Ident(rhs) => rhs.text == lhs.text,
+                    tt::Leaf::Punct(_) => false,
+                },
+                Err(_) => false,
+            },
+            Separator::Puncts(lhs) => match fork.expect_glued_punct() {
+                Ok(rhs) => {
+                    let lhs = lhs.iter().map(|it| it.char);
+                    let rhs = rhs.iter().map(|it| it.char);
+                    lhs.eq(rhs)
+                }
+                Err(_) => false,
+            },
+        };
+        if ok {
+            *self = fork;
+        }
+        ok
     }
-    ok
-}
 
-fn expect_tt<S: Copy>(iter: &mut TtIter<'_, S>) -> Result<tt::TokenTree<S>, ()> {
-    if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) = iter.peek_n(0) {
-        if punct.char == '\'' {
-            expect_lifetime(iter)
+    fn expect_tt(&mut self) -> Result<tt::TokenTree<Span>, ()> {
+        if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) = self.peek_n(0) {
+            if punct.char == '\'' {
+                self.expect_lifetime()
+            } else {
+                let puncts = self.expect_glued_punct()?;
+                let delimiter = tt::Delimiter {
+                    open: puncts.first().unwrap().span,
+                    close: puncts.last().unwrap().span,
+                    kind: tt::DelimiterKind::Invisible,
+                };
+                let token_trees = puncts.into_iter().map(|p| tt::Leaf::Punct(p).into()).collect();
+                Ok(tt::TokenTree::Subtree(tt::Subtree { delimiter, token_trees }))
+            }
         } else {
-            let puncts = iter.expect_glued_punct()?;
-            let delimiter = tt::Delimiter {
-                open: puncts.first().unwrap().span,
-                close: puncts.last().unwrap().span,
-                kind: tt::DelimiterKind::Invisible,
-            };
-            let token_trees = puncts.into_iter().map(|p| tt::Leaf::Punct(p).into()).collect();
-            Ok(tt::TokenTree::Subtree(tt::Subtree { delimiter, token_trees }))
+            self.next().ok_or(()).cloned()
         }
-    } else {
-        iter.next().ok_or(()).cloned()
     }
-}
 
-fn expect_lifetime<S: Copy>(iter: &mut TtIter<'_, S>) -> Result<tt::TokenTree<S>, ()> {
-    let punct = iter.expect_single_punct()?;
-    if punct.char != '\'' {
-        return Err(());
-    }
-    let ident = iter.expect_ident_or_underscore()?;
-
-    Ok(tt::Subtree {
-        delimiter: tt::Delimiter {
-            open: punct.span,
-            close: ident.span,
-            kind: tt::DelimiterKind::Invisible,
-        },
-        token_trees: Box::new([
-            tt::Leaf::Punct(*punct).into(),
-            tt::Leaf::Ident(ident.clone()).into(),
-        ]),
-    }
-    .into())
-}
+    fn expect_lifetime(&mut self) -> Result<tt::TokenTree<Span>, ()> {
+        let punct = self.expect_single_punct()?;
+        if punct.char != '\'' {
+            return Err(());
+        }
+        let ident = self.expect_ident_or_underscore()?;
 
-fn eat_char<S: Copy>(iter: &mut TtIter<'_, S>, c: char) -> Option<tt::TokenTree<S>> {
-    let mut fork = iter.clone();
-    match fork.expect_char(c) {
-        Ok(_) => {
-            let tt = iter.next().cloned();
-            *iter = fork;
-            tt
+        Ok(tt::Subtree {
+            delimiter: tt::Delimiter {
+                open: punct.span,
+                close: ident.span,
+                kind: tt::DelimiterKind::Invisible,
+            },
+            token_trees: Box::new([
+                tt::Leaf::Punct(*punct).into(),
+                tt::Leaf::Ident(ident.clone()).into(),
+            ]),
+        }
+        .into())
+    }
+
+    fn eat_char(&mut self, c: char) -> Option<tt::TokenTree<Span>> {
+        let mut fork = self.clone();
+        match fork.expect_char(c) {
+            Ok(_) => {
+                let tt = self.next().cloned();
+                *self = fork;
+                tt
+            }
+            Err(_) => None,
         }
-        Err(_) => None,
     }
 }
diff --git a/crates/mbe/src/expander/transcriber.rs b/crates/mbe/src/expander/transcriber.rs
index c09cbd1d07..0f689a2692 100644
--- a/crates/mbe/src/expander/transcriber.rs
+++ b/crates/mbe/src/expander/transcriber.rs
@@ -195,7 +195,7 @@ fn expand_subtree(
                 .into(),
             ),
             Op::Punct(puncts) => {
-                for punct in puncts.as_slice() {
+                for punct in puncts {
                     arena.push(
                         tt::Leaf::from({
                             let mut it = *punct;
@@ -222,7 +222,7 @@ fn expand_subtree(
             }
             Op::Repeat { tokens: subtree, kind, separator } => {
                 let ExpandResult { value: fragment, err: e } =
-                    expand_repeat(ctx, subtree, *kind, separator.as_deref(), arena, marker);
+                    expand_repeat(ctx, subtree, *kind, separator, arena, marker);
                 err = err.or(e);
                 push_fragment(ctx, arena, fragment)
             }
@@ -383,7 +383,7 @@ fn expand_repeat(
     ctx: &mut ExpandCtx<'_>,
     template: &MetaTemplate,
     kind: RepeatKind,
-    separator: Option<&Separator>,
+    separator: &Option<Separator>,
     arena: &mut Vec<tt::TokenTree<Span>>,
     marker: impl Fn(&mut Span) + Copy,
 ) -> ExpandResult<Fragment> {
diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs
index 5f0598dfe0..ed3200964d 100644
--- a/crates/mbe/src/lib.rs
+++ b/crates/mbe/src/lib.rs
@@ -12,17 +12,20 @@ mod expander;
 mod parser;
 mod syntax_bridge;
 mod to_parser_input;
+mod tt_iter;
 
 #[cfg(test)]
 mod benchmark;
 
 use span::{Edition, Span, SyntaxContextId};
 use stdx::impl_from;
-use tt::iter::TtIter;
 
 use std::fmt;
 
-use crate::parser::{MetaTemplate, MetaVarKind, Op};
+use crate::{
+    parser::{MetaTemplate, MetaVarKind, Op},
+    tt_iter::TtIter,
+};
 
 // FIXME: we probably should re-think  `token_tree_to_syntax_node` interfaces
 pub use ::parser::TopEntryPoint;
@@ -244,10 +247,6 @@ impl DeclarativeMacro {
         self.err.as_deref()
     }
 
-    pub fn num_rules(&self) -> usize {
-        self.rules.len()
-    }
-
     pub fn expand(
         &self,
         tt: &tt::Subtree<Span>,
@@ -362,60 +361,3 @@ impl<T: Default, E> From<Result<T, E>> for ValueResult<T, E> {
         result.map_or_else(Self::only_err, Self::ok)
     }
 }
-
-fn expect_fragment<S: Copy + fmt::Debug>(
-    tt_iter: &mut TtIter<'_, S>,
-    entry_point: ::parser::PrefixEntryPoint,
-    edition: ::parser::Edition,
-) -> ExpandResult<Option<tt::TokenTree<S>>> {
-    use ::parser;
-    let buffer = tt::buffer::TokenBuffer::from_tokens(tt_iter.as_slice());
-    let parser_input = to_parser_input::to_parser_input(&buffer);
-    let tree_traversal = entry_point.parse(&parser_input, edition);
-    let mut cursor = buffer.begin();
-    let mut error = false;
-    for step in tree_traversal.iter() {
-        match step {
-            parser::Step::Token { kind, mut n_input_tokens } => {
-                if kind == ::parser::SyntaxKind::LIFETIME_IDENT {
-                    n_input_tokens = 2;
-                }
-                for _ in 0..n_input_tokens {
-                    cursor = cursor.bump_subtree();
-                }
-            }
-            parser::Step::FloatSplit { .. } => {
-                // FIXME: We need to split the tree properly here, but mutating the token trees
-                // in the buffer is somewhat tricky to pull off.
-                cursor = cursor.bump_subtree();
-            }
-            parser::Step::Enter { .. } | parser::Step::Exit => (),
-            parser::Step::Error { .. } => error = true,
-        }
-    }
-
-    let err = if error || !cursor.is_root() {
-        Some(ExpandError::binding_error(format!("expected {entry_point:?}")))
-    } else {
-        None
-    };
-
-    let mut curr = buffer.begin();
-    let mut res = vec![];
-
-    while curr != cursor {
-        let Some(token) = curr.token_tree() else { break };
-        res.push(token.cloned());
-        curr = curr.bump();
-    }
-
-    *tt_iter = TtIter::new_iter(tt_iter.as_slice()[res.len()..].iter());
-    let res = match &*res {
-        [] | [_] => res.pop(),
-        [first, ..] => Some(tt::TokenTree::Subtree(tt::Subtree {
-            delimiter: Delimiter::invisible_spanned(first.first_span()),
-            token_trees: res.into_boxed_slice(),
-        })),
-    };
-    ExpandResult { value: res, err }
-}
diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs
index 5c499c06b1..bbe00f0afc 100644
--- a/crates/mbe/src/parser.rs
+++ b/crates/mbe/src/parser.rs
@@ -1,14 +1,11 @@
 //! Parser recognizes special macro syntax, `$var` and `$(repeat)*`, in token
 //! trees.
 
-use std::sync::Arc;
-
-use arrayvec::ArrayVec;
+use smallvec::{smallvec, SmallVec};
 use span::{Edition, Span, SyntaxContextId};
 use syntax::SmolStr;
-use tt::iter::TtIter;
 
-use crate::ParseError;
+use crate::{tt_iter::TtIter, ParseError};
 
 /// Consider
 ///
@@ -89,14 +86,14 @@ pub(crate) enum Op {
     Repeat {
         tokens: MetaTemplate,
         kind: RepeatKind,
-        separator: Option<Arc<Separator>>,
+        separator: Option<Separator>,
     },
     Subtree {
         tokens: MetaTemplate,
         delimiter: tt::Delimiter<Span>,
     },
     Literal(tt::Literal<Span>),
-    Punct(Box<ArrayVec<tt::Punct<Span>, 3>>),
+    Punct(SmallVec<[tt::Punct<Span>; 3]>),
     Ident(tt::Ident<Span>),
 }
 
@@ -129,7 +126,7 @@ pub(crate) enum MetaVarKind {
 pub(crate) enum Separator {
     Literal(tt::Literal<Span>),
     Ident(tt::Ident<Span>),
-    Puncts(ArrayVec<tt::Punct<Span>, 3>),
+    Puncts(SmallVec<[tt::Punct<Span>; 3]>),
 }
 
 // Note that when we compare a Separator, we just care about its textual value.
@@ -168,13 +165,7 @@ fn next_op(
             src.next().expect("first token already peeked");
             // Note that the '$' itself is a valid token inside macro_rules.
             let second = match src.next() {
-                None => {
-                    return Ok(Op::Punct({
-                        let mut res = ArrayVec::new();
-                        res.push(*p);
-                        Box::new(res)
-                    }))
-                }
+                None => return Ok(Op::Punct(smallvec![*p])),
                 Some(it) => it,
             };
             match second {
@@ -182,7 +173,7 @@ fn next_op(
                     tt::DelimiterKind::Parenthesis => {
                         let (separator, kind) = parse_repeat(src)?;
                         let tokens = MetaTemplate::parse(edition, subtree, mode, new_meta_vars)?;
-                        Op::Repeat { tokens, separator: separator.map(Arc::new), kind }
+                        Op::Repeat { tokens, separator, kind }
                     }
                     tt::DelimiterKind::Brace => match mode {
                         Mode::Template => {
@@ -225,11 +216,7 @@ fn next_op(
                                 "`$$` is not allowed on the pattern side",
                             ))
                         }
-                        Mode::Template => Op::Punct({
-                            let mut res = ArrayVec::new();
-                            res.push(*punct);
-                            Box::new(res)
-                        }),
+                        Mode::Template => Op::Punct(smallvec![*punct]),
                     },
                     tt::Leaf::Punct(_) | tt::Leaf::Literal(_) => {
                         return Err(ParseError::expected("expected ident"))
@@ -251,7 +238,7 @@ fn next_op(
         tt::TokenTree::Leaf(tt::Leaf::Punct(_)) => {
             // There's at least one punct so this shouldn't fail.
             let puncts = src.expect_glued_punct().unwrap();
-            Op::Punct(Box::new(puncts))
+            Op::Punct(puncts)
         }
 
         tt::TokenTree::Subtree(subtree) => {
@@ -303,7 +290,7 @@ fn is_boolean_literal(lit: &tt::Literal<Span>) -> bool {
 }
 
 fn parse_repeat(src: &mut TtIter<'_, Span>) -> Result<(Option<Separator>, RepeatKind), ParseError> {
-    let mut separator = Separator::Puncts(ArrayVec::new());
+    let mut separator = Separator::Puncts(SmallVec::new());
     for tt in src {
         let tt = match tt {
             tt::TokenTree::Leaf(leaf) => leaf,
@@ -325,7 +312,7 @@ fn parse_repeat(src: &mut TtIter<'_, Span>) -> Result<(Option<Separator>, Repeat
                     '+' => RepeatKind::OneOrMore,
                     '?' => RepeatKind::ZeroOrOne,
                     _ => match &mut separator {
-                        Separator::Puncts(puncts) if puncts.len() < 3 => {
+                        Separator::Puncts(puncts) if puncts.len() != 3 => {
                             puncts.push(*punct);
                             continue;
                         }
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs
index 73a04f00d9..c8ff8c35e9 100644
--- a/crates/mbe/src/syntax_bridge.rs
+++ b/crates/mbe/src/syntax_bridge.rs
@@ -11,12 +11,9 @@ use syntax::{
     SyntaxKind::*,
     SyntaxNode, SyntaxToken, SyntaxTreeBuilder, TextRange, TextSize, WalkEvent, T,
 };
-use tt::{
-    buffer::{Cursor, TokenBuffer},
-    iter::TtIter,
-};
+use tt::buffer::{Cursor, TokenBuffer};
 
-use crate::to_parser_input::to_parser_input;
+use crate::{to_parser_input::to_parser_input, tt_iter::TtIter};
 
 #[cfg(test)]
 mod tests;
@@ -216,7 +213,7 @@ where
     let mut res = Vec::new();
 
     while iter.peek_n(0).is_some() {
-        let expanded = crate::expect_fragment(&mut iter, parser::PrefixEntryPoint::Expr, edition);
+        let expanded = iter.expect_fragment(parser::PrefixEntryPoint::Expr, edition);
 
         res.push(match expanded.value {
             None => break,
diff --git a/crates/mbe/src/tt_iter.rs b/crates/mbe/src/tt_iter.rs
new file mode 100644
index 0000000000..9c7d7af7b1
--- /dev/null
+++ b/crates/mbe/src/tt_iter.rs
@@ -0,0 +1,208 @@
+//! A "Parser" structure for token trees. We use this when parsing a declarative
+//! macro definition into a list of patterns and templates.
+
+use core::fmt;
+
+use smallvec::{smallvec, SmallVec};
+use syntax::SyntaxKind;
+
+use crate::{to_parser_input::to_parser_input, ExpandError, ExpandResult};
+
+#[derive(Debug, Clone)]
+pub(crate) struct TtIter<'a, S> {
+    pub(crate) inner: std::slice::Iter<'a, tt::TokenTree<S>>,
+}
+
+impl<'a, S: Copy> TtIter<'a, S> {
+    pub(crate) fn new(subtree: &'a tt::Subtree<S>) -> TtIter<'a, S> {
+        TtIter { inner: subtree.token_trees.iter() }
+    }
+
+    pub(crate) fn expect_char(&mut self, char: char) -> Result<(), ()> {
+        match self.next() {
+            Some(&tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: c, .. }))) if c == char => {
+                Ok(())
+            }
+            _ => Err(()),
+        }
+    }
+
+    pub(crate) fn expect_any_char(&mut self, chars: &[char]) -> Result<(), ()> {
+        match self.next() {
+            Some(tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: c, .. })))
+                if chars.contains(c) =>
+            {
+                Ok(())
+            }
+            _ => Err(()),
+        }
+    }
+
+    pub(crate) fn expect_subtree(&mut self) -> Result<&'a tt::Subtree<S>, ()> {
+        match self.next() {
+            Some(tt::TokenTree::Subtree(it)) => Ok(it),
+            _ => Err(()),
+        }
+    }
+
+    pub(crate) fn expect_leaf(&mut self) -> Result<&'a tt::Leaf<S>, ()> {
+        match self.next() {
+            Some(tt::TokenTree::Leaf(it)) => Ok(it),
+            _ => Err(()),
+        }
+    }
+
+    pub(crate) fn expect_dollar(&mut self) -> Result<(), ()> {
+        match self.expect_leaf()? {
+            tt::Leaf::Punct(tt::Punct { char: '$', .. }) => Ok(()),
+            _ => Err(()),
+        }
+    }
+
+    pub(crate) fn expect_ident(&mut self) -> Result<&'a tt::Ident<S>, ()> {
+        match self.expect_leaf()? {
+            tt::Leaf::Ident(it) if it.text != "_" => Ok(it),
+            _ => Err(()),
+        }
+    }
+
+    pub(crate) fn expect_ident_or_underscore(&mut self) -> Result<&'a tt::Ident<S>, ()> {
+        match self.expect_leaf()? {
+            tt::Leaf::Ident(it) => Ok(it),
+            _ => Err(()),
+        }
+    }
+
+    pub(crate) fn expect_literal(&mut self) -> Result<&'a tt::Leaf<S>, ()> {
+        let it = self.expect_leaf()?;
+        match it {
+            tt::Leaf::Literal(_) => Ok(it),
+            tt::Leaf::Ident(ident) if ident.text == "true" || ident.text == "false" => Ok(it),
+            _ => Err(()),
+        }
+    }
+
+    pub(crate) fn expect_single_punct(&mut self) -> Result<&'a tt::Punct<S>, ()> {
+        match self.expect_leaf()? {
+            tt::Leaf::Punct(it) => Ok(it),
+            _ => Err(()),
+        }
+    }
+
+    /// Returns consecutive `Punct`s that can be glued together.
+    ///
+    /// This method currently may return a single quotation, which is part of lifetime ident and
+    /// conceptually not a punct in the context of mbe. Callers should handle this.
+    pub(crate) fn expect_glued_punct(&mut self) -> Result<SmallVec<[tt::Punct<S>; 3]>, ()> {
+        let tt::TokenTree::Leaf(tt::Leaf::Punct(first)) = self.next().ok_or(())?.clone() else {
+            return Err(());
+        };
+
+        if first.spacing == tt::Spacing::Alone {
+            return Ok(smallvec![first]);
+        }
+
+        let (second, third) = match (self.peek_n(0), self.peek_n(1)) {
+            (
+                Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p2))),
+                Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p3))),
+            ) if p2.spacing == tt::Spacing::Joint => (p2, Some(p3)),
+            (Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p2))), _) => (p2, None),
+            _ => return Ok(smallvec![first]),
+        };
+
+        match (first.char, second.char, third.map(|it| it.char)) {
+            ('.', '.', Some('.' | '=')) | ('<', '<', Some('=')) | ('>', '>', Some('=')) => {
+                let _ = self.next().unwrap();
+                let _ = self.next().unwrap();
+                Ok(smallvec![first, *second, *third.unwrap()])
+            }
+            ('-' | '!' | '*' | '/' | '&' | '%' | '^' | '+' | '<' | '=' | '>' | '|', '=', _)
+            | ('-' | '=' | '>', '>', _)
+            | ('<', '-', _)
+            | (':', ':', _)
+            | ('.', '.', _)
+            | ('&', '&', _)
+            | ('<', '<', _)
+            | ('|', '|', _) => {
+                let _ = self.next().unwrap();
+                Ok(smallvec![first, *second])
+            }
+            _ => Ok(smallvec![first]),
+        }
+    }
+    pub(crate) fn peek_n(&self, n: usize) -> Option<&'a tt::TokenTree<S>> {
+        self.inner.as_slice().get(n)
+    }
+}
+
+impl<'a, S: Copy + fmt::Debug> TtIter<'a, S> {
+    pub(crate) fn expect_fragment(
+        &mut self,
+        entry_point: parser::PrefixEntryPoint,
+        edition: parser::Edition,
+    ) -> ExpandResult<Option<tt::TokenTree<S>>> {
+        let buffer = tt::buffer::TokenBuffer::from_tokens(self.inner.as_slice());
+        let parser_input = to_parser_input(&buffer);
+        let tree_traversal = entry_point.parse(&parser_input, edition);
+        let mut cursor = buffer.begin();
+        let mut error = false;
+        for step in tree_traversal.iter() {
+            match step {
+                parser::Step::Token { kind, mut n_input_tokens } => {
+                    if kind == SyntaxKind::LIFETIME_IDENT {
+                        n_input_tokens = 2;
+                    }
+                    for _ in 0..n_input_tokens {
+                        cursor = cursor.bump_subtree();
+                    }
+                }
+                parser::Step::FloatSplit { .. } => {
+                    // FIXME: We need to split the tree properly here, but mutating the token trees
+                    // in the buffer is somewhat tricky to pull off.
+                    cursor = cursor.bump_subtree();
+                }
+                parser::Step::Enter { .. } | parser::Step::Exit => (),
+                parser::Step::Error { .. } => error = true,
+            }
+        }
+
+        let err = if error || !cursor.is_root() {
+            Some(ExpandError::binding_error(format!("expected {entry_point:?}")))
+        } else {
+            None
+        };
+
+        let mut curr = buffer.begin();
+        let mut res = vec![];
+
+        while curr != cursor {
+            let Some(token) = curr.token_tree() else { break };
+            res.push(token.cloned());
+            curr = curr.bump();
+        }
+
+        self.inner = self.inner.as_slice()[res.len()..].iter();
+        let res = match &*res {
+            [] | [_] => res.pop(),
+            [first, ..] => Some(tt::TokenTree::Subtree(tt::Subtree {
+                delimiter: tt::Delimiter::invisible_spanned(first.first_span()),
+                token_trees: res.into_boxed_slice(),
+            })),
+        };
+        ExpandResult { value: res, err }
+    }
+}
+
+impl<'a, S> Iterator for TtIter<'a, S> {
+    type Item = &'a tt::TokenTree<S>;
+    fn next(&mut self) -> Option<Self::Item> {
+        self.inner.next()
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.inner.size_hint()
+    }
+}
+
+impl<S> std::iter::ExactSizeIterator for TtIter<'_, S> {}
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index f719a47248..e8504979be 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -341,8 +341,8 @@ config_data! {
         assist_emitMustUse: bool               = false,
         /// Placeholder expression to use for missing expressions in assists.
         assist_expressionFillDefault: ExprFillDefaultDef              = ExprFillDefaultDef::Todo,
-        /// Term search fuel in "units of work" for assists (Defaults to 1800).
-        assist_termSearch_fuel: usize = 1800,
+        /// Term search fuel in "units of work" for assists (Defaults to 400).
+        assist_termSearch_fuel: usize = 400,
 
         /// Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file.
         imports_granularity_enforce: bool              = false,
@@ -426,8 +426,8 @@ config_data! {
         }"#).unwrap(),
         /// Whether to enable term search based snippets like `Some(foo.bar().baz())`.
         completion_termSearch_enable: bool = false,
-        /// Term search fuel in "units of work" for autocompletion (Defaults to 1000).
-        completion_termSearch_fuel: usize = 1000,
+        /// Term search fuel in "units of work" for autocompletion (Defaults to 200).
+        completion_termSearch_fuel: usize = 200,
 
         /// Controls file watching implementation.
         files_watcher: FilesWatcherDef = FilesWatcherDef::Client,
@@ -844,9 +844,6 @@ impl Config {
             config.source_root_parent_map = source_root_map;
         }
 
-        // IMPORTANT : This holds as long as ` completion_snippets_custom` is declared `client`.
-        config.snippets.clear();
-
         let snips = self.completion_snippets_custom().to_owned();
 
         for (name, def) in snips.iter() {
diff --git a/crates/syntax/src/ast/prec.rs b/crates/syntax/src/ast/prec.rs
index 28089ffb37..9131cd2f17 100644
--- a/crates/syntax/src/ast/prec.rs
+++ b/crates/syntax/src/ast/prec.rs
@@ -27,14 +27,6 @@ impl Expr {
     }
 
     fn needs_parens_in_expr(&self, parent: &Expr) -> bool {
-        // Parentheses are necessary when calling a function-like pointer that is a member of a struct or union
-        // (e.g. `(a.f)()`).
-        let is_parent_call_expr = matches!(parent, ast::Expr::CallExpr(_));
-        let is_field_expr = matches!(self, ast::Expr::FieldExpr(_));
-        if is_parent_call_expr && is_field_expr {
-            return true;
-        }
-
         // Special-case block weirdness
         if parent.child_is_followed_by_a_block() {
             use Expr::*;
diff --git a/crates/tt/Cargo.toml b/crates/tt/Cargo.toml
index 1311e2ddf8..c96f088cdc 100644
--- a/crates/tt/Cargo.toml
+++ b/crates/tt/Cargo.toml
@@ -12,7 +12,6 @@ rust-version.workspace = true
 doctest = false
 
 [dependencies]
-arrayvec.workspace = true
 smol_str.workspace = true
 text-size.workspace = true
 
diff --git a/crates/tt/src/iter.rs b/crates/tt/src/iter.rs
deleted file mode 100644
index 175259a3e4..0000000000
--- a/crates/tt/src/iter.rs
+++ /dev/null
@@ -1,161 +0,0 @@
-//! A "Parser" structure for token trees. We use this when parsing a declarative
-//! macro definition into a list of patterns and templates.
-
-use arrayvec::ArrayVec;
-
-use crate::{Ident, Leaf, Punct, Spacing, Subtree, TokenTree};
-
-#[derive(Debug, Clone)]
-pub struct TtIter<'a, S> {
-    inner: std::slice::Iter<'a, TokenTree<S>>,
-}
-
-impl<'a, S: Copy> TtIter<'a, S> {
-    pub fn new(subtree: &'a Subtree<S>) -> TtIter<'a, S> {
-        TtIter { inner: subtree.token_trees.iter() }
-    }
-
-    pub fn new_iter(iter: std::slice::Iter<'a, TokenTree<S>>) -> TtIter<'a, S> {
-        TtIter { inner: iter }
-    }
-
-    pub fn expect_char(&mut self, char: char) -> Result<(), ()> {
-        match self.next() {
-            Some(&TokenTree::Leaf(Leaf::Punct(Punct { char: c, .. }))) if c == char => Ok(()),
-            _ => Err(()),
-        }
-    }
-
-    pub fn expect_any_char(&mut self, chars: &[char]) -> Result<(), ()> {
-        match self.next() {
-            Some(TokenTree::Leaf(Leaf::Punct(Punct { char: c, .. }))) if chars.contains(c) => {
-                Ok(())
-            }
-            _ => Err(()),
-        }
-    }
-
-    pub fn expect_subtree(&mut self) -> Result<&'a Subtree<S>, ()> {
-        match self.next() {
-            Some(TokenTree::Subtree(it)) => Ok(it),
-            _ => Err(()),
-        }
-    }
-
-    pub fn expect_leaf(&mut self) -> Result<&'a Leaf<S>, ()> {
-        match self.next() {
-            Some(TokenTree::Leaf(it)) => Ok(it),
-            _ => Err(()),
-        }
-    }
-
-    pub fn expect_dollar(&mut self) -> Result<(), ()> {
-        match self.expect_leaf()? {
-            Leaf::Punct(Punct { char: '$', .. }) => Ok(()),
-            _ => Err(()),
-        }
-    }
-
-    pub fn expect_ident(&mut self) -> Result<&'a Ident<S>, ()> {
-        match self.expect_leaf()? {
-            Leaf::Ident(it) if it.text != "_" => Ok(it),
-            _ => Err(()),
-        }
-    }
-
-    pub fn expect_ident_or_underscore(&mut self) -> Result<&'a Ident<S>, ()> {
-        match self.expect_leaf()? {
-            Leaf::Ident(it) => Ok(it),
-            _ => Err(()),
-        }
-    }
-
-    pub fn expect_literal(&mut self) -> Result<&'a Leaf<S>, ()> {
-        let it = self.expect_leaf()?;
-        match it {
-            Leaf::Literal(_) => Ok(it),
-            Leaf::Ident(ident) if ident.text == "true" || ident.text == "false" => Ok(it),
-            _ => Err(()),
-        }
-    }
-
-    pub fn expect_single_punct(&mut self) -> Result<&'a Punct<S>, ()> {
-        match self.expect_leaf()? {
-            Leaf::Punct(it) => Ok(it),
-            _ => Err(()),
-        }
-    }
-
-    /// Returns consecutive `Punct`s that can be glued together.
-    ///
-    /// This method currently may return a single quotation, which is part of lifetime ident and
-    /// conceptually not a punct in the context of mbe. Callers should handle this.
-    pub fn expect_glued_punct(&mut self) -> Result<ArrayVec<Punct<S>, 3>, ()> {
-        let TokenTree::Leaf(Leaf::Punct(first)) = self.next().ok_or(())?.clone() else {
-            return Err(());
-        };
-
-        let mut res = ArrayVec::new();
-        if first.spacing == Spacing::Alone {
-            res.push(first);
-            return Ok(res);
-        }
-
-        let (second, third) = match (self.peek_n(0), self.peek_n(1)) {
-            (Some(TokenTree::Leaf(Leaf::Punct(p2))), Some(TokenTree::Leaf(Leaf::Punct(p3))))
-                if p2.spacing == Spacing::Joint =>
-            {
-                (p2, Some(p3))
-            }
-            (Some(TokenTree::Leaf(Leaf::Punct(p2))), _) => (p2, None),
-            _ => {
-                res.push(first);
-                return Ok(res);
-            }
-        };
-
-        match (first.char, second.char, third.map(|it| it.char)) {
-            ('.', '.', Some('.' | '=')) | ('<', '<', Some('=')) | ('>', '>', Some('=')) => {
-                let _ = self.next().unwrap();
-                let _ = self.next().unwrap();
-                res.push(first);
-                res.push(*second);
-                res.push(*third.unwrap());
-            }
-            ('-' | '!' | '*' | '/' | '&' | '%' | '^' | '+' | '<' | '=' | '>' | '|', '=', _)
-            | ('-' | '=' | '>', '>', _)
-            | ('<', '-', _)
-            | (':', ':', _)
-            | ('.', '.', _)
-            | ('&', '&', _)
-            | ('<', '<', _)
-            | ('|', '|', _) => {
-                let _ = self.next().unwrap();
-                res.push(first);
-                res.push(*second);
-            }
-            _ => res.push(first),
-        }
-        Ok(res)
-    }
-    pub fn peek_n(&self, n: usize) -> Option<&'a TokenTree<S>> {
-        self.inner.as_slice().get(n)
-    }
-
-    pub fn as_slice(&self) -> &'a [TokenTree<S>] {
-        self.inner.as_slice()
-    }
-}
-
-impl<'a, S> Iterator for TtIter<'a, S> {
-    type Item = &'a TokenTree<S>;
-    fn next(&mut self) -> Option<Self::Item> {
-        self.inner.next()
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.inner.size_hint()
-    }
-}
-
-impl<S> std::iter::ExactSizeIterator for TtIter<'_, S> {}
diff --git a/crates/tt/src/lib.rs b/crates/tt/src/lib.rs
index b2a21b1913..e9de3f97b0 100644
--- a/crates/tt/src/lib.rs
+++ b/crates/tt/src/lib.rs
@@ -4,9 +4,6 @@
 
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
-pub mod buffer;
-pub mod iter;
-
 use std::fmt;
 
 use stdx::impl_from;
@@ -368,6 +365,8 @@ impl<S> Subtree<S> {
     }
 }
 
+pub mod buffer;
+
 pub fn pretty<S>(tkns: &[TokenTree<S>]) -> String {
     fn tokentree_to_text<S>(tkn: &TokenTree<S>) -> String {
         match tkn {
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index 81f30dc56e..14aae91741 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -9,10 +9,10 @@ for enum variants.
 --
 Placeholder expression to use for missing expressions in assists.
 --
-[[rust-analyzer.assist.termSearch.fuel]]rust-analyzer.assist.termSearch.fuel (default: `1800`)::
+[[rust-analyzer.assist.termSearch.fuel]]rust-analyzer.assist.termSearch.fuel (default: `400`)::
 +
 --
-Term search fuel in "units of work" for assists (Defaults to 1800).
+Term search fuel in "units of work" for assists (Defaults to 400).
 --
 [[rust-analyzer.cachePriming.enable]]rust-analyzer.cachePriming.enable (default: `true`)::
 +
@@ -378,10 +378,10 @@ Custom completion snippets.
 --
 Whether to enable term search based snippets like `Some(foo.bar().baz())`.
 --
-[[rust-analyzer.completion.termSearch.fuel]]rust-analyzer.completion.termSearch.fuel (default: `1000`)::
+[[rust-analyzer.completion.termSearch.fuel]]rust-analyzer.completion.termSearch.fuel (default: `200`)::
 +
 --
-Term search fuel in "units of work" for autocompletion (Defaults to 1000).
+Term search fuel in "units of work" for autocompletion (Defaults to 200).
 --
 [[rust-analyzer.diagnostics.disabled]]rust-analyzer.diagnostics.disabled (default: `[]`)::
 +
diff --git a/editors/code/package.json b/editors/code/package.json
index 0da5b920a7..db2a989106 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -592,8 +592,8 @@
                 "title": "assist",
                 "properties": {
                     "rust-analyzer.assist.termSearch.fuel": {
-                        "markdownDescription": "Term search fuel in \"units of work\" for assists (Defaults to 1800).",
-                        "default": 1800,
+                        "markdownDescription": "Term search fuel in \"units of work\" for assists (Defaults to 400).",
+                        "default": 400,
                         "type": "integer",
                         "minimum": 0
                     }
@@ -1224,8 +1224,8 @@
                 "title": "completion",
                 "properties": {
                     "rust-analyzer.completion.termSearch.fuel": {
-                        "markdownDescription": "Term search fuel in \"units of work\" for autocompletion (Defaults to 1000).",
-                        "default": 1000,
+                        "markdownDescription": "Term search fuel in \"units of work\" for autocompletion (Defaults to 200).",
+                        "default": 200,
                         "type": "integer",
                         "minimum": 0
                     }
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts
index 542233e7b9..1c2a34b484 100644
--- a/editors/code/src/client.ts
+++ b/editors/code/src/client.ts
@@ -76,8 +76,7 @@ export async function createClient(
                         // value === "unlinked-file" &&
                         value === "temporary-disabled" &&
                         !unlinkedFiles.includes(uri) &&
-                        (diag.message === "file not included in crate hierarchy" ||
-                            diag.message.startsWith("This file is not included in any crates"))
+                        diag.message !== "file not included in module tree"
                     ) {
                         const config = vscode.workspace.getConfiguration("rust-analyzer");
                         if (config.get("showUnlinkedFileNotification")) {
diff --git a/xtask/src/publish.rs b/xtask/src/publish.rs
index f5d765d7c9..7faae9b20c 100644
--- a/xtask/src/publish.rs
+++ b/xtask/src/publish.rs
@@ -9,15 +9,6 @@ impl flags::PublishReleaseNotes {
     pub(crate) fn run(self, sh: &Shell) -> anyhow::Result<()> {
         let asciidoc = sh.read_file(&self.changelog)?;
         let mut markdown = notes::convert_asciidoc_to_markdown(std::io::Cursor::new(&asciidoc))?;
-        if !markdown.starts_with("# Changelog") {
-            bail!("changelog Markdown should start with `# Changelog`");
-        }
-        const NEWLINES: &str = "\n\n";
-        let Some(idx) = markdown.find(NEWLINES) else {
-            bail!("missing newlines after changelog title");
-        };
-        markdown.replace_range(0..idx + NEWLINES.len(), "");
-
         let file_name = check_file_name(self.changelog)?;
         let tag_name = &file_name[0..10];
         let original_changelog_url = create_original_changelog_url(&file_name);


Test patch:
diff --git a/crates/ide-completion/src/tests/pattern.rs b/crates/ide-completion/src/tests/pattern.rs
index 6a0b67e291..8720cb555a 100644
--- a/crates/ide-completion/src/tests/pattern.rs
+++ b/crates/ide-completion/src/tests/pattern.rs
@@ -146,7 +146,7 @@ enum SingleVariantEnum {
 }
 use SingleVariantEnum::Variant;
 fn foo() {
-   for a$0
+   let a$0
 }
 "#,
         expect![[r#"