Auto merge of #147784 - nxsaken:div_exact_return_option, r=dtolnay

Return `Option` from `exact_div` and inherit overflow checks

According to https://github.com/rust-lang/rust/issues/139911#issuecomment-3404056127, `exact_div` should return `Option::None` if `self % rhs != 0`, panic if `rhs == 0`, and handle overflow conditionally (panic in debug, wrap in release).

rust-lang/rust#147771 should rename `exact_div` to `div_exact`.
diff --git a/Cargo.lock b/Cargo.lock
index 267b516..535833d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -235,6 +235,7 @@
 version = "0.0.0"
 dependencies = [
  "arbitrary",
+ "cfg",
  "expect-test",
  "intern",
  "oorandom",
@@ -258,28 +259,6 @@
 checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
 
 [[package]]
-name = "chalk-derive"
-version = "0.104.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ea9b1e80910f66ae87c772247591432032ef3f6a67367ff17f8343db05beafa"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "synstructure",
-]
-
-[[package]]
-name = "chalk-ir"
-version = "0.104.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7047a516de16226cd17344d41a319d0ea1064bf9e60bd612ab341ab4a34bbfa8"
-dependencies = [
- "bitflags 2.9.4",
- "chalk-derive",
-]
-
-[[package]]
 name = "clap"
 version = "4.5.48"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -776,8 +755,6 @@
  "arrayvec",
  "base-db",
  "bitflags 2.9.4",
- "chalk-derive",
- "chalk-ir",
  "cov-mark",
  "either",
  "ena",
@@ -819,11 +796,11 @@
 
 [[package]]
 name = "home"
-version = "0.5.11"
+version = "0.5.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
+checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d"
 dependencies = [
- "windows-sys 0.59.0",
+ "windows-sys 0.61.0",
 ]
 
 [[package]]
@@ -929,6 +906,7 @@
  "ide-diagnostics",
  "ide-ssr",
  "itertools",
+ "macros",
  "nohash-hasher",
  "oorandom",
  "profile",
@@ -975,6 +953,7 @@
  "hir",
  "ide-db",
  "itertools",
+ "macros",
  "smallvec",
  "stdx",
  "syntax",
@@ -999,6 +978,7 @@
  "indexmap",
  "itertools",
  "line-index 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "macros",
  "memchr",
  "nohash-hasher",
  "parser",
@@ -1008,6 +988,7 @@
  "rustc-hash 2.1.1",
  "salsa",
  "salsa-macros",
+ "smallvec",
  "span",
  "stdx",
  "syntax",
@@ -1404,14 +1385,14 @@
 
 [[package]]
 name = "mio"
-version = "1.0.4"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
+checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873"
 dependencies = [
  "libc",
  "log",
  "wasi",
- "windows-sys 0.59.0",
+ "windows-sys 0.61.0",
 ]
 
 [[package]]
@@ -1467,11 +1448,11 @@
 
 [[package]]
 name = "nu-ansi-term"
-version = "0.50.1"
+version = "0.50.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399"
+checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
 dependencies = [
- "windows-sys 0.52.0",
+ "windows-sys 0.60.2",
 ]
 
 [[package]]
@@ -1578,6 +1559,7 @@
  "rustc-literal-escaper 0.0.4",
  "stdx",
  "tracing",
+ "winnow",
 ]
 
 [[package]]
@@ -1842,9 +1824,9 @@
 
 [[package]]
 name = "ra-ap-rustc_abi"
-version = "0.133.0"
+version = "0.137.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c063a7fef3c49d03837ee9a5d988aad83630c3460b03b32355c279d3fafa7d07"
+checksum = "a4ce5c9ea794353e02beae390c4674f74ffb23a2ad9de763469fdcef5c1026ef"
 dependencies = [
  "bitflags 2.9.4",
  "ra-ap-rustc_hashes",
@@ -1854,24 +1836,24 @@
 
 [[package]]
 name = "ra-ap-rustc_ast_ir"
-version = "0.133.0"
+version = "0.137.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a210dbd77e794b33ff17d2d15750dee44eeabd1330685d69a6bad272d515892a"
+checksum = "1696b77af9bbfe1fcc7a09c907561061c6ef4c8bd6d5f1675b927bc62d349103"
 
 [[package]]
 name = "ra-ap-rustc_hashes"
-version = "0.133.0"
+version = "0.137.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dea031ea45bb92cd346ed222b35c812e355f304183096ee91bb437b3813c6348"
+checksum = "c055d8b0d8a592d8cf9547495189f52c1ee5c691d28df1628253a816214e8521"
 dependencies = [
  "rustc-stable-hash",
 ]
 
 [[package]]
 name = "ra-ap-rustc_index"
-version = "0.133.0"
+version = "0.137.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db0114f842b20cba9beb2d9002ca31ae706b47f28ba2d6a49cbf9fd65fa72b9d"
+checksum = "a08a03e3d4a452144b68f48130eda3a2894d4d79e99ddb44bdb4e0ab8c384e10"
 dependencies = [
  "ra-ap-rustc_index_macros",
  "smallvec",
@@ -1879,9 +1861,9 @@
 
 [[package]]
 name = "ra-ap-rustc_index_macros"
-version = "0.133.0"
+version = "0.137.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc738a5bb06fb3893725fbeb3640ff1822bb2aae3f416c4a49f0a706ba89d1cc"
+checksum = "a1e0446b4d65a8ce19d8fd12826c4bf2365ffa4b8fe0ee94daf5968fe36e920c"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1890,9 +1872,9 @@
 
 [[package]]
 name = "ra-ap-rustc_lexer"
-version = "0.133.0"
+version = "0.137.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31c35b3d812cfc101d3f534640c13f24c0ec50ee2249685e4c20b2868609c9ee"
+checksum = "ac80365383a3c749f38af567fdcfaeff3fa6ea5df3846852abbce73e943921b9"
 dependencies = [
  "memchr",
  "unicode-properties",
@@ -1901,9 +1883,9 @@
 
 [[package]]
 name = "ra-ap-rustc_next_trait_solver"
-version = "0.133.0"
+version = "0.137.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7b0fa6fb8e0717ebd0836f8de4a6efc954fca1a8652980fd2584dbe448c7d95"
+checksum = "a39b419d2d6f7fdec7e0981b7fb7d5beb5dda7140064f1199704ec9dadbb6f73"
 dependencies = [
  "derive-where",
  "ra-ap-rustc_index",
@@ -1914,9 +1896,9 @@
 
 [[package]]
 name = "ra-ap-rustc_parse_format"
-version = "0.133.0"
+version = "0.137.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33d01bad23470cc749ef607476890aabcc8993ca3ef87d4241d0f6a08c6f9402"
+checksum = "b743b0c8f795842e41b1720bbc5af6e896129fb9acf04e9785774bfb0dc5947c"
 dependencies = [
  "ra-ap-rustc_lexer",
  "rustc-literal-escaper 0.0.5",
@@ -1924,9 +1906,9 @@
 
 [[package]]
 name = "ra-ap-rustc_pattern_analysis"
-version = "0.133.0"
+version = "0.137.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a181cf7943dc16e888046584d6172be95818811b25d695dbacbb4dd71973cc3"
+checksum = "cf944dce80137195528f89a576f70153c2060a6f8ca49c3fa9f55f9da14ab937"
 dependencies = [
  "ra-ap-rustc_index",
  "rustc-hash 2.1.1",
@@ -1937,9 +1919,9 @@
 
 [[package]]
 name = "ra-ap-rustc_type_ir"
-version = "0.133.0"
+version = "0.137.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87c99f33be18d9e50cefef5442822da1f0b416e9a17a483879a9704e08a6a6e6"
+checksum = "1bfe2722b20bc889a9d7711bd3a1f4f7b082940491241615aa643c17e0deffec"
 dependencies = [
  "arrayvec",
  "bitflags 2.9.4",
@@ -1957,9 +1939,9 @@
 
 [[package]]
 name = "ra-ap-rustc_type_ir_macros"
-version = "0.133.0"
+version = "0.137.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77b162d65e058abfc058e6b67ae68156cc282fbd78da148c1a7ec77b4230661e"
+checksum = "6fad1527df26aaa77367393fae86f42818b33e02b3737a19f3846d1c7671e7f9"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2993,24 +2975,6 @@
 
 [[package]]
 name = "windows-sys"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
-dependencies = [
- "windows-targets 0.52.6",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.59.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
-dependencies = [
- "windows-targets 0.52.6",
-]
-
-[[package]]
-name = "windows-sys"
 version = "0.60.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
diff --git a/Cargo.toml b/Cargo.toml
index f94fd37..ecb2686 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -37,8 +37,6 @@
 [patch.'crates-io']
 # rowan = { path = "../rowan" }
 
-# chalk-ir = { path = "../chalk/chalk-ir" }
-# chalk-derive = { path = "../chalk/chalk-derive" }
 # line-index = { path = "lib/line-index" }
 # la-arena = { path = "lib/la-arena" }
 # lsp-server = { path = "lib/lsp-server" }
@@ -88,14 +86,14 @@
 vfs = { path = "./crates/vfs", version = "0.0.0" }
 edition = { path = "./crates/edition", version = "0.0.0" }
 
-ra-ap-rustc_lexer = { version = "0.133", default-features = false }
-ra-ap-rustc_parse_format = { version = "0.133", default-features = false }
-ra-ap-rustc_index = { version = "0.133", default-features = false }
-ra-ap-rustc_abi = { version = "0.133", default-features = false }
-ra-ap-rustc_pattern_analysis = { version = "0.133", default-features = false }
-ra-ap-rustc_ast_ir = { version = "0.133", default-features = false }
-ra-ap-rustc_type_ir = { version = "0.133", default-features = false }
-ra-ap-rustc_next_trait_solver = { version = "0.133", default-features = false }
+ra-ap-rustc_lexer = { version = "0.137", default-features = false }
+ra-ap-rustc_parse_format = { version = "0.137", default-features = false }
+ra-ap-rustc_index = { version = "0.137", default-features = false }
+ra-ap-rustc_abi = { version = "0.137", default-features = false }
+ra-ap-rustc_pattern_analysis = { version = "0.137", default-features = false }
+ra-ap-rustc_ast_ir = { version = "0.137", default-features = false }
+ra-ap-rustc_type_ir = { version = "0.137", default-features = false }
+ra-ap-rustc_next_trait_solver = { version = "0.137", default-features = false }
 
 # local crates that aren't published to crates.io. These should not have versions.
 
@@ -110,8 +108,6 @@
 bitflags = "2.9.1"
 cargo_metadata = "0.21.0"
 camino = "1.1.10"
-chalk-ir = "0.104.0"
-chalk-derive = "0.104.0"
 crossbeam-channel = "0.5.15"
 dissimilar = "1.0.10"
 dot = "0.1.4"
diff --git a/crates/cfg/Cargo.toml b/crates/cfg/Cargo.toml
index af95f86..e17969b 100644
--- a/crates/cfg/Cargo.toml
+++ b/crates/cfg/Cargo.toml
@@ -29,5 +29,8 @@
 syntax-bridge.workspace = true
 syntax.workspace = true
 
+# tt is needed for testing
+cfg = { path = ".", default-features = false, features = ["tt"] }
+
 [lints]
 workspace = true
diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs
index 906106c..b1ec4c2 100644
--- a/crates/cfg/src/lib.rs
+++ b/crates/cfg/src/lib.rs
@@ -115,6 +115,13 @@
     pub fn shrink_to_fit(&mut self) {
         self.enabled.shrink_to_fit();
     }
+
+    pub fn append(&mut self, other: CfgOptions) {
+        // Do not call `insert_any_atom()`, as it'll check for `true` and `false`, but this is not
+        // needed since we already checked for that when constructing `other`. Furthermore, this
+        // will always err, as `other` inevitably contains `true` (just as we do).
+        self.enabled.extend(other.enabled);
+    }
 }
 
 impl Extend<CfgAtom> for CfgOptions {
diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml
index ec65633..378a0f0 100644
--- a/crates/hir-ty/Cargo.toml
+++ b/crates/hir-ty/Cargo.toml
@@ -24,8 +24,6 @@
 tracing.workspace = true
 rustc-hash.workspace = true
 scoped-tls = "1.0.1"
-chalk-ir.workspace = true
-chalk-derive.workspace = true
 la-arena.workspace = true
 triomphe.workspace = true
 typed-arena = "2.0.2"
diff --git a/crates/hir-ty/src/builder.rs b/crates/hir-ty/src/builder.rs
deleted file mode 100644
index 706bbe8..0000000
--- a/crates/hir-ty/src/builder.rs
+++ /dev/null
@@ -1,398 +0,0 @@
-//! `TyBuilder`, a helper for building instances of `Ty` and related types.
-
-use chalk_ir::{
-    AdtId, DebruijnIndex, Scalar,
-    cast::{Cast, CastTo, Caster},
-};
-use hir_def::{GenericDefId, GenericParamId, TraitId, TypeAliasId, builtin_type::BuiltinType};
-use smallvec::SmallVec;
-
-use crate::{
-    BoundVar, CallableSig, GenericArg, GenericArgData, Interner, ProjectionTy, Substitution,
-    TraitRef, Ty, TyDefId, TyExt, TyKind,
-    consteval::unknown_const_as_generic,
-    db::HirDatabase,
-    error_lifetime,
-    generics::generics,
-    infer::unify::InferenceTable,
-    next_solver::{
-        DbInterner, EarlyBinder,
-        mapping::{ChalkToNextSolver, NextSolverToChalk},
-    },
-    primitive, to_assoc_type_id, to_chalk_trait_id,
-};
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum ParamKind {
-    Type,
-    Lifetime,
-    Const(Ty),
-}
-
-/// This is a builder for `Ty` or anything that needs a `Substitution`.
-pub struct TyBuilder<D> {
-    /// The `data` field is used to keep track of what we're building (e.g. an
-    /// ADT, a `TraitRef`, ...).
-    data: D,
-    vec: SmallVec<[GenericArg; 2]>,
-    param_kinds: SmallVec<[ParamKind; 2]>,
-    parent_subst: Substitution,
-}
-
-impl<A> TyBuilder<A> {
-    fn with_data<B>(self, data: B) -> TyBuilder<B> {
-        TyBuilder {
-            data,
-            vec: self.vec,
-            param_kinds: self.param_kinds,
-            parent_subst: self.parent_subst,
-        }
-    }
-}
-
-impl<D> TyBuilder<D> {
-    fn new(
-        data: D,
-        param_kinds: SmallVec<[ParamKind; 2]>,
-        parent_subst: Option<Substitution>,
-    ) -> Self {
-        let parent_subst = parent_subst.unwrap_or_else(|| Substitution::empty(Interner));
-        Self { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds, parent_subst }
-    }
-
-    fn new_empty(data: D) -> Self {
-        TyBuilder::new(data, SmallVec::new(), None)
-    }
-
-    fn build_internal(self) -> (D, Substitution) {
-        assert_eq!(
-            self.vec.len(),
-            self.param_kinds.len(),
-            "{} args received, {} expected ({:?})",
-            self.vec.len(),
-            self.param_kinds.len(),
-            &self.param_kinds
-        );
-        for (a, e) in self.vec.iter().zip(self.param_kinds.iter()) {
-            self.assert_match_kind(a, e);
-        }
-        let subst = Substitution::from_iter(
-            Interner,
-            self.parent_subst.iter(Interner).cloned().chain(self.vec),
-        );
-        (self.data, subst)
-    }
-
-    pub fn build_into_subst(self) -> Substitution {
-        self.build_internal().1
-    }
-
-    pub fn push(mut self, arg: impl CastTo<GenericArg>) -> Self {
-        assert!(self.remaining() > 0);
-        let arg = arg.cast(Interner);
-        let expected_kind = &self.param_kinds[self.vec.len()];
-
-        let arg_kind = match arg.data(Interner) {
-            GenericArgData::Ty(_) => ParamKind::Type,
-            GenericArgData::Lifetime(_) => panic!("Got lifetime in TyBuilder::push"),
-            GenericArgData::Const(c) => {
-                let c = c.data(Interner);
-                ParamKind::Const(c.ty.clone())
-            }
-        };
-        assert_eq!(*expected_kind, arg_kind);
-
-        self.vec.push(arg);
-
-        self
-    }
-
-    pub fn remaining(&self) -> usize {
-        self.param_kinds.len() - self.vec.len()
-    }
-
-    pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self {
-        // self.fill is inlined to make borrow checker happy
-        let mut this = self;
-        let other = &this.param_kinds[this.vec.len()..];
-        let filler = (starting_from..).zip(other).map(|(idx, kind)| match kind {
-            ParamKind::Type => BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner),
-            ParamKind::Const(ty) => {
-                BoundVar::new(debruijn, idx).to_const(Interner, ty.clone()).cast(Interner)
-            }
-            ParamKind::Lifetime => {
-                BoundVar::new(debruijn, idx).to_lifetime(Interner).cast(Interner)
-            }
-        });
-        this.vec.extend(filler.take(this.remaining()).casted(Interner));
-        assert_eq!(this.remaining(), 0);
-        this
-    }
-
-    pub fn fill_with_unknown(self) -> Self {
-        let interner = DbInterner::conjure();
-        // self.fill is inlined to make borrow checker happy
-        let mut this = self;
-        let filler = this.param_kinds[this.vec.len()..].iter().map(|x| match x {
-            ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner),
-            ParamKind::Const(ty) => {
-                unknown_const_as_generic(ty.to_nextsolver(interner)).to_chalk(interner)
-            }
-            ParamKind::Lifetime => error_lifetime().cast(Interner),
-        });
-        this.vec.extend(filler.casted(Interner));
-        assert_eq!(this.remaining(), 0);
-        this
-    }
-
-    #[tracing::instrument(skip_all)]
-    pub(crate) fn fill_with_inference_vars(self, table: &mut InferenceTable<'_>) -> Self {
-        self.fill(|x| {
-            match x {
-                ParamKind::Type => crate::next_solver::GenericArg::Ty(table.next_ty_var()),
-                ParamKind::Const(_) => table.next_const_var().into(),
-                ParamKind::Lifetime => table.next_region_var().into(),
-            }
-            .to_chalk(table.interner())
-        })
-    }
-
-    pub fn fill(mut self, filler: impl FnMut(&ParamKind) -> GenericArg) -> Self {
-        self.vec.extend(self.param_kinds[self.vec.len()..].iter().map(filler));
-        assert_eq!(self.remaining(), 0);
-        self
-    }
-
-    fn assert_match_kind(&self, a: &chalk_ir::GenericArg<Interner>, e: &ParamKind) {
-        match (a.data(Interner), e) {
-            (GenericArgData::Ty(_), ParamKind::Type)
-            | (GenericArgData::Const(_), ParamKind::Const(_))
-            | (GenericArgData::Lifetime(_), ParamKind::Lifetime) => (),
-            _ => panic!("Mismatched kinds: {a:?}, {:?}, {:?}", self.vec, self.param_kinds),
-        }
-    }
-}
-
-impl TyBuilder<()> {
-    pub fn unit() -> Ty {
-        TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner)
-    }
-
-    // FIXME: rustc's ty is dependent on the adt type, maybe we need to do that as well
-    pub fn discr_ty() -> Ty {
-        TyKind::Scalar(chalk_ir::Scalar::Int(chalk_ir::IntTy::I128)).intern(Interner)
-    }
-
-    pub fn bool() -> Ty {
-        TyKind::Scalar(chalk_ir::Scalar::Bool).intern(Interner)
-    }
-
-    pub fn usize() -> Ty {
-        TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)).intern(Interner)
-    }
-
-    pub fn fn_ptr(sig: CallableSig) -> Ty {
-        TyKind::Function(sig.to_fn_ptr()).intern(Interner)
-    }
-
-    pub fn builtin(builtin: BuiltinType) -> Ty {
-        match builtin {
-            BuiltinType::Char => TyKind::Scalar(Scalar::Char).intern(Interner),
-            BuiltinType::Bool => TyKind::Scalar(Scalar::Bool).intern(Interner),
-            BuiltinType::Str => TyKind::Str.intern(Interner),
-            BuiltinType::Int(t) => {
-                TyKind::Scalar(Scalar::Int(primitive::int_ty_from_builtin(t))).intern(Interner)
-            }
-            BuiltinType::Uint(t) => {
-                TyKind::Scalar(Scalar::Uint(primitive::uint_ty_from_builtin(t))).intern(Interner)
-            }
-            BuiltinType::Float(t) => {
-                TyKind::Scalar(Scalar::Float(primitive::float_ty_from_builtin(t))).intern(Interner)
-            }
-        }
-    }
-
-    pub fn slice(argument: Ty) -> Ty {
-        TyKind::Slice(argument).intern(Interner)
-    }
-
-    pub fn placeholder_subst(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> Substitution {
-        let params = generics(db, def.into());
-        params.placeholder_subst(db)
-    }
-
-    pub fn unknown_subst(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> Substitution {
-        let interner = DbInterner::conjure();
-        let params = generics(db, def.into());
-        Substitution::from_iter(
-            Interner,
-            params.iter_id().map(|id| match id {
-                GenericParamId::TypeParamId(_) => TyKind::Error.intern(Interner).cast(Interner),
-                GenericParamId::ConstParamId(id) => {
-                    unknown_const_as_generic(db.const_param_ty_ns(id))
-                        .to_chalk(interner)
-                        .cast(Interner)
-                }
-                GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner),
-            }),
-        )
-    }
-
-    #[tracing::instrument(skip_all)]
-    pub fn subst_for_def(
-        db: &dyn HirDatabase,
-        def: impl Into<GenericDefId>,
-        parent_subst: Option<Substitution>,
-    ) -> TyBuilder<()> {
-        let generics = generics(db, def.into());
-        assert!(generics.parent_generics().is_some() == parent_subst.is_some());
-        let params = generics
-            .iter_self()
-            .map(|(id, _data)| match id {
-                GenericParamId::TypeParamId(_) => ParamKind::Type,
-                GenericParamId::ConstParamId(id) => ParamKind::Const(db.const_param_ty(id)),
-                GenericParamId::LifetimeParamId(_) => ParamKind::Lifetime,
-            })
-            .collect();
-        TyBuilder::new((), params, parent_subst)
-    }
-
-    pub fn build(self) -> Substitution {
-        let ((), subst) = self.build_internal();
-        subst
-    }
-}
-
-impl TyBuilder<hir_def::AdtId> {
-    pub fn adt(db: &dyn HirDatabase, def: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> {
-        TyBuilder::subst_for_def(db, def, None).with_data(def)
-    }
-
-    pub fn fill_with_defaults(
-        mut self,
-        db: &dyn HirDatabase,
-        mut fallback: impl FnMut() -> Ty,
-    ) -> Self {
-        let interner = DbInterner::conjure();
-        // Note that we're building ADT, so we never have parent generic parameters.
-        let defaults = db.generic_defaults(self.data.into());
-
-        if let Some(defaults) = defaults.get(self.vec.len()..) {
-            for default_ty in defaults {
-                // NOTE(skip_binders): we only check if the arg type is error type.
-                if let Some(x) = default_ty.skip_binders().ty(Interner)
-                    && x.is_unknown()
-                {
-                    self.vec.push(fallback().cast(Interner));
-                    continue;
-                }
-                // Each default can only depend on the previous parameters.
-                self.vec.push(default_ty.clone().substitute(Interner, &*self.vec).cast(Interner));
-            }
-        }
-
-        // The defaults may be missing if no param has default, so fill that.
-        let filler = self.param_kinds[self.vec.len()..].iter().map(|x| match x {
-            ParamKind::Type => fallback().cast(Interner),
-            ParamKind::Const(ty) => {
-                unknown_const_as_generic(ty.to_nextsolver(interner)).to_chalk(interner)
-            }
-            ParamKind::Lifetime => error_lifetime().cast(Interner),
-        });
-        self.vec.extend(filler.casted(Interner));
-
-        self
-    }
-
-    pub fn build(self) -> Ty {
-        let (adt, subst) = self.build_internal();
-        TyKind::Adt(AdtId(adt), subst).intern(Interner)
-    }
-}
-
-pub struct Tuple(usize);
-impl TyBuilder<Tuple> {
-    pub fn tuple(size: usize) -> TyBuilder<Tuple> {
-        TyBuilder::new(Tuple(size), std::iter::repeat_n(ParamKind::Type, size).collect(), None)
-    }
-
-    pub fn build(self) -> Ty {
-        let (Tuple(size), subst) = self.build_internal();
-        TyKind::Tuple(size, subst).intern(Interner)
-    }
-
-    pub fn tuple_with<I>(elements: I) -> Ty
-    where
-        I: IntoIterator<Item = Ty>,
-        <I as IntoIterator>::IntoIter: ExactSizeIterator,
-    {
-        let elements = elements.into_iter();
-        let len = elements.len();
-        let mut b =
-            TyBuilder::new(Tuple(len), std::iter::repeat_n(ParamKind::Type, len).collect(), None);
-        for e in elements {
-            b = b.push(e);
-        }
-        b.build()
-    }
-}
-
-impl TyBuilder<TraitId> {
-    pub fn trait_ref(db: &dyn HirDatabase, def: TraitId) -> TyBuilder<TraitId> {
-        TyBuilder::subst_for_def(db, def, None).with_data(def)
-    }
-
-    pub fn build(self) -> TraitRef {
-        let (trait_id, substitution) = self.build_internal();
-        TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution }
-    }
-}
-
-impl TyBuilder<TypeAliasId> {
-    pub fn assoc_type_projection(
-        db: &dyn HirDatabase,
-        def: TypeAliasId,
-        parent_subst: Option<Substitution>,
-    ) -> TyBuilder<TypeAliasId> {
-        TyBuilder::subst_for_def(db, def, parent_subst).with_data(def)
-    }
-
-    pub fn build(self) -> ProjectionTy {
-        let (type_alias, substitution) = self.build_internal();
-        ProjectionTy { associated_ty_id: to_assoc_type_id(type_alias), substitution }
-    }
-}
-
-impl<'db, T: rustc_type_ir::TypeFoldable<DbInterner<'db>>> TyBuilder<EarlyBinder<'db, T>> {
-    pub fn build(self, interner: DbInterner<'db>) -> T {
-        let (b, subst) = self.build_internal();
-        let args: crate::next_solver::GenericArgs<'db> = subst.to_nextsolver(interner);
-        b.instantiate(interner, args)
-    }
-}
-
-impl<'db> TyBuilder<EarlyBinder<'db, crate::next_solver::Ty<'db>>> {
-    pub fn def_ty(
-        db: &'db dyn HirDatabase,
-        def: TyDefId,
-        parent_subst: Option<Substitution>,
-    ) -> TyBuilder<EarlyBinder<'db, crate::next_solver::Ty<'db>>> {
-        let poly_ty = db.ty(def);
-        let id: GenericDefId = match def {
-            TyDefId::BuiltinType(_) => {
-                assert!(parent_subst.is_none());
-                return TyBuilder::new_empty(poly_ty);
-            }
-            TyDefId::AdtId(id) => id.into(),
-            TyDefId::TypeAliasId(id) => id.into(),
-        };
-        TyBuilder::subst_for_def(db, id, parent_subst).with_data(poly_ty)
-    }
-
-    pub fn impl_self_ty(
-        db: &'db dyn HirDatabase,
-        def: hir_def::ImplId,
-    ) -> TyBuilder<EarlyBinder<'db, crate::next_solver::Ty<'db>>> {
-        TyBuilder::subst_for_def(db, def, None).with_data(db.impl_self_ty(def))
-    }
-}
diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs
deleted file mode 100644
index 3d06b52..0000000
--- a/crates/hir-ty/src/chalk_db.rs
+++ /dev/null
@@ -1,55 +0,0 @@
-//! The implementation of `RustIrDatabase` for Chalk, which provides information
-//! about the code that Chalk needs.
-use hir_def::{CallableDefId, GenericDefId};
-
-use crate::{Interner, db::HirDatabase, mapping::from_chalk};
-
-pub(crate) type AssocTypeId = chalk_ir::AssocTypeId<Interner>;
-pub(crate) type TraitId = chalk_ir::TraitId<Interner>;
-pub(crate) type AdtId = chalk_ir::AdtId<Interner>;
-pub(crate) type ImplId = chalk_ir::ImplId<Interner>;
-pub(crate) type Variances = chalk_ir::Variances<Interner>;
-
-impl chalk_ir::UnificationDatabase<Interner> for &dyn HirDatabase {
-    fn fn_def_variance(
-        &self,
-        fn_def_id: chalk_ir::FnDefId<Interner>,
-    ) -> chalk_ir::Variances<Interner> {
-        HirDatabase::fn_def_variance(*self, from_chalk(*self, fn_def_id))
-    }
-
-    fn adt_variance(&self, adt_id: chalk_ir::AdtId<Interner>) -> chalk_ir::Variances<Interner> {
-        HirDatabase::adt_variance(*self, adt_id.0)
-    }
-}
-
-pub(crate) fn fn_def_variance_query(
-    db: &dyn HirDatabase,
-    callable_def: CallableDefId,
-) -> Variances {
-    Variances::from_iter(
-        Interner,
-        db.variances_of(GenericDefId::from_callable(db, callable_def))
-            .as_deref()
-            .unwrap_or_default()
-            .iter()
-            .map(|v| match v {
-                crate::variance::Variance::Covariant => chalk_ir::Variance::Covariant,
-                crate::variance::Variance::Invariant => chalk_ir::Variance::Invariant,
-                crate::variance::Variance::Contravariant => chalk_ir::Variance::Contravariant,
-                crate::variance::Variance::Bivariant => chalk_ir::Variance::Invariant,
-            }),
-    )
-}
-
-pub(crate) fn adt_variance_query(db: &dyn HirDatabase, adt_id: hir_def::AdtId) -> Variances {
-    Variances::from_iter(
-        Interner,
-        db.variances_of(adt_id.into()).as_deref().unwrap_or_default().iter().map(|v| match v {
-            crate::variance::Variance::Covariant => chalk_ir::Variance::Covariant,
-            crate::variance::Variance::Invariant => chalk_ir::Variance::Invariant,
-            crate::variance::Variance::Contravariant => chalk_ir::Variance::Contravariant,
-            crate::variance::Variance::Bivariant => chalk_ir::Variance::Invariant,
-        }),
-    )
-}
diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs
deleted file mode 100644
index e996037..0000000
--- a/crates/hir-ty/src/chalk_ext.rs
+++ /dev/null
@@ -1,168 +0,0 @@
-//! Various extensions traits for Chalk types.
-
-use chalk_ir::Mutability;
-use hir_def::{FunctionId, ItemContainerId, Lookup, TraitId};
-
-use crate::{
-    AdtId, Binders, CallableDefId, CallableSig, DynTy, Interner, Lifetime, ProjectionTy,
-    Substitution, ToChalk, TraitRef, Ty, TyKind, TypeFlags, WhereClause, db::HirDatabase,
-    from_assoc_type_id, from_chalk_trait_id, generics::generics, to_chalk_trait_id,
-    utils::ClosureSubst,
-};
-
-pub(crate) trait TyExt {
-    fn is_unit(&self) -> bool;
-    fn is_unknown(&self) -> bool;
-    fn contains_unknown(&self) -> bool;
-
-    fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)>;
-    fn as_tuple(&self) -> Option<&Substitution>;
-    fn as_fn_def(&self, db: &dyn HirDatabase) -> Option<FunctionId>;
-    fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)>;
-
-    fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId>;
-    fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig>;
-
-    fn strip_references(&self) -> &Ty;
-
-    /// If this is a `dyn Trait`, returns that trait.
-    fn dyn_trait(&self) -> Option<TraitId>;
-}
-
-impl TyExt for Ty {
-    fn is_unit(&self) -> bool {
-        matches!(self.kind(Interner), TyKind::Tuple(0, _))
-    }
-
-    fn is_unknown(&self) -> bool {
-        matches!(self.kind(Interner), TyKind::Error)
-    }
-
-    fn contains_unknown(&self) -> bool {
-        self.data(Interner).flags.contains(TypeFlags::HAS_ERROR)
-    }
-
-    fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)> {
-        match self.kind(Interner) {
-            TyKind::Adt(AdtId(adt), parameters) => Some((*adt, parameters)),
-            _ => None,
-        }
-    }
-
-    fn as_tuple(&self) -> Option<&Substitution> {
-        match self.kind(Interner) {
-            TyKind::Tuple(_, substs) => Some(substs),
-            _ => None,
-        }
-    }
-
-    fn as_fn_def(&self, db: &dyn HirDatabase) -> Option<FunctionId> {
-        match self.callable_def(db) {
-            Some(CallableDefId::FunctionId(func)) => Some(func),
-            Some(CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_)) | None => None,
-        }
-    }
-
-    fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)> {
-        match self.kind(Interner) {
-            TyKind::Ref(mutability, lifetime, ty) => Some((ty, lifetime.clone(), *mutability)),
-            _ => None,
-        }
-    }
-
-    fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId> {
-        match self.kind(Interner) {
-            &TyKind::FnDef(def, ..) => Some(ToChalk::from_chalk(db, def)),
-            _ => None,
-        }
-    }
-
-    fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig> {
-        match self.kind(Interner) {
-            TyKind::Function(fn_ptr) => Some(CallableSig::from_fn_ptr(fn_ptr)),
-            TyKind::FnDef(def, parameters) => Some(CallableSig::from_def(db, *def, parameters)),
-            TyKind::Closure(.., substs) => ClosureSubst(substs).sig_ty(db).callable_sig(db),
-            _ => None,
-        }
-    }
-
-    fn dyn_trait(&self) -> Option<TraitId> {
-        let trait_ref = match self.kind(Interner) {
-            // The principal trait bound should be the first element of the bounds. This is an
-            // invariant ensured by `TyLoweringContext::lower_dyn_trait()`.
-            // FIXME: dyn types may not have principal trait and we don't want to return auto trait
-            // here.
-            TyKind::Dyn(dyn_ty) => dyn_ty.bounds.skip_binders().interned().first().and_then(|b| {
-                match b.skip_binders() {
-                    WhereClause::Implemented(trait_ref) => Some(trait_ref),
-                    _ => None,
-                }
-            }),
-            _ => None,
-        }?;
-        Some(from_chalk_trait_id(trait_ref.trait_id))
-    }
-
-    fn strip_references(&self) -> &Ty {
-        let mut t: &Ty = self;
-        while let TyKind::Ref(_mutability, _lifetime, ty) = t.kind(Interner) {
-            t = ty;
-        }
-        t
-    }
-}
-
-pub trait ProjectionTyExt {
-    fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef;
-    fn trait_(&self, db: &dyn HirDatabase) -> TraitId;
-    fn self_type_parameter(&self, db: &dyn HirDatabase) -> Ty;
-}
-
-impl ProjectionTyExt for ProjectionTy {
-    fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef {
-        // FIXME: something like `Split` trait from chalk-solve might be nice.
-        let generics = generics(db, from_assoc_type_id(self.associated_ty_id).into());
-        let parent_len = generics.parent_generics().map_or(0, |g| g.len_self());
-        let substitution =
-            Substitution::from_iter(Interner, self.substitution.iter(Interner).take(parent_len));
-        TraitRef { trait_id: to_chalk_trait_id(self.trait_(db)), substitution }
-    }
-
-    fn trait_(&self, db: &dyn HirDatabase) -> TraitId {
-        match from_assoc_type_id(self.associated_ty_id).lookup(db).container {
-            ItemContainerId::TraitId(it) => it,
-            _ => panic!("projection ty without parent trait"),
-        }
-    }
-
-    fn self_type_parameter(&self, db: &dyn HirDatabase) -> Ty {
-        self.trait_ref(db).self_type_parameter(Interner)
-    }
-}
-
-pub(crate) trait DynTyExt {
-    fn principal(&self) -> Option<Binders<Binders<&TraitRef>>>;
-}
-
-impl DynTyExt for DynTy {
-    fn principal(&self) -> Option<Binders<Binders<&TraitRef>>> {
-        self.bounds.as_ref().filter_map(|bounds| {
-            bounds.interned().first().and_then(|b| {
-                b.as_ref().filter_map(|b| match b {
-                    crate::WhereClause::Implemented(trait_ref) => Some(trait_ref),
-                    _ => None,
-                })
-            })
-        })
-    }
-}
-
-pub trait TraitRefExt {
-    fn hir_trait_id(&self) -> TraitId;
-}
-
-impl TraitRefExt for TraitRef {
-    fn hir_trait_id(&self) -> TraitId {
-        from_chalk_trait_id(self.trait_id)
-    }
-}
diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs
index 002e082..18ebe7d 100644
--- a/crates/hir-ty/src/consteval.rs
+++ b/crates/hir-ty/src/consteval.rs
@@ -5,76 +5,29 @@
 
 use base_db::Crate;
 use hir_def::{
-    EnumVariantId, GeneralConstId,
-    expr_store::{Body, HygieneId, path::Path},
+    EnumVariantId, GeneralConstId, HasModule, StaticId,
+    expr_store::Body,
     hir::{Expr, ExprId},
-    resolver::{Resolver, ValueNs},
     type_ref::LiteralConstRef,
 };
-use hir_def::{HasModule, StaticId};
 use hir_expand::Lookup;
-use rustc_type_ir::{UnevaluatedConst, inherent::IntoKind};
-use stdx::never;
+use rustc_type_ir::inherent::IntoKind;
 use triomphe::Arc;
 
 use crate::{
-    MemoryMap, TraitEnvironment,
+    LifetimeElisionKind, MemoryMap, TraitEnvironment, TyLoweringContext,
     db::HirDatabase,
     display::DisplayTarget,
-    generics::Generics,
     infer::InferenceContext,
     mir::{MirEvalError, MirLowerError},
     next_solver::{
         Const, ConstBytes, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs,
-        ParamConst, SolverDefId, Ty, ValueConst,
+        SolverDefId, Ty, ValueConst,
     },
 };
 
 use super::mir::{interpret_mir, lower_to_mir, pad16};
 
-pub(crate) fn path_to_const<'a, 'g>(
-    db: &'a dyn HirDatabase,
-    resolver: &Resolver<'a>,
-    path: &Path,
-    args: impl FnOnce() -> &'g Generics,
-    _expected_ty: Ty<'a>,
-) -> Option<Const<'a>> {
-    let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
-    match resolver.resolve_path_in_value_ns_fully(db, path, HygieneId::ROOT) {
-        Some(ValueNs::GenericParam(p)) => {
-            let args = args();
-            match args
-                .type_or_const_param(p.into())
-                .and_then(|(idx, p)| p.const_param().map(|p| (idx, p.clone())))
-            {
-                Some((idx, _param)) => {
-                    Some(Const::new_param(interner, ParamConst { index: idx as u32, id: p }))
-                }
-                None => {
-                    never!(
-                        "Generic list doesn't contain this param: {:?}, {:?}, {:?}",
-                        args,
-                        path,
-                        p
-                    );
-                    None
-                }
-            }
-        }
-        Some(ValueNs::ConstId(c)) => {
-            let args = GenericArgs::new_from_iter(interner, []);
-            Some(Const::new(
-                interner,
-                rustc_type_ir::ConstKind::Unevaluated(UnevaluatedConst::new(
-                    SolverDefId::ConstId(c),
-                    args,
-                )),
-            ))
-        }
-        _ => None,
-    }
-}
-
 pub fn unknown_const<'db>(_ty: Ty<'db>) -> Const<'db> {
     Const::new(DbInterner::conjure(), rustc_type_ir::ConstKind::Error(ErrorGuaranteed))
 }
@@ -280,8 +233,14 @@
         return unknown_const(infer[expr]);
     }
     if let Expr::Path(p) = &ctx.body[expr] {
-        let resolver = &ctx.resolver;
-        if let Some(c) = path_to_const(ctx.db, resolver, p, || ctx.generics(), infer[expr]) {
+        let mut ctx = TyLoweringContext::new(
+            ctx.db,
+            &ctx.resolver,
+            ctx.body,
+            ctx.generic_def,
+            LifetimeElisionKind::Infer,
+        );
+        if let Some(c) = ctx.path_to_const(p) {
             return c;
         }
     }
diff --git a/crates/hir-ty/src/consteval_chalk.rs b/crates/hir-ty/src/consteval_chalk.rs
deleted file mode 100644
index 07b783e..0000000
--- a/crates/hir-ty/src/consteval_chalk.rs
+++ /dev/null
@@ -1,108 +0,0 @@
-//! Constant evaluation details
-
-use base_db::Crate;
-use chalk_ir::{BoundVar, DebruijnIndex, cast::Cast};
-use hir_def::{
-    expr_store::{HygieneId, path::Path},
-    resolver::{Resolver, ValueNs},
-    type_ref::LiteralConstRef,
-};
-use stdx::never;
-
-use crate::{
-    Const, ConstData, ConstScalar, ConstValue, GenericArg, Interner, MemoryMap, Substitution,
-    TraitEnvironment, Ty,
-    db::HirDatabase,
-    generics::Generics,
-    lower::ParamLoweringMode,
-    next_solver::{DbInterner, mapping::ChalkToNextSolver},
-    to_placeholder_idx,
-};
-
-pub(crate) fn path_to_const<'g>(
-    db: &dyn HirDatabase,
-    resolver: &Resolver<'_>,
-    path: &Path,
-    mode: ParamLoweringMode,
-    args: impl FnOnce() -> &'g Generics,
-    debruijn: DebruijnIndex,
-    expected_ty: Ty,
-) -> Option<Const> {
-    match resolver.resolve_path_in_value_ns_fully(db, path, HygieneId::ROOT) {
-        Some(ValueNs::GenericParam(p)) => {
-            let ty = db.const_param_ty(p);
-            let args = args();
-            let value = match mode {
-                ParamLoweringMode::Placeholder => {
-                    let idx = args.type_or_const_param_idx(p.into()).unwrap();
-                    ConstValue::Placeholder(to_placeholder_idx(db, p.into(), idx as u32))
-                }
-                ParamLoweringMode::Variable => match args.type_or_const_param_idx(p.into()) {
-                    Some(it) => ConstValue::BoundVar(BoundVar::new(debruijn, it)),
-                    None => {
-                        never!(
-                            "Generic list doesn't contain this param: {:?}, {:?}, {:?}",
-                            args,
-                            path,
-                            p
-                        );
-                        return None;
-                    }
-                },
-            };
-            Some(ConstData { ty, value }.intern(Interner))
-        }
-        Some(ValueNs::ConstId(c)) => Some(intern_const_scalar(
-            ConstScalar::UnevaluatedConst(c.into(), Substitution::empty(Interner)),
-            expected_ty,
-        )),
-        // FIXME: With feature(adt_const_params), we also need to consider other things here, e.g. struct constructors.
-        _ => None,
-    }
-}
-
-pub(crate) fn unknown_const(ty: Ty) -> Const {
-    ConstData {
-        ty,
-        value: ConstValue::Concrete(chalk_ir::ConcreteConst { interned: ConstScalar::Unknown }),
-    }
-    .intern(Interner)
-}
-
-pub(crate) fn unknown_const_as_generic(ty: Ty) -> GenericArg {
-    unknown_const(ty).cast(Interner)
-}
-
-/// Interns a constant scalar with the given type
-pub(crate) fn intern_const_scalar(value: ConstScalar, ty: Ty) -> Const {
-    ConstData { ty, value: ConstValue::Concrete(chalk_ir::ConcreteConst { interned: value }) }
-        .intern(Interner)
-}
-
-/// Interns a constant scalar with the given type
-pub(crate) fn intern_const_ref(
-    db: &dyn HirDatabase,
-    value: &LiteralConstRef,
-    ty: Ty,
-    krate: Crate,
-) -> Const {
-    let interner = DbInterner::new_with(db, Some(krate), None);
-    let layout = || db.layout_of_ty(ty.to_nextsolver(interner), TraitEnvironment::empty(krate));
-    let bytes = match value {
-        LiteralConstRef::Int(i) => {
-            // FIXME: We should handle failure of layout better.
-            let size = layout().map(|it| it.size.bytes_usize()).unwrap_or(16);
-            ConstScalar::Bytes(i.to_le_bytes()[0..size].into(), MemoryMap::default())
-        }
-        LiteralConstRef::UInt(i) => {
-            let size = layout().map(|it| it.size.bytes_usize()).unwrap_or(16);
-            ConstScalar::Bytes(i.to_le_bytes()[0..size].into(), MemoryMap::default())
-        }
-        LiteralConstRef::Bool(b) => ConstScalar::Bytes(Box::new([*b as u8]), MemoryMap::default()),
-        LiteralConstRef::Char(c) => {
-            ConstScalar::Bytes((*c as u32).to_le_bytes().into(), MemoryMap::default())
-        }
-        LiteralConstRef::Unknown => ConstScalar::Unknown,
-    };
-    intern_const_scalar(bytes, ty)
-}
diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs
index 4b33c8a..9b58abb 100644
--- a/crates/hir-ty/src/db.rs
+++ b/crates/hir-ty/src/db.rs
@@ -1,8 +1,7 @@
 //! The home of `HirDatabase`, which is the Salsa database containing all the
 //! type inference-related queries.
 
-use base_db::Crate;
-use base_db::target::TargetLoadError;
+use base_db::{Crate, target::TargetLoadError};
 use hir_def::{
     AdtId, BlockId, CallableDefId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId,
     GeneralConstId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, StaticId, TraitId,
@@ -16,15 +15,14 @@
 use triomphe::Arc;
 
 use crate::{
-    Binders, ImplTraitId, ImplTraits, InferenceResult, TraitEnvironment, Ty, TyDefId, ValueTyDefId,
-    chalk_db,
+    ImplTraitId, InferenceResult, TraitEnvironment, TyDefId, ValueTyDefId,
     consteval::ConstEvalError,
     dyn_compatibility::DynCompatibilityViolation,
     layout::{Layout, LayoutError},
-    lower::{Diagnostics, GenericDefaults, GenericPredicates},
+    lower::{Diagnostics, GenericDefaults, GenericPredicates, ImplTraits},
     method_resolution::{InherentImpls, TraitImpls, TyFingerprint},
     mir::{BorrowckResult, MirBody, MirLowerError},
-    traits::NextTraitSolveResult,
+    next_solver::{Const, EarlyBinder, GenericArgs, PolyFnSig, TraitRef, Ty, VariancesOf},
 };
 
 #[query_group::query_group]
@@ -53,7 +51,7 @@
     fn monomorphized_mir_body<'db>(
         &'db self,
         def: DefWithBodyId,
-        subst: crate::next_solver::GenericArgs<'db>,
+        subst: GenericArgs<'db>,
         env: Arc<TraitEnvironment<'db>>,
     ) -> Result<Arc<MirBody<'db>>, MirLowerError<'db>>;
 
@@ -61,7 +59,7 @@
     fn monomorphized_mir_body_for_closure<'db>(
         &'db self,
         def: InternedClosureId,
-        subst: crate::next_solver::GenericArgs<'db>,
+        subst: GenericArgs<'db>,
         env: Arc<TraitEnvironment<'db>>,
     ) -> Result<Arc<MirBody<'db>>, MirLowerError<'db>>;
 
@@ -77,16 +75,13 @@
     fn const_eval<'db>(
         &'db self,
         def: GeneralConstId,
-        subst: crate::next_solver::GenericArgs<'db>,
+        subst: GenericArgs<'db>,
         trait_env: Option<Arc<TraitEnvironment<'db>>>,
-    ) -> Result<crate::next_solver::Const<'db>, ConstEvalError<'db>>;
+    ) -> Result<Const<'db>, ConstEvalError<'db>>;
 
     #[salsa::invoke(crate::consteval::const_eval_static_query)]
     #[salsa::cycle(cycle_result = crate::consteval::const_eval_static_cycle_result)]
-    fn const_eval_static<'db>(
-        &'db self,
-        def: StaticId,
-    ) -> Result<crate::next_solver::Const<'db>, ConstEvalError<'db>>;
+    fn const_eval_static<'db>(&'db self, def: StaticId) -> Result<Const<'db>, ConstEvalError<'db>>;
 
     #[salsa::invoke(crate::consteval::const_eval_discriminant_variant)]
     #[salsa::cycle(cycle_result = crate::consteval::const_eval_discriminant_cycle_result)]
@@ -96,12 +91,13 @@
     ) -> Result<i128, ConstEvalError<'db>>;
 
     #[salsa::invoke(crate::method_resolution::lookup_impl_method_query)]
+    #[salsa::transparent]
     fn lookup_impl_method<'db>(
         &'db self,
         env: Arc<TraitEnvironment<'db>>,
         func: FunctionId,
-        fn_subst: crate::next_solver::GenericArgs<'db>,
-    ) -> (FunctionId, crate::next_solver::GenericArgs<'db>);
+        fn_subst: GenericArgs<'db>,
+    ) -> (FunctionId, GenericArgs<'db>);
 
     // endregion:mir
 
@@ -110,7 +106,7 @@
     fn layout_of_adt<'db>(
         &'db self,
         def: AdtId,
-        args: crate::next_solver::GenericArgs<'db>,
+        args: GenericArgs<'db>,
         trait_env: Arc<TraitEnvironment<'db>>,
     ) -> Result<Arc<Layout>, LayoutError>;
 
@@ -118,7 +114,7 @@
     #[salsa::cycle(cycle_result = crate::layout::layout_of_ty_cycle_result)]
     fn layout_of_ty<'db>(
         &'db self,
-        ty: crate::next_solver::Ty<'db>,
+        ty: Ty<'db>,
         env: Arc<TraitEnvironment<'db>>,
     ) -> Result<Arc<Layout>, LayoutError>;
 
@@ -128,149 +124,130 @@
     #[salsa::invoke(crate::dyn_compatibility::dyn_compatibility_of_trait_query)]
     fn dyn_compatibility_of_trait(&self, trait_: TraitId) -> Option<DynCompatibilityViolation>;
 
-    #[salsa::invoke(crate::lower_nextsolver::ty_query)]
+    #[salsa::invoke(crate::lower::ty_query)]
     #[salsa::transparent]
-    fn ty<'db>(
-        &'db self,
-        def: TyDefId,
-    ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>;
+    fn ty<'db>(&'db self, def: TyDefId) -> EarlyBinder<'db, Ty<'db>>;
 
-    #[salsa::invoke(crate::lower_nextsolver::type_for_type_alias_with_diagnostics_query)]
-    #[salsa::cycle(cycle_result = crate::lower_nextsolver::type_for_type_alias_with_diagnostics_cycle_result)]
+    #[salsa::invoke(crate::lower::type_for_type_alias_with_diagnostics_query)]
+    #[salsa::cycle(cycle_result = crate::lower::type_for_type_alias_with_diagnostics_cycle_result)]
     fn type_for_type_alias_with_diagnostics<'db>(
         &'db self,
         def: TypeAliasId,
-    ) -> (crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>, Diagnostics);
+    ) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics);
 
     /// Returns the type of the value of the given constant, or `None` if the `ValueTyDefId` is
     /// a `StructId` or `EnumVariantId` with a record constructor.
-    #[salsa::invoke(crate::lower_nextsolver::value_ty_query)]
-    fn value_ty<'db>(
-        &'db self,
-        def: ValueTyDefId,
-    ) -> Option<crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>>;
+    #[salsa::invoke(crate::lower::value_ty_query)]
+    fn value_ty<'db>(&'db self, def: ValueTyDefId) -> Option<EarlyBinder<'db, Ty<'db>>>;
 
-    #[salsa::invoke(crate::lower_nextsolver::impl_self_ty_with_diagnostics_query)]
-    #[salsa::cycle(cycle_result = crate::lower_nextsolver::impl_self_ty_with_diagnostics_cycle_result)]
+    #[salsa::invoke(crate::lower::impl_self_ty_with_diagnostics_query)]
+    #[salsa::cycle(cycle_result = crate::lower::impl_self_ty_with_diagnostics_cycle_result)]
     fn impl_self_ty_with_diagnostics<'db>(
         &'db self,
         def: ImplId,
-    ) -> (crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>, Diagnostics);
+    ) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics);
 
-    #[salsa::invoke(crate::lower_nextsolver::impl_self_ty_query)]
+    #[salsa::invoke(crate::lower::impl_self_ty_query)]
     #[salsa::transparent]
-    fn impl_self_ty<'db>(
-        &'db self,
-        def: ImplId,
-    ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>;
+    fn impl_self_ty<'db>(&'db self, def: ImplId) -> EarlyBinder<'db, Ty<'db>>;
 
     // FIXME: Make this a non-interned query.
-    #[salsa::invoke_interned(crate::lower_nextsolver::const_param_ty_with_diagnostics_query)]
-    #[salsa::cycle(cycle_result = crate::lower_nextsolver::const_param_ty_with_diagnostics_cycle_result)]
-    fn const_param_ty_with_diagnostics<'db>(
-        &'db self,
-        def: ConstParamId,
-    ) -> (crate::next_solver::Ty<'db>, Diagnostics);
+    #[salsa::invoke_interned(crate::lower::const_param_ty_with_diagnostics_query)]
+    #[salsa::cycle(cycle_result = crate::lower::const_param_ty_with_diagnostics_cycle_result)]
+    fn const_param_ty_with_diagnostics<'db>(&'db self, def: ConstParamId)
+    -> (Ty<'db>, Diagnostics);
 
-    // FIXME: Make this a non-interned query.
-    #[salsa::invoke_interned(crate::lower::const_param_ty_query)]
-    #[salsa::cycle(cycle_result = crate::lower::const_param_ty_cycle_result)]
-    fn const_param_ty(&self, def: ConstParamId) -> Ty;
+    #[salsa::invoke(crate::lower::const_param_ty_query)]
+    #[salsa::transparent]
+    fn const_param_ty_ns<'db>(&'db self, def: ConstParamId) -> Ty<'db>;
 
-    #[salsa::invoke(crate::lower_nextsolver::impl_trait_with_diagnostics_query)]
+    #[salsa::invoke(crate::lower::impl_trait_with_diagnostics_query)]
     fn impl_trait_with_diagnostics<'db>(
         &'db self,
         def: ImplId,
-    ) -> Option<(
-        crate::next_solver::EarlyBinder<'db, crate::next_solver::TraitRef<'db>>,
-        Diagnostics,
-    )>;
+    ) -> Option<(EarlyBinder<'db, TraitRef<'db>>, Diagnostics)>;
 
-    #[salsa::invoke(crate::lower_nextsolver::impl_trait_query)]
+    #[salsa::invoke(crate::lower::impl_trait_query)]
     #[salsa::transparent]
-    fn impl_trait<'db>(
-        &'db self,
-        def: ImplId,
-    ) -> Option<crate::next_solver::EarlyBinder<'db, crate::next_solver::TraitRef<'db>>>;
+    fn impl_trait<'db>(&'db self, def: ImplId) -> Option<EarlyBinder<'db, TraitRef<'db>>>;
 
-    #[salsa::invoke(crate::lower_nextsolver::field_types_with_diagnostics_query)]
+    #[salsa::invoke(crate::lower::field_types_with_diagnostics_query)]
     fn field_types_with_diagnostics<'db>(
         &'db self,
         var: VariantId,
-    ) -> (
-        Arc<
-            ArenaMap<
-                LocalFieldId,
-                crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>,
-            >,
-        >,
-        Diagnostics,
-    );
+    ) -> (Arc<ArenaMap<LocalFieldId, EarlyBinder<'db, Ty<'db>>>>, Diagnostics);
 
     #[salsa::invoke(crate::lower::field_types_query)]
     #[salsa::transparent]
-    fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>>;
+    fn field_types<'db>(
+        &'db self,
+        var: VariantId,
+    ) -> Arc<ArenaMap<LocalFieldId, EarlyBinder<'db, Ty<'db>>>>;
 
-    #[salsa::invoke(crate::lower_nextsolver::callable_item_signature_query)]
+    #[salsa::invoke(crate::lower::callable_item_signature_query)]
     fn callable_item_signature<'db>(
         &'db self,
         def: CallableDefId,
-    ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::PolyFnSig<'db>>;
+    ) -> EarlyBinder<'db, PolyFnSig<'db>>;
 
     #[salsa::invoke(crate::lower::return_type_impl_traits)]
-    fn return_type_impl_traits(&self, def: FunctionId) -> Option<Arc<Binders<ImplTraits>>>;
+    fn return_type_impl_traits<'db>(
+        &'db self,
+        def: FunctionId,
+    ) -> Option<Arc<EarlyBinder<'db, ImplTraits<'db>>>>;
 
     #[salsa::invoke(crate::lower::type_alias_impl_traits)]
-    fn type_alias_impl_traits(&self, def: TypeAliasId) -> Option<Arc<Binders<ImplTraits>>>;
+    fn type_alias_impl_traits<'db>(
+        &'db self,
+        def: TypeAliasId,
+    ) -> Option<Arc<EarlyBinder<'db, ImplTraits<'db>>>>;
 
-    #[salsa::invoke(crate::lower::generic_predicates_for_param_query)]
-    #[salsa::cycle(cycle_result = crate::lower::generic_predicates_for_param_cycle_result)]
-    fn generic_predicates_for_param(
-        &self,
-        def: GenericDefId,
-        param_id: TypeOrConstParamId,
-        assoc_name: Option<Name>,
-    ) -> GenericPredicates;
-
-    #[salsa::invoke(crate::lower::generic_predicates_query)]
-    fn generic_predicates(&self, def: GenericDefId) -> GenericPredicates;
-
-    #[salsa::invoke(
-        crate::lower_nextsolver::generic_predicates_without_parent_with_diagnostics_query
-    )]
+    #[salsa::invoke(crate::lower::generic_predicates_without_parent_with_diagnostics_query)]
     fn generic_predicates_without_parent_with_diagnostics<'db>(
         &'db self,
         def: GenericDefId,
-    ) -> (crate::lower_nextsolver::GenericPredicates<'db>, Diagnostics);
+    ) -> (GenericPredicates<'db>, Diagnostics);
 
-    #[salsa::invoke(crate::lower_nextsolver::generic_predicates_without_parent_query)]
+    #[salsa::invoke(crate::lower::generic_predicates_without_parent_query)]
     #[salsa::transparent]
     fn generic_predicates_without_parent<'db>(
         &'db self,
         def: GenericDefId,
-    ) -> crate::lower_nextsolver::GenericPredicates<'db>;
+    ) -> GenericPredicates<'db>;
 
-    #[salsa::invoke(crate::lower_nextsolver::trait_environment_for_body_query)]
+    #[salsa::invoke(crate::lower::generic_predicates_for_param_query)]
+    #[salsa::cycle(cycle_result = crate::lower::generic_predicates_for_param_cycle_result)]
+    fn generic_predicates_for_param<'db>(
+        &'db self,
+        def: GenericDefId,
+        param_id: TypeOrConstParamId,
+        assoc_name: Option<Name>,
+    ) -> GenericPredicates<'db>;
+
+    #[salsa::invoke(crate::lower::generic_predicates_query)]
+    fn generic_predicates<'db>(&'db self, def: GenericDefId) -> GenericPredicates<'db>;
+
+    #[salsa::invoke(crate::lower::trait_environment_for_body_query)]
     #[salsa::transparent]
     fn trait_environment_for_body<'db>(&'db self, def: DefWithBodyId)
     -> Arc<TraitEnvironment<'db>>;
 
-    #[salsa::invoke(crate::lower_nextsolver::trait_environment_query)]
+    #[salsa::invoke(crate::lower::trait_environment_query)]
     fn trait_environment<'db>(&'db self, def: GenericDefId) -> Arc<TraitEnvironment<'db>>;
 
     #[salsa::invoke(crate::lower::generic_defaults_with_diagnostics_query)]
     #[salsa::cycle(cycle_result = crate::lower::generic_defaults_with_diagnostics_cycle_result)]
-    fn generic_defaults_with_diagnostics(
-        &self,
+    fn generic_defaults_with_diagnostics<'db>(
+        &'db self,
         def: GenericDefId,
-    ) -> (GenericDefaults, Diagnostics);
+    ) -> (GenericDefaults<'db>, Diagnostics);
 
     /// This returns an empty list if no parameter has default.
     ///
     /// The binders of the returned defaults are only up to (not including) this parameter.
     #[salsa::invoke(crate::lower::generic_defaults_query)]
     #[salsa::transparent]
-    fn generic_defaults(&self, def: GenericDefId) -> GenericDefaults;
+    fn generic_defaults<'db>(&'db self, def: GenericDefId) -> GenericDefaults<'db>;
 
     #[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)]
     fn inherent_impls_in_crate(&self, krate: Crate) -> Arc<InherentImpls>;
@@ -298,9 +275,9 @@
     #[salsa::invoke(TraitImpls::trait_impls_in_deps_query)]
     fn trait_impls_in_deps(&self, krate: Crate) -> Arc<[Arc<TraitImpls>]>;
 
-    // Interned IDs for Chalk integration
+    // Interned IDs for solver integration
     #[salsa::interned]
-    fn intern_impl_trait_id(&self, id: ImplTraitId) -> InternedOpaqueTyId;
+    fn intern_impl_trait_id(&self, id: ImplTraitId<'_>) -> InternedOpaqueTyId;
 
     #[salsa::interned]
     fn intern_closure(&self, id: InternedClosure) -> InternedClosureId;
@@ -308,95 +285,13 @@
     #[salsa::interned]
     fn intern_coroutine(&self, id: InternedCoroutine) -> InternedCoroutineId;
 
-    #[salsa::invoke(chalk_db::fn_def_variance_query)]
-    fn fn_def_variance(&self, fn_def_id: CallableDefId) -> chalk_db::Variances;
-
-    #[salsa::invoke(chalk_db::adt_variance_query)]
-    fn adt_variance(&self, adt_id: AdtId) -> chalk_db::Variances;
-
     #[salsa::invoke(crate::variance::variances_of)]
     #[salsa::cycle(
         // cycle_fn = crate::variance::variances_of_cycle_fn,
         // cycle_initial = crate::variance::variances_of_cycle_initial,
         cycle_result = crate::variance::variances_of_cycle_initial,
     )]
-    fn variances_of(&self, def: GenericDefId) -> Option<Arc<[crate::variance::Variance]>>;
-
-    #[salsa::invoke(crate::traits::normalize_projection_query)]
-    #[salsa::transparent]
-    fn normalize_projection(
-        &self,
-        projection: crate::ProjectionTy,
-        env: Arc<TraitEnvironment<'_>>,
-    ) -> Ty;
-
-    #[salsa::invoke(crate::traits::trait_solve_query)]
-    #[salsa::transparent]
-    fn trait_solve(
-        &self,
-        krate: Crate,
-        block: Option<BlockId>,
-        goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
-    ) -> NextTraitSolveResult;
-
-    // next trait solver
-
-    #[salsa::invoke(crate::lower_nextsolver::const_param_ty_query)]
-    #[salsa::transparent]
-    fn const_param_ty_ns<'db>(&'db self, def: ConstParamId) -> crate::next_solver::Ty<'db>;
-
-    #[salsa::invoke(crate::lower_nextsolver::field_types_query)]
-    #[salsa::transparent]
-    fn field_types_ns<'db>(
-        &'db self,
-        var: VariantId,
-    ) -> Arc<
-        ArenaMap<LocalFieldId, crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>>,
-    >;
-
-    #[salsa::invoke(crate::lower_nextsolver::return_type_impl_traits)]
-    fn return_type_impl_traits_ns<'db>(
-        &'db self,
-        def: FunctionId,
-    ) -> Option<Arc<crate::next_solver::EarlyBinder<'db, crate::lower_nextsolver::ImplTraits<'db>>>>;
-
-    #[salsa::invoke(crate::lower_nextsolver::type_alias_impl_traits)]
-    fn type_alias_impl_traits_ns<'db>(
-        &'db self,
-        def: TypeAliasId,
-    ) -> Option<Arc<crate::next_solver::EarlyBinder<'db, crate::lower_nextsolver::ImplTraits<'db>>>>;
-
-    #[salsa::invoke(crate::lower_nextsolver::generic_predicates_for_param_query)]
-    #[salsa::cycle(cycle_result = crate::lower_nextsolver::generic_predicates_for_param_cycle_result)]
-    fn generic_predicates_for_param_ns<'db>(
-        &'db self,
-        def: GenericDefId,
-        param_id: TypeOrConstParamId,
-        assoc_name: Option<Name>,
-    ) -> crate::lower_nextsolver::GenericPredicates<'db>;
-
-    #[salsa::invoke(crate::lower_nextsolver::generic_predicates_query)]
-    fn generic_predicates_ns<'db>(
-        &'db self,
-        def: GenericDefId,
-    ) -> crate::lower_nextsolver::GenericPredicates<'db>;
-
-    #[salsa::invoke(crate::lower_nextsolver::generic_defaults_with_diagnostics_query)]
-    #[salsa::cycle(cycle_result = crate::lower_nextsolver::generic_defaults_with_diagnostics_cycle_result)]
-    fn generic_defaults_ns_with_diagnostics<'db>(
-        &'db self,
-        def: GenericDefId,
-    ) -> (crate::lower_nextsolver::GenericDefaults<'db>, Diagnostics);
-
-    /// This returns an empty list if no parameter has default.
-    ///
-    /// The binders of the returned defaults are only up to (not including) this parameter.
-    #[salsa::invoke(crate::lower_nextsolver::generic_defaults_query)]
-    #[salsa::transparent]
-    fn generic_defaults_ns<'db>(
-        &'db self,
-        def: GenericDefId,
-    ) -> crate::lower_nextsolver::GenericDefaults<'db>;
+    fn variances_of<'db>(&'db self, def: GenericDefId) -> VariancesOf<'db>;
 }
 
 #[test]
@@ -427,7 +322,7 @@
 #[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)]
 #[derive(PartialOrd, Ord)]
 pub struct InternedOpaqueTyId {
-    pub loc: ImplTraitId,
+    pub loc: ImplTraitId<'db>,
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
diff --git a/crates/hir-ty/src/diagnostics/expr.rs b/crates/hir-ty/src/diagnostics/expr.rs
index 7b6fb99..0eca0c0 100644
--- a/crates/hir-ty/src/diagnostics/expr.rs
+++ b/crates/hir-ty/src/diagnostics/expr.rs
@@ -15,6 +15,7 @@
 use itertools::Itertools;
 use rustc_hash::FxHashSet;
 use rustc_pattern_analysis::constructor::Constructor;
+use rustc_type_ir::inherent::{AdtDef, IntoKind};
 use syntax::{
     AstNode,
     ast::{self, UnaryOp},
@@ -23,16 +24,18 @@
 use triomphe::Arc;
 use typed_arena::Arena;
 
-use crate::next_solver::DbInterner;
-use crate::next_solver::mapping::NextSolverToChalk;
 use crate::{
-    Adjust, InferenceResult, Interner, TraitEnvironment, Ty, TyExt, TyKind,
+    Adjust, InferenceResult, TraitEnvironment,
     db::HirDatabase,
     diagnostics::match_check::{
         self,
         pat_analysis::{self, DeconstructedPat, MatchCheckCtx, WitnessPat},
     },
     display::{DisplayTarget, HirDisplay},
+    next_solver::{
+        DbInterner, Ty, TyKind, TypingMode,
+        infer::{DbInternerInferExt, InferCtxt},
+    },
 };
 
 pub(crate) use hir_def::{
@@ -77,6 +80,8 @@
         let body = db.body(owner);
         let env = db.trait_environment_for_body(owner);
         let interner = DbInterner::new_with(db, Some(env.krate), env.block);
+        let infcx =
+            interner.infer_ctxt().build(TypingMode::typeck_for_body(interner, owner.into()));
         let mut validator = ExprValidator {
             owner,
             body,
@@ -84,9 +89,9 @@
             diagnostics: Vec::new(),
             validate_lints,
             env,
-            interner,
+            infcx,
         };
-        validator.validate_body(db);
+        validator.validate_body();
         validator.diagnostics
     }
 }
@@ -98,11 +103,17 @@
     env: Arc<TraitEnvironment<'db>>,
     diagnostics: Vec<BodyValidationDiagnostic>,
     validate_lints: bool,
-    interner: DbInterner<'db>,
+    infcx: InferCtxt<'db>,
 }
 
 impl<'db> ExprValidator<'db> {
-    fn validate_body(&mut self, db: &'db dyn HirDatabase) {
+    #[inline]
+    fn db(&self) -> &'db dyn HirDatabase {
+        self.infcx.interner.db
+    }
+
+    fn validate_body(&mut self) {
+        let db = self.db();
         let mut filter_map_next_checker = None;
         // we'll pass &mut self while iterating over body.exprs, so they need to be disjoint
         let body = Arc::clone(&self.body);
@@ -124,19 +135,19 @@
 
             match expr {
                 Expr::Match { expr, arms } => {
-                    self.validate_match(id, *expr, arms, db);
+                    self.validate_match(id, *expr, arms);
                 }
                 Expr::Call { .. } | Expr::MethodCall { .. } => {
-                    self.validate_call(db, id, expr, &mut filter_map_next_checker);
+                    self.validate_call(id, expr, &mut filter_map_next_checker);
                 }
                 Expr::Closure { body: body_expr, .. } => {
                     self.check_for_trailing_return(*body_expr, &body);
                 }
                 Expr::If { .. } => {
-                    self.check_for_unnecessary_else(id, expr, db);
+                    self.check_for_unnecessary_else(id, expr);
                 }
                 Expr::Block { .. } | Expr::Async { .. } | Expr::Unsafe { .. } => {
-                    self.validate_block(db, expr);
+                    self.validate_block(expr);
                 }
                 _ => {}
             }
@@ -157,10 +168,9 @@
 
     fn validate_call(
         &mut self,
-        db: &dyn HirDatabase,
         call_id: ExprId,
         expr: &Expr,
-        filter_map_next_checker: &mut Option<FilterMapNextChecker>,
+        filter_map_next_checker: &mut Option<FilterMapNextChecker<'db>>,
     ) {
         if !self.validate_lints {
             return;
@@ -176,8 +186,9 @@
                 None => return,
             };
 
-            let checker = filter_map_next_checker
-                .get_or_insert_with(|| FilterMapNextChecker::new(&self.owner.resolver(db), db));
+            let checker = filter_map_next_checker.get_or_insert_with(|| {
+                FilterMapNextChecker::new(&self.owner.resolver(self.db()), self.db())
+            });
 
             if checker.check(call_id, receiver, &callee).is_some() {
                 self.diagnostics.push(BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap {
@@ -186,27 +197,20 @@
             }
 
             if let Some(receiver_ty) = self.infer.type_of_expr_with_adjust(*receiver) {
-                checker.prev_receiver_ty = Some(receiver_ty.to_chalk(self.interner));
+                checker.prev_receiver_ty = Some(receiver_ty);
             }
         }
     }
 
-    fn validate_match(
-        &mut self,
-        match_expr: ExprId,
-        scrutinee_expr: ExprId,
-        arms: &[MatchArm],
-        db: &dyn HirDatabase,
-    ) {
+    fn validate_match(&mut self, match_expr: ExprId, scrutinee_expr: ExprId, arms: &[MatchArm]) {
         let Some(scrut_ty) = self.infer.type_of_expr_with_adjust(scrutinee_expr) else {
             return;
         };
-        let scrut_ty = scrut_ty.to_chalk(self.interner);
-        if scrut_ty.contains_unknown() {
+        if scrut_ty.references_non_lt_error() {
             return;
         }
 
-        let cx = MatchCheckCtx::new(self.owner.module(db), self.owner, db, self.env.clone());
+        let cx = MatchCheckCtx::new(self.owner.module(self.db()), &self.infcx, self.env.clone());
 
         let pattern_arena = Arena::new();
         let mut m_arms = Vec::with_capacity(arms.len());
@@ -217,8 +221,7 @@
             let Some(pat_ty) = self.infer.type_of_pat_with_adjust(arm.pat) else {
                 return;
             };
-            let pat_ty = pat_ty.to_chalk(self.interner);
-            if pat_ty.contains_unknown() {
+            if pat_ty.references_non_lt_error() {
                 return;
             }
 
@@ -235,14 +238,14 @@
             if (pat_ty == scrut_ty
                 || scrut_ty
                     .as_reference()
-                    .map(|(match_expr_ty, ..)| *match_expr_ty == pat_ty)
+                    .map(|(match_expr_ty, ..)| match_expr_ty == pat_ty)
                     .unwrap_or(false))
                 && types_of_subpatterns_do_match(arm.pat, &self.body, &self.infer)
             {
                 // If we had a NotUsefulMatchArm diagnostic, we could
                 // check the usefulness of each pattern as we added it
                 // to the matrix here.
-                let pat = self.lower_pattern(&cx, arm.pat, db, &mut has_lowering_errors);
+                let pat = self.lower_pattern(&cx, arm.pat, &mut has_lowering_errors);
                 let m_arm = pat_analysis::MatchArm {
                     pat: pattern_arena.alloc(pat),
                     has_guard: arm.guard.is_some(),
@@ -258,15 +261,12 @@
             return;
         }
 
-        let known_valid_scrutinee = Some(self.is_known_valid_scrutinee(scrutinee_expr, db));
-        let report = match cx.compute_match_usefulness(
-            m_arms.as_slice(),
-            scrut_ty.clone(),
-            known_valid_scrutinee,
-        ) {
-            Ok(report) => report,
-            Err(()) => return,
-        };
+        let known_valid_scrutinee = Some(self.is_known_valid_scrutinee(scrutinee_expr));
+        let report =
+            match cx.compute_match_usefulness(m_arms.as_slice(), scrut_ty, known_valid_scrutinee) {
+                Ok(report) => report,
+                Err(()) => return,
+            };
 
         // FIXME Report unreachable arms
         // https://github.com/rust-lang/rust/blob/f31622a50/compiler/rustc_mir_build/src/thir/pattern/check_match.rs#L200
@@ -277,10 +277,10 @@
                 match_expr,
                 uncovered_patterns: missing_match_arms(
                     &cx,
-                    &scrut_ty,
+                    scrut_ty,
                     witnesses,
                     m_arms.is_empty(),
-                    self.owner.krate(db),
+                    self.owner.krate(self.db()),
                 ),
             });
         }
@@ -291,7 +291,9 @@
     // While the above function in rustc uses thir exprs, r-a doesn't have them.
     // So, the logic here is getting same result as "hir lowering + match with lowered thir"
     // with "hir only"
-    fn is_known_valid_scrutinee(&self, scrutinee_expr: ExprId, db: &dyn HirDatabase) -> bool {
+    fn is_known_valid_scrutinee(&self, scrutinee_expr: ExprId) -> bool {
+        let db = self.db();
+
         if self
             .infer
             .expr_adjustments
@@ -311,20 +313,18 @@
                 );
                 value_or_partial.is_none_or(|v| !matches!(v, ValueNs::StaticId(_)))
             }
-            Expr::Field { expr, .. } => {
-                match self.infer.type_of_expr[*expr].to_chalk(self.interner).kind(Interner) {
-                    TyKind::Adt(adt, ..) if matches!(adt.0, AdtId::UnionId(_)) => false,
-                    _ => self.is_known_valid_scrutinee(*expr, db),
-                }
-            }
-            Expr::Index { base, .. } => self.is_known_valid_scrutinee(*base, db),
-            Expr::Cast { expr, .. } => self.is_known_valid_scrutinee(*expr, db),
+            Expr::Field { expr, .. } => match self.infer.type_of_expr[*expr].kind() {
+                TyKind::Adt(adt, ..) if matches!(adt.def_id().0, AdtId::UnionId(_)) => false,
+                _ => self.is_known_valid_scrutinee(*expr),
+            },
+            Expr::Index { base, .. } => self.is_known_valid_scrutinee(*base),
+            Expr::Cast { expr, .. } => self.is_known_valid_scrutinee(*expr),
             Expr::Missing => false,
             _ => true,
         }
     }
 
-    fn validate_block(&mut self, db: &dyn HirDatabase, expr: &Expr) {
+    fn validate_block(&mut self, expr: &Expr) {
         let (Expr::Block { statements, .. }
         | Expr::Async { statements, .. }
         | Expr::Unsafe { statements, .. }) = expr
@@ -332,7 +332,7 @@
             return;
         };
         let pattern_arena = Arena::new();
-        let cx = MatchCheckCtx::new(self.owner.module(db), self.owner, db, self.env.clone());
+        let cx = MatchCheckCtx::new(self.owner.module(self.db()), &self.infcx, self.env.clone());
         for stmt in &**statements {
             let &Statement::Let { pat, initializer, else_branch: None, .. } = stmt else {
                 continue;
@@ -342,13 +342,12 @@
             }
             let Some(initializer) = initializer else { continue };
             let Some(ty) = self.infer.type_of_expr_with_adjust(initializer) else { continue };
-            let ty = ty.to_chalk(self.interner);
-            if ty.contains_unknown() {
+            if ty.references_non_lt_error() {
                 continue;
             }
 
             let mut have_errors = false;
-            let deconstructed_pat = self.lower_pattern(&cx, pat, db, &mut have_errors);
+            let deconstructed_pat = self.lower_pattern(&cx, pat, &mut have_errors);
 
             // optimization, wildcard trivially hold
             if have_errors || matches!(deconstructed_pat.ctor(), Constructor::Wildcard) {
@@ -360,7 +359,7 @@
                 has_guard: false,
                 arm_data: (),
             };
-            let report = match cx.compute_match_usefulness(&[match_arm], ty.clone(), None) {
+            let report = match cx.compute_match_usefulness(&[match_arm], ty, None) {
                 Ok(v) => v,
                 Err(e) => {
                     debug!(?e, "match usefulness error");
@@ -373,24 +372,23 @@
                     pat,
                     uncovered_patterns: missing_match_arms(
                         &cx,
-                        &ty,
+                        ty,
                         witnesses,
                         false,
-                        self.owner.krate(db),
+                        self.owner.krate(self.db()),
                     ),
                 });
             }
         }
     }
 
-    fn lower_pattern<'p>(
+    fn lower_pattern<'a>(
         &self,
-        cx: &MatchCheckCtx<'p>,
+        cx: &MatchCheckCtx<'a, 'db>,
         pat: PatId,
-        db: &dyn HirDatabase,
         have_errors: &mut bool,
-    ) -> DeconstructedPat<'p> {
-        let mut patcx = match_check::PatCtxt::new(db, &self.infer, &self.body);
+    ) -> DeconstructedPat<'a, 'db> {
+        let mut patcx = match_check::PatCtxt::new(self.db(), &self.infer, &self.body);
         let pattern = patcx.lower_pattern(pat);
         let pattern = cx.lower_pat(&pattern);
         if !patcx.errors.is_empty() {
@@ -434,7 +432,7 @@
         }
     }
 
-    fn check_for_unnecessary_else(&mut self, id: ExprId, expr: &Expr, db: &dyn HirDatabase) {
+    fn check_for_unnecessary_else(&mut self, id: ExprId, expr: &Expr) {
         if !self.validate_lints {
             return;
         }
@@ -453,11 +451,11 @@
                     && last_then_expr_ty.is_never()
                 {
                     // Only look at sources if the then branch diverges and we have an else branch.
-                    let source_map = db.body_with_source_map(self.owner).1;
+                    let source_map = self.db().body_with_source_map(self.owner).1;
                     let Ok(source_ptr) = source_map.expr_syntax(id) else {
                         return;
                     };
-                    let root = source_ptr.file_syntax(db);
+                    let root = source_ptr.file_syntax(self.db());
                     let either::Left(ast::Expr::IfExpr(if_expr)) = source_ptr.value.to_node(&root)
                     else {
                         return;
@@ -491,15 +489,15 @@
     }
 }
 
-struct FilterMapNextChecker {
+struct FilterMapNextChecker<'db> {
     filter_map_function_id: Option<hir_def::FunctionId>,
     next_function_id: Option<hir_def::FunctionId>,
     prev_filter_map_expr_id: Option<ExprId>,
-    prev_receiver_ty: Option<chalk_ir::Ty<Interner>>,
+    prev_receiver_ty: Option<Ty<'db>>,
 }
 
-impl FilterMapNextChecker {
-    fn new(resolver: &hir_def::resolver::Resolver<'_>, db: &dyn HirDatabase) -> Self {
+impl<'db> FilterMapNextChecker<'db> {
+    fn new(resolver: &hir_def::resolver::Resolver<'db>, db: &'db dyn HirDatabase) -> Self {
         // Find and store the FunctionIds for Iterator::filter_map and Iterator::next
         let (next_function_id, filter_map_function_id) = match LangItem::IteratorNext
             .resolve_function(db, resolver.krate())
@@ -639,15 +637,19 @@
     !has_type_mismatches
 }
 
-fn missing_match_arms<'p>(
-    cx: &MatchCheckCtx<'p>,
-    scrut_ty: &Ty,
-    witnesses: Vec<WitnessPat<'p>>,
+fn missing_match_arms<'a, 'db>(
+    cx: &MatchCheckCtx<'a, 'db>,
+    scrut_ty: Ty<'a>,
+    witnesses: Vec<WitnessPat<'a, 'db>>,
     arms_is_empty: bool,
     krate: Crate,
 ) -> String {
-    struct DisplayWitness<'a, 'p>(&'a WitnessPat<'p>, &'a MatchCheckCtx<'p>, DisplayTarget);
-    impl fmt::Display for DisplayWitness<'_, '_> {
+    struct DisplayWitness<'a, 'b, 'db>(
+        &'a WitnessPat<'b, 'db>,
+        &'a MatchCheckCtx<'b, 'db>,
+        DisplayTarget,
+    );
+    impl fmt::Display for DisplayWitness<'_, '_, '_> {
         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             let DisplayWitness(witness, cx, display_target) = *self;
             let pat = cx.hoist_witness_pat(witness);
diff --git a/crates/hir-ty/src/diagnostics/match_check.rs b/crates/hir-ty/src/diagnostics/match_check.rs
index af541ff..80b65ac 100644
--- a/crates/hir-ty/src/diagnostics/match_check.rs
+++ b/crates/hir-ty/src/diagnostics/match_check.rs
@@ -9,7 +9,6 @@
 
 pub(crate) mod pat_analysis;
 
-use chalk_ir::Mutability;
 use hir_def::{
     AdtId, EnumVariantId, LocalFieldId, Lookup, VariantId,
     expr_store::{Body, path::Path},
@@ -17,16 +16,16 @@
     item_tree::FieldsShape,
 };
 use hir_expand::name::Name;
+use rustc_type_ir::inherent::{IntoKind, SliceLike};
 use span::Edition;
-use stdx::{always, never};
+use stdx::{always, never, variance::PhantomCovariantLifetime};
 
-use crate::next_solver::DbInterner;
-use crate::next_solver::mapping::NextSolverToChalk;
 use crate::{
-    InferenceResult, Interner, Substitution, Ty, TyExt, TyKind,
+    InferenceResult,
     db::HirDatabase,
     display::{HirDisplay, HirDisplayError, HirFormatter},
     infer::BindingMode,
+    next_solver::{GenericArgs, Mutability, Ty, TyKind},
 };
 
 use self::pat_util::EnumerateAndAdjustIterator;
@@ -41,46 +40,46 @@
 }
 
 #[derive(Clone, Debug, PartialEq)]
-pub(crate) struct FieldPat {
+pub(crate) struct FieldPat<'db> {
     pub(crate) field: LocalFieldId,
-    pub(crate) pattern: Pat,
+    pub(crate) pattern: Pat<'db>,
 }
 
 #[derive(Clone, Debug, PartialEq)]
-pub(crate) struct Pat {
-    pub(crate) ty: Ty,
-    pub(crate) kind: Box<PatKind>,
+pub(crate) struct Pat<'db> {
+    pub(crate) ty: Ty<'db>,
+    pub(crate) kind: Box<PatKind<'db>>,
 }
 
 /// Close relative to `rustc_mir_build::thir::pattern::PatKind`
 #[derive(Clone, Debug, PartialEq)]
-pub(crate) enum PatKind {
+pub(crate) enum PatKind<'db> {
     Wild,
     Never,
 
     /// `x`, `ref x`, `x @ P`, etc.
     Binding {
         name: Name,
-        subpattern: Option<Pat>,
+        subpattern: Option<Pat<'db>>,
     },
 
     /// `Foo(...)` or `Foo{...}` or `Foo`, where `Foo` is a variant name from an ADT with
     /// multiple variants.
     Variant {
-        substs: Substitution,
+        substs: GenericArgs<'db>,
         enum_variant: EnumVariantId,
-        subpatterns: Vec<FieldPat>,
+        subpatterns: Vec<FieldPat<'db>>,
     },
 
     /// `(...)`, `Foo(...)`, `Foo{...}`, or `Foo`, where `Foo` is a variant name from an ADT with
     /// a single variant.
     Leaf {
-        subpatterns: Vec<FieldPat>,
+        subpatterns: Vec<FieldPat<'db>>,
     },
 
     /// `&P`, `&mut P`, etc.
     Deref {
-        subpattern: Pat,
+        subpattern: Pat<'db>,
     },
 
     // FIXME: for now, only bool literals are implemented
@@ -91,28 +90,27 @@
     /// An or-pattern, e.g. `p | q`.
     /// Invariant: `pats.len() >= 2`.
     Or {
-        pats: Vec<Pat>,
+        pats: Vec<Pat<'db>>,
     },
 }
 
-pub(crate) struct PatCtxt<'db> {
+pub(crate) struct PatCtxt<'a, 'db> {
     db: &'db dyn HirDatabase,
-    infer: &'db InferenceResult<'db>,
-    body: &'db Body,
+    infer: &'a InferenceResult<'db>,
+    body: &'a Body,
     pub(crate) errors: Vec<PatternError>,
-    interner: DbInterner<'db>,
 }
 
-impl<'a> PatCtxt<'a> {
+impl<'a, 'db> PatCtxt<'a, 'db> {
     pub(crate) fn new(
-        db: &'a dyn HirDatabase,
-        infer: &'a InferenceResult<'a>,
+        db: &'db dyn HirDatabase,
+        infer: &'a InferenceResult<'db>,
         body: &'a Body,
     ) -> Self {
-        Self { db, infer, body, errors: Vec::new(), interner: DbInterner::new_with(db, None, None) }
+        Self { db, infer, body, errors: Vec::new() }
     }
 
-    pub(crate) fn lower_pattern(&mut self, pat: PatId) -> Pat {
+    pub(crate) fn lower_pattern(&mut self, pat: PatId) -> Pat<'db> {
         // XXX(iDawer): Collecting pattern adjustments feels imprecise to me.
         // When lowering of & and box patterns are implemented this should be tested
         // in a manner of `match_ergonomics_issue_9095` test.
@@ -121,15 +119,12 @@
         let unadjusted_pat = self.lower_pattern_unadjusted(pat);
         self.infer.pat_adjustments.get(&pat).map(|it| &**it).unwrap_or_default().iter().rev().fold(
             unadjusted_pat,
-            |subpattern, ref_ty| Pat {
-                ty: ref_ty.to_chalk(self.interner).clone(),
-                kind: Box::new(PatKind::Deref { subpattern }),
-            },
+            |subpattern, ref_ty| Pat { ty: *ref_ty, kind: Box::new(PatKind::Deref { subpattern }) },
         )
     }
 
-    fn lower_pattern_unadjusted(&mut self, pat: PatId) -> Pat {
-        let mut ty = self.infer[pat].to_chalk(self.interner);
+    fn lower_pattern_unadjusted(&mut self, pat: PatId) -> Pat<'db> {
+        let mut ty = self.infer[pat];
         let variant = self.infer.variant_resolution_for_pat(pat);
 
         let kind = match self.body[pat] {
@@ -142,8 +137,8 @@
             }
 
             hir_def::hir::Pat::Tuple { ref args, ellipsis } => {
-                let arity = match *ty.kind(Interner) {
-                    TyKind::Tuple(arity, _) => arity,
+                let arity = match ty.kind() {
+                    TyKind::Tuple(tys) => tys.len(),
                     _ => {
                         never!("unexpected type for tuple pattern: {:?}", ty);
                         self.errors.push(PatternError::UnexpectedType);
@@ -156,10 +151,10 @@
 
             hir_def::hir::Pat::Bind { id, subpat, .. } => {
                 let bm = self.infer.binding_modes[pat];
-                ty = self.infer[id].to_chalk(self.interner);
+                ty = self.infer[id];
                 let name = &self.body[id].name;
-                match (bm, ty.kind(Interner)) {
-                    (BindingMode::Ref(_), TyKind::Ref(.., rty)) => ty = rty.clone(),
+                match (bm, ty.kind()) {
+                    (BindingMode::Ref(_), TyKind::Ref(_, rty, _)) => ty = rty,
                     (BindingMode::Ref(_), _) => {
                         never!(
                             "`ref {}` has wrong type {:?}",
@@ -167,7 +162,7 @@
                             ty
                         );
                         self.errors.push(PatternError::UnexpectedType);
-                        return Pat { ty: ty.clone(), kind: PatKind::Wild.into() };
+                        return Pat { ty, kind: PatKind::Wild.into() };
                     }
                     _ => (),
                 }
@@ -177,7 +172,7 @@
             hir_def::hir::Pat::TupleStruct { ref args, ellipsis, .. } if variant.is_some() => {
                 let expected_len = variant.unwrap().fields(self.db).fields().len();
                 let subpatterns = self.lower_tuple_subpats(args, expected_len, ellipsis);
-                self.lower_variant_or_leaf(pat, &ty, subpatterns)
+                self.lower_variant_or_leaf(pat, ty, subpatterns)
             }
 
             hir_def::hir::Pat::Record { ref args, .. } if variant.is_some() => {
@@ -193,7 +188,7 @@
                     })
                     .collect();
                 match subpatterns {
-                    Some(subpatterns) => self.lower_variant_or_leaf(pat, &ty, subpatterns),
+                    Some(subpatterns) => self.lower_variant_or_leaf(pat, ty, subpatterns),
                     None => {
                         self.errors.push(PatternError::MissingField);
                         PatKind::Wild
@@ -213,7 +208,7 @@
             }
         };
 
-        Pat { ty: ty.clone(), kind: Box::new(kind) }
+        Pat { ty, kind: Box::new(kind) }
     }
 
     fn lower_tuple_subpats(
@@ -221,7 +216,7 @@
         pats: &[PatId],
         expected_len: usize,
         ellipsis: Option<u32>,
-    ) -> Vec<FieldPat> {
+    ) -> Vec<FieldPat<'db>> {
         if pats.len() > expected_len {
             self.errors.push(PatternError::ExtraFields);
             return Vec::new();
@@ -236,28 +231,28 @@
             .collect()
     }
 
-    fn lower_patterns(&mut self, pats: &[PatId]) -> Vec<Pat> {
+    fn lower_patterns(&mut self, pats: &[PatId]) -> Vec<Pat<'db>> {
         pats.iter().map(|&p| self.lower_pattern(p)).collect()
     }
 
-    fn lower_opt_pattern(&mut self, pat: Option<PatId>) -> Option<Pat> {
+    fn lower_opt_pattern(&mut self, pat: Option<PatId>) -> Option<Pat<'db>> {
         pat.map(|p| self.lower_pattern(p))
     }
 
     fn lower_variant_or_leaf(
         &mut self,
         pat: PatId,
-        ty: &Ty,
-        subpatterns: Vec<FieldPat>,
-    ) -> PatKind {
+        ty: Ty<'db>,
+        subpatterns: Vec<FieldPat<'db>>,
+    ) -> PatKind<'db> {
         match self.infer.variant_resolution_for_pat(pat) {
             Some(variant_id) => {
                 if let VariantId::EnumVariantId(enum_variant) = variant_id {
-                    let substs = match ty.kind(Interner) {
-                        TyKind::Adt(_, substs) => substs.clone(),
+                    let substs = match ty.kind() {
+                        TyKind::Adt(_, substs) => substs,
                         kind => {
                             always!(
-                                matches!(kind, TyKind::FnDef(..) | TyKind::Error),
+                                matches!(kind, TyKind::FnDef(..) | TyKind::Error(_)),
                                 "inappropriate type for def: {:?}",
                                 ty
                             );
@@ -277,13 +272,13 @@
         }
     }
 
-    fn lower_path(&mut self, pat: PatId, _path: &Path) -> Pat {
-        let ty = self.infer[pat].to_chalk(self.interner);
+    fn lower_path(&mut self, pat: PatId, _path: &Path) -> Pat<'db> {
+        let ty = self.infer[pat];
 
-        let pat_from_kind = |kind| Pat { ty: ty.clone(), kind: Box::new(kind) };
+        let pat_from_kind = |kind| Pat { ty, kind: Box::new(kind) };
 
         match self.infer.variant_resolution_for_pat(pat) {
-            Some(_) => pat_from_kind(self.lower_variant_or_leaf(pat, &ty, Vec::new())),
+            Some(_) => pat_from_kind(self.lower_variant_or_leaf(pat, ty, Vec::new())),
             None => {
                 self.errors.push(PatternError::UnresolvedVariant);
                 pat_from_kind(PatKind::Wild)
@@ -291,7 +286,7 @@
         }
     }
 
-    fn lower_lit(&mut self, expr: hir_def::hir::ExprId) -> PatKind {
+    fn lower_lit(&mut self, expr: hir_def::hir::ExprId) -> PatKind<'db> {
         use hir_def::hir::{Expr, Literal::Bool};
 
         match self.body[expr] {
@@ -304,8 +299,8 @@
     }
 }
 
-impl HirDisplay for Pat {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Pat<'db> {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         match &*self.kind {
             PatKind::Wild => write!(f, "_"),
             PatKind::Never => write!(f, "!"),
@@ -361,7 +356,7 @@
                             .filter(|p| !matches!(*p.pattern.kind, PatKind::Wild))
                             .map(|p| {
                                 printed += 1;
-                                WriteWith(|f| {
+                                WriteWith::new(|f| {
                                     write!(
                                         f,
                                         "{}: ",
@@ -387,7 +382,7 @@
                 if num_fields != 0 || variant.is_none() {
                     write!(f, "(")?;
                     let subpats = (0..num_fields).map(|i| {
-                        WriteWith(move |f| {
+                        WriteWith::new(move |f| {
                             let fid = LocalFieldId::from_raw((i as u32).into());
                             if let Some(p) = subpatterns.get(i)
                                 && p.field == fid
@@ -402,7 +397,7 @@
                         })
                     });
                     f.write_joined(subpats, ", ")?;
-                    if let (TyKind::Tuple(..), 1) = (self.ty.kind(Interner), num_fields) {
+                    if let (TyKind::Tuple(..), 1) = (self.ty.kind(), num_fields) {
                         write!(f, ",")?;
                     }
                     write!(f, ")")?;
@@ -411,8 +406,8 @@
                 Ok(())
             }
             PatKind::Deref { subpattern } => {
-                match self.ty.kind(Interner) {
-                    &TyKind::Ref(mutbl, ..) => {
+                match self.ty.kind() {
+                    TyKind::Ref(.., mutbl) => {
                         write!(f, "&{}", if mutbl == Mutability::Mut { "mut " } else { "" })?
                     }
                     _ => never!("{:?} is a bad Deref pattern type", self.ty),
@@ -425,15 +420,24 @@
     }
 }
 
-struct WriteWith<F>(F)
+struct WriteWith<'db, F>(F, PhantomCovariantLifetime<'db>)
 where
-    F: Fn(&mut HirFormatter<'_>) -> Result<(), HirDisplayError>;
+    F: Fn(&mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError>;
 
-impl<F> HirDisplay for WriteWith<F>
+impl<'db, F> WriteWith<'db, F>
 where
-    F: Fn(&mut HirFormatter<'_>) -> Result<(), HirDisplayError>,
+    F: Fn(&mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError>,
 {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+    fn new(f: F) -> Self {
+        Self(f, PhantomCovariantLifetime::new())
+    }
+}
+
+impl<'db, F> HirDisplay<'db> for WriteWith<'db, F>
+where
+    F: Fn(&mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError>,
+{
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         (self.0)(f)
     }
 }
diff --git a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
index eb20d3c..fb942e3 100644
--- a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
+++ b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
@@ -1,24 +1,27 @@
 //! Interface with `rustc_pattern_analysis`.
 
-use std::cell::LazyCell;
-use std::fmt;
+use std::{cell::LazyCell, fmt};
 
-use hir_def::{DefWithBodyId, EnumId, EnumVariantId, HasModule, LocalFieldId, ModuleId, VariantId};
+use hir_def::{EnumId, EnumVariantId, HasModule, LocalFieldId, ModuleId, VariantId};
 use intern::sym;
 use rustc_pattern_analysis::{
     IndexVec, PatCx, PrivateUninhabitedField,
     constructor::{Constructor, ConstructorSet, VariantVisibility},
     usefulness::{PlaceValidity, UsefulnessReport, compute_match_usefulness},
 };
+use rustc_type_ir::inherent::{AdtDef, IntoKind, SliceLike};
 use smallvec::{SmallVec, smallvec};
 use stdx::never;
 use triomphe::Arc;
 
 use crate::{
-    AdtId, Interner, Scalar, TraitEnvironment, Ty, TyExt, TyKind,
+    TraitEnvironment,
     db::HirDatabase,
-    infer::normalize,
     inhabitedness::{is_enum_variant_uninhabited_from, is_ty_uninhabited_from},
+    next_solver::{
+        Ty, TyKind,
+        infer::{InferCtxt, traits::ObligationCause},
+    },
 };
 
 use super::{FieldPat, Pat, PatKind};
@@ -26,10 +29,12 @@
 use Constructor::*;
 
 // Re-export r-a-specific versions of all these types.
-pub(crate) type DeconstructedPat<'db> =
-    rustc_pattern_analysis::pat::DeconstructedPat<MatchCheckCtx<'db>>;
-pub(crate) type MatchArm<'db> = rustc_pattern_analysis::MatchArm<'db, MatchCheckCtx<'db>>;
-pub(crate) type WitnessPat<'db> = rustc_pattern_analysis::pat::WitnessPat<MatchCheckCtx<'db>>;
+pub(crate) type DeconstructedPat<'a, 'db> =
+    rustc_pattern_analysis::pat::DeconstructedPat<MatchCheckCtx<'a, 'db>>;
+pub(crate) type MatchArm<'a, 'b, 'db> =
+    rustc_pattern_analysis::MatchArm<'b, MatchCheckCtx<'a, 'db>>;
+pub(crate) type WitnessPat<'a, 'db> =
+    rustc_pattern_analysis::pat::WitnessPat<MatchCheckCtx<'a, 'db>>;
 
 /// [Constructor] uses this in unimplemented variants.
 /// It allows porting match expressions from upstream algorithm without losing semantics.
@@ -65,37 +70,37 @@
 }
 
 #[derive(Clone)]
-pub(crate) struct MatchCheckCtx<'db> {
+pub(crate) struct MatchCheckCtx<'a, 'db> {
     module: ModuleId,
-    body: DefWithBodyId,
     pub(crate) db: &'db dyn HirDatabase,
     exhaustive_patterns: bool,
     env: Arc<TraitEnvironment<'db>>,
+    infcx: &'a InferCtxt<'db>,
 }
 
-impl<'db> MatchCheckCtx<'db> {
+impl<'a, 'db> MatchCheckCtx<'a, 'db> {
     pub(crate) fn new(
         module: ModuleId,
-        body: DefWithBodyId,
-        db: &'db dyn HirDatabase,
+        infcx: &'a InferCtxt<'db>,
         env: Arc<TraitEnvironment<'db>>,
     ) -> Self {
+        let db = infcx.interner.db;
         let def_map = module.crate_def_map(db);
         let exhaustive_patterns = def_map.is_unstable_feature_enabled(&sym::exhaustive_patterns);
-        Self { module, body, db, exhaustive_patterns, env }
+        Self { module, db, exhaustive_patterns, env, infcx }
     }
 
-    pub(crate) fn compute_match_usefulness(
+    pub(crate) fn compute_match_usefulness<'b>(
         &self,
-        arms: &[MatchArm<'db>],
-        scrut_ty: Ty,
+        arms: &[MatchArm<'a, 'b, 'db>],
+        scrut_ty: Ty<'db>,
         known_valid_scrutinee: Option<bool>,
-    ) -> Result<UsefulnessReport<'db, Self>, ()> {
-        if scrut_ty.contains_unknown() {
+    ) -> Result<UsefulnessReport<'b, Self>, ()> {
+        if scrut_ty.references_non_lt_error() {
             return Err(());
         }
         for arm in arms {
-            if arm.pat.ty().contains_unknown() {
+            if arm.pat.ty().references_non_lt_error() {
                 return Err(());
             }
         }
@@ -106,8 +111,8 @@
         compute_match_usefulness(self, arms, scrut_ty, place_validity, complexity_limit)
     }
 
-    fn is_uninhabited(&self, ty: &Ty) -> bool {
-        is_ty_uninhabited_from(self.db, ty, self.module, self.env.clone())
+    fn is_uninhabited(&self, ty: Ty<'db>) -> bool {
+        is_ty_uninhabited_from(self.infcx, ty, self.module, self.env.clone())
     }
 
     /// Returns whether the given ADT is from another crate declared `#[non_exhaustive]`.
@@ -140,23 +145,27 @@
     // This lists the fields of a variant along with their types.
     fn list_variant_fields(
         &self,
-        ty: &Ty,
+        ty: Ty<'db>,
         variant: VariantId,
-    ) -> impl Iterator<Item = (LocalFieldId, Ty)> {
+    ) -> impl Iterator<Item = (LocalFieldId, Ty<'db>)> {
         let (_, substs) = ty.as_adt().unwrap();
 
         let field_tys = self.db.field_types(variant);
         let fields_len = variant.fields(self.db).fields().len() as u32;
 
         (0..fields_len).map(|idx| LocalFieldId::from_raw(idx.into())).map(move |fid| {
-            let ty = field_tys[fid].clone().substitute(Interner, substs);
-            let ty = normalize(self.db, self.db.trait_environment_for_body(self.body), ty);
+            let ty = field_tys[fid].instantiate(self.infcx.interner, substs);
+            let ty = self
+                .infcx
+                .at(&ObligationCause::dummy(), self.env.env)
+                .deeply_normalize(ty)
+                .unwrap_or(ty);
             (fid, ty)
         })
     }
 
-    pub(crate) fn lower_pat(&self, pat: &Pat) -> DeconstructedPat<'db> {
-        let singleton = |pat: DeconstructedPat<'db>| vec![pat.at_index(0)];
+    pub(crate) fn lower_pat(&self, pat: &Pat<'db>) -> DeconstructedPat<'a, 'db> {
+        let singleton = |pat: DeconstructedPat<'a, 'db>| vec![pat.at_index(0)];
         let ctor;
         let mut fields: Vec<_>;
         let arity;
@@ -169,7 +178,7 @@
                 arity = 0;
             }
             PatKind::Deref { subpattern } => {
-                ctor = match pat.ty.kind(Interner) {
+                ctor = match pat.ty.kind() {
                     TyKind::Ref(..) => Ref,
                     _ => {
                         never!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, &pat.ty);
@@ -187,12 +196,13 @@
                         self.lower_pat(&pat.pattern).at_index(idx as usize)
                     })
                     .collect();
-                match pat.ty.kind(Interner) {
-                    TyKind::Tuple(_, substs) => {
+                match pat.ty.kind() {
+                    TyKind::Tuple(substs) => {
                         ctor = Struct;
-                        arity = substs.len(Interner);
+                        arity = substs.len();
                     }
-                    &TyKind::Adt(AdtId(adt), _) => {
+                    TyKind::Adt(adt_def, _) => {
+                        let adt = adt_def.def_id().0;
                         ctor = match pat.kind.as_ref() {
                             PatKind::Leaf { .. } if matches!(adt, hir_def::AdtId::UnionId(_)) => {
                                 UnionField
@@ -240,15 +250,15 @@
                 arity = pats.len();
             }
         }
-        DeconstructedPat::new(ctor, fields, arity, pat.ty.clone(), ())
+        DeconstructedPat::new(ctor, fields, arity, pat.ty, ())
     }
 
-    pub(crate) fn hoist_witness_pat(&self, pat: &WitnessPat<'db>) -> Pat {
+    pub(crate) fn hoist_witness_pat(&self, pat: &WitnessPat<'a, 'db>) -> Pat<'db> {
         let mut subpatterns = pat.iter_fields().map(|p| self.hoist_witness_pat(p));
         let kind = match pat.ctor() {
             &Bool(value) => PatKind::LiteralBool { value },
             IntRange(_) => unimplemented!(),
-            Struct | Variant(_) | UnionField => match pat.ty().kind(Interner) {
+            Struct | Variant(_) | UnionField => match pat.ty().kind() {
                 TyKind::Tuple(..) => PatKind::Leaf {
                     subpatterns: subpatterns
                         .zip(0u32..)
@@ -259,15 +269,16 @@
                         .collect(),
                 },
                 TyKind::Adt(adt, substs) => {
-                    let variant = Self::variant_id_for_adt(self.db, pat.ctor(), adt.0).unwrap();
+                    let variant =
+                        Self::variant_id_for_adt(self.db, pat.ctor(), adt.def_id().0).unwrap();
                     let subpatterns = self
-                        .list_variant_fields(pat.ty(), variant)
+                        .list_variant_fields(*pat.ty(), variant)
                         .zip(subpatterns)
                         .map(|((field, _ty), pattern)| FieldPat { field, pattern })
                         .collect();
 
                     if let VariantId::EnumVariantId(enum_variant) = variant {
-                        PatKind::Variant { substs: substs.clone(), enum_variant, subpatterns }
+                        PatKind::Variant { substs, enum_variant, subpatterns }
                     } else {
                         PatKind::Leaf { subpatterns }
                     }
@@ -293,13 +304,13 @@
                 PatKind::Wild
             }
         };
-        Pat { ty: pat.ty().clone(), kind: Box::new(kind) }
+        Pat { ty: *pat.ty(), kind: Box::new(kind) }
     }
 }
 
-impl PatCx for MatchCheckCtx<'_> {
+impl<'a, 'db> PatCx for MatchCheckCtx<'a, 'db> {
     type Error = ();
-    type Ty = Ty;
+    type Ty = Ty<'db>;
     type VariantIdx = EnumVariantContiguousIndex;
     type StrLit = Void;
     type ArmData = ();
@@ -315,10 +326,11 @@
         ty: &Self::Ty,
     ) -> usize {
         match ctor {
-            Struct | Variant(_) | UnionField => match *ty.kind(Interner) {
-                TyKind::Tuple(arity, ..) => arity,
-                TyKind::Adt(AdtId(adt), ..) => {
-                    let variant = Self::variant_id_for_adt(self.db, ctor, adt).unwrap();
+            Struct | Variant(_) | UnionField => match ty.kind() {
+                TyKind::Tuple(tys) => tys.len(),
+                TyKind::Adt(adt_def, ..) => {
+                    let variant =
+                        Self::variant_id_for_adt(self.db, ctor, adt_def.def_id().0).unwrap();
                     variant.fields(self.db).fields().len()
                 }
                 _ => {
@@ -346,24 +358,24 @@
     ) -> impl ExactSizeIterator<Item = (Self::Ty, PrivateUninhabitedField)> {
         let single = |ty| smallvec![(ty, PrivateUninhabitedField(false))];
         let tys: SmallVec<[_; 2]> = match ctor {
-            Struct | Variant(_) | UnionField => match ty.kind(Interner) {
-                TyKind::Tuple(_, substs) => {
-                    let tys = substs.iter(Interner).map(|ty| ty.assert_ty_ref(Interner));
-                    tys.cloned().map(|ty| (ty, PrivateUninhabitedField(false))).collect()
+            Struct | Variant(_) | UnionField => match ty.kind() {
+                TyKind::Tuple(substs) => {
+                    substs.iter().map(|ty| (ty, PrivateUninhabitedField(false))).collect()
                 }
-                TyKind::Ref(.., rty) => single(rty.clone()),
-                &TyKind::Adt(AdtId(adt), ..) => {
+                TyKind::Ref(_, rty, _) => single(rty),
+                TyKind::Adt(adt_def, ..) => {
+                    let adt = adt_def.def_id().0;
                     let variant = Self::variant_id_for_adt(self.db, ctor, adt).unwrap();
 
                     let visibilities = LazyCell::new(|| self.db.field_visibilities(variant));
 
-                    self.list_variant_fields(ty, variant)
+                    self.list_variant_fields(*ty, variant)
                         .map(move |(fid, ty)| {
                             let is_visible = || {
                                 matches!(adt, hir_def::AdtId::EnumId(..))
                                     || visibilities[fid].is_visible_from(self.db, self.module)
                             };
-                            let is_uninhabited = self.is_uninhabited(&ty);
+                            let is_uninhabited = self.is_uninhabited(ty);
                             let private_uninhabited = is_uninhabited && !is_visible();
                             (ty, PrivateUninhabitedField(private_uninhabited))
                         })
@@ -371,14 +383,14 @@
                 }
                 ty_kind => {
                     never!("Unexpected type for `{:?}` constructor: {:?}", ctor, ty_kind);
-                    single(ty.clone())
+                    single(*ty)
                 }
             },
-            Ref => match ty.kind(Interner) {
-                TyKind::Ref(.., rty) => single(rty.clone()),
+            Ref => match ty.kind() {
+                TyKind::Ref(_, rty, _) => single(rty),
                 ty_kind => {
                     never!("Unexpected type for `{:?}` constructor: {:?}", ctor, ty_kind);
-                    single(ty.clone())
+                    single(*ty)
                 }
             },
             Slice(_) => unreachable!("Found a `Slice` constructor in match checking"),
@@ -414,42 +426,51 @@
         // returned list of constructors.
         // Invariant: this is empty if and only if the type is uninhabited (as determined by
         // `cx.is_uninhabited()`).
-        Ok(match ty.kind(Interner) {
-            TyKind::Scalar(Scalar::Bool) => ConstructorSet::Bool,
-            TyKind::Scalar(Scalar::Char) => unhandled(),
-            TyKind::Scalar(Scalar::Int(..) | Scalar::Uint(..)) => unhandled(),
+        Ok(match ty.kind() {
+            TyKind::Bool => ConstructorSet::Bool,
+            TyKind::Char => unhandled(),
+            TyKind::Int(..) | TyKind::Uint(..) => unhandled(),
             TyKind::Array(..) | TyKind::Slice(..) => unhandled(),
-            &TyKind::Adt(AdtId(adt @ hir_def::AdtId::EnumId(enum_id)), ref subst) => {
-                let enum_data = enum_id.enum_variants(cx.db);
-                let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive(adt);
+            TyKind::Adt(adt_def, subst) => {
+                let adt = adt_def.def_id().0;
+                match adt {
+                    hir_def::AdtId::EnumId(enum_id) => {
+                        let enum_data = enum_id.enum_variants(cx.db);
+                        let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive(adt);
 
-                if enum_data.variants.is_empty() && !is_declared_nonexhaustive {
-                    ConstructorSet::NoConstructors
-                } else {
-                    let mut variants = IndexVec::with_capacity(enum_data.variants.len());
-                    for &(variant, _, _) in enum_data.variants.iter() {
-                        let is_uninhabited = is_enum_variant_uninhabited_from(
-                            cx.db,
-                            variant,
-                            subst,
-                            cx.module,
-                            self.env.clone(),
-                        );
-                        let visibility = if is_uninhabited {
-                            VariantVisibility::Empty
+                        if enum_data.variants.is_empty() && !is_declared_nonexhaustive {
+                            ConstructorSet::NoConstructors
                         } else {
-                            VariantVisibility::Visible
-                        };
-                        variants.push(visibility);
-                    }
+                            let mut variants = IndexVec::with_capacity(enum_data.variants.len());
+                            for &(variant, _, _) in enum_data.variants.iter() {
+                                let is_uninhabited = is_enum_variant_uninhabited_from(
+                                    cx.infcx,
+                                    variant,
+                                    subst,
+                                    cx.module,
+                                    self.env.clone(),
+                                );
+                                let visibility = if is_uninhabited {
+                                    VariantVisibility::Empty
+                                } else {
+                                    VariantVisibility::Visible
+                                };
+                                variants.push(visibility);
+                            }
 
-                    ConstructorSet::Variants { variants, non_exhaustive: is_declared_nonexhaustive }
+                            ConstructorSet::Variants {
+                                variants,
+                                non_exhaustive: is_declared_nonexhaustive,
+                            }
+                        }
+                    }
+                    hir_def::AdtId::UnionId(_) => ConstructorSet::Union,
+                    hir_def::AdtId::StructId(_) => {
+                        ConstructorSet::Struct { empty: cx.is_uninhabited(*ty) }
+                    }
                 }
             }
-            TyKind::Adt(AdtId(hir_def::AdtId::UnionId(_)), _) => ConstructorSet::Union,
-            TyKind::Adt(..) | TyKind::Tuple(..) => {
-                ConstructorSet::Struct { empty: cx.is_uninhabited(ty) }
-            }
+            TyKind::Tuple(..) => ConstructorSet::Struct { empty: cx.is_uninhabited(*ty) },
             TyKind::Ref(..) => ConstructorSet::Ref,
             TyKind::Never => ConstructorSet::NoConstructors,
             // This type is one for which we cannot list constructors, like `str` or `f64`.
@@ -492,14 +513,14 @@
 
     fn report_mixed_deref_pat_ctors(
         &self,
-        _deref_pat: &DeconstructedPat<'_>,
-        _normal_pat: &DeconstructedPat<'_>,
+        _deref_pat: &DeconstructedPat<'a, 'db>,
+        _normal_pat: &DeconstructedPat<'a, 'db>,
     ) {
         // FIXME(deref_patterns): This could report an error comparable to the one in rustc.
     }
 }
 
-impl fmt::Debug for MatchCheckCtx<'_> {
+impl fmt::Debug for MatchCheckCtx<'_, '_> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("MatchCheckCtx").finish()
     }
diff --git a/crates/hir-ty/src/diagnostics/unsafe_check.rs b/crates/hir-ty/src/diagnostics/unsafe_check.rs
index 31100e1..53524d6 100644
--- a/crates/hir-ty/src/diagnostics/unsafe_check.rs
+++ b/crates/hir-ty/src/diagnostics/unsafe_check.rs
@@ -5,22 +5,21 @@
 
 use either::Either;
 use hir_def::{
-    AdtId, DefWithBodyId, FieldId, FunctionId, VariantId,
+    AdtId, CallableDefId, DefWithBodyId, FieldId, FunctionId, VariantId,
     expr_store::{Body, path::Path},
     hir::{AsmOperand, Expr, ExprId, ExprOrPatId, InlineAsmKind, Pat, PatId, Statement, UnaryOp},
     resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs},
     signatures::StaticFlags,
     type_ref::Rawness,
 };
+use rustc_type_ir::inherent::IntoKind;
 use span::Edition;
 
-use crate::next_solver::DbInterner;
-use crate::next_solver::mapping::NextSolverToChalk;
-use crate::utils::TargetFeatureIsSafeInTarget;
 use crate::{
-    InferenceResult, Interner, TargetFeatures, TyExt, TyKind,
+    InferenceResult, TargetFeatures,
     db::HirDatabase,
-    utils::{is_fn_unsafe_to_call, target_feature_is_safe_in_target},
+    next_solver::{CallableIdWrapper, TyKind, abi::Safety},
+    utils::{TargetFeatureIsSafeInTarget, is_fn_unsafe_to_call, target_feature_is_safe_in_target},
 };
 
 #[derive(Debug, Default)]
@@ -151,7 +150,6 @@
     /// On some targets (WASM), calling safe functions with `#[target_feature]` is always safe, even when
     /// the target feature is not enabled. This flag encodes that.
     target_feature_is_safe: TargetFeatureIsSafeInTarget,
-    interner: DbInterner<'db>,
 }
 
 impl<'db> UnsafeVisitor<'db> {
@@ -186,7 +184,6 @@
             def_target_features,
             edition,
             target_feature_is_safe,
-            interner: DbInterner::new_with(db, None, None),
         }
     }
 
@@ -289,12 +286,14 @@
         let inside_assignment = mem::replace(&mut self.inside_assignment, false);
         match expr {
             &Expr::Call { callee, .. } => {
-                let callee = self.infer[callee].to_chalk(self.interner);
-                if let Some(func) = callee.as_fn_def(self.db) {
+                let callee = self.infer[callee];
+                if let TyKind::FnDef(CallableIdWrapper(CallableDefId::FunctionId(func)), _) =
+                    callee.kind()
+                {
                     self.check_call(current, func);
                 }
-                if let TyKind::Function(fn_ptr) = callee.kind(Interner)
-                    && fn_ptr.sig.safety == chalk_ir::Safety::Unsafe
+                if let TyKind::FnPtr(_, hdr) = callee.kind()
+                    && hdr.safety == Safety::Unsafe
                 {
                     self.on_unsafe_op(current.into(), UnsafetyReason::UnsafeFnCall);
                 }
@@ -342,7 +341,7 @@
                 }
             }
             Expr::UnaryOp { expr, op: UnaryOp::Deref } => {
-                if let TyKind::Raw(..) = &self.infer[*expr].to_chalk(self.interner).kind(Interner) {
+                if let TyKind::RawPtr(..) = self.infer[*expr].kind() {
                     self.on_unsafe_op(current.into(), UnsafetyReason::RawPtrDeref);
                 }
             }
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index bcd93c6..dd1b212 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -8,7 +8,6 @@
 };
 
 use base_db::Crate;
-use chalk_ir::{BoundVar, Safety, TyKind};
 use either::Either;
 use hir_def::{
     FindPathConfig, GeneralConstId, GenericDefId, HasModule, LocalFieldId, Lookup, ModuleDefId,
@@ -36,39 +35,33 @@
     Float,
     ieee::{Half as f16, Quad as f128},
 };
+use rustc_ast_ir::FloatTy;
 use rustc_hash::FxHashSet;
 use rustc_type_ir::{
-    AliasTyKind, CoroutineArgsParts, RegionKind,
-    inherent::{AdtDef, GenericArgs as _, IntoKind, SliceLike},
+    AliasTyKind, BoundVarIndexKind, CoroutineArgsParts, CoroutineClosureArgsParts, RegionKind,
+    Upcast,
+    inherent::{AdtDef, GenericArgs as _, IntoKind, SliceLike, Term as _, Ty as _, Tys as _},
 };
 use smallvec::SmallVec;
 use span::Edition;
 use stdx::never;
 use triomphe::Arc;
 
-use crate::next_solver::infer::traits::ObligationCause;
-use crate::next_solver::{infer::DbInternerInferExt, mapping::NextSolverToChalk};
 use crate::{
-    AliasEq, AliasTy, Binders, CallableDefId, CallableSig, ConcreteConst, Const, ConstScalar,
-    ConstValue, DomainGoal, FnAbi, GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData,
-    LifetimeOutlives, MemoryMap, OpaqueTy, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause,
-    TraitEnvironment, TraitRef, TraitRefExt, Ty, TyExt, WhereClause, consteval,
-    db::{HirDatabase, InternedClosure},
-    from_assoc_type_id, from_placeholder_idx,
+    CallableDefId, FnAbi, ImplTraitId, MemoryMap, TraitEnvironment, consteval,
+    db::{HirDatabase, InternedClosure, InternedCoroutine},
     generics::generics,
-    infer::normalize,
     layout::Layout,
-    lt_from_placeholder_idx,
     mir::pad16,
     next_solver::{
-        BoundExistentialPredicate, DbInterner, GenericArgs, SolverDefId,
-        mapping::{
-            ChalkToNextSolver, convert_args_for_result, convert_const_for_result,
-            convert_region_for_result, convert_ty_for_result,
-        },
+        AliasTy, Clause, ClauseKind, Const, ConstKind, DbInterner, EarlyBinder,
+        ExistentialPredicate, FnSig, GenericArg, GenericArgs, PolyFnSig, Region, SolverDefId, Term,
+        TraitRef, Ty, TyKind, TypingMode,
+        abi::Safety,
+        infer::{DbInternerInferExt, traits::ObligationCause},
     },
-    primitive, to_assoc_type_id,
-    utils::{self, ClosureSubst, detect_variant_from_bytes},
+    primitive,
+    utils::{self, detect_variant_from_bytes},
 };
 
 pub trait HirWrite: fmt::Write {
@@ -82,9 +75,10 @@
 // `core::Formatter` will ignore metadata
 impl HirWrite for fmt::Formatter<'_> {}
 
-pub struct HirFormatter<'a> {
+pub struct HirFormatter<'a, 'db> {
     /// The database handle
-    pub db: &'a dyn HirDatabase,
+    pub db: &'db dyn HirDatabase,
+    pub interner: DbInterner<'db>,
     /// The sink to write into
     fmt: &'a mut dyn HirWrite,
     /// A buffer to intercept writes with, this allows us to track the overall size of the formatted output.
@@ -103,7 +97,7 @@
     display_lifetimes: DisplayLifetime,
     display_kind: DisplayKind,
     display_target: DisplayTarget,
-    bounds_formatting_ctx: BoundsFormattingCtx,
+    bounds_formatting_ctx: BoundsFormattingCtx<'db>,
 }
 
 // FIXME: To consider, ref and dyn trait lifetimes can be omitted if they are `'_`, path args should
@@ -121,7 +115,7 @@
 }
 
 #[derive(Default)]
-enum BoundsFormattingCtx {
+enum BoundsFormattingCtx<'db> {
     Entered {
         /// We can have recursive bounds like the following case:
         /// ```ignore
@@ -131,14 +125,14 @@
         /// ```
         /// So, record the projection types met while formatting bounds and
         //. prevent recursing into their bounds to avoid infinite loops.
-        projection_tys_met: FxHashSet<ProjectionTy>,
+        projection_tys_met: FxHashSet<AliasTy<'db>>,
     },
     #[default]
     Exited,
 }
 
-impl BoundsFormattingCtx {
-    fn contains(&mut self, proj: &ProjectionTy) -> bool {
+impl<'db> BoundsFormattingCtx<'db> {
+    fn contains(&self, proj: &AliasTy<'db>) -> bool {
         match self {
             BoundsFormattingCtx::Entered { projection_tys_met } => {
                 projection_tys_met.contains(proj)
@@ -148,7 +142,7 @@
     }
 }
 
-impl HirFormatter<'_> {
+impl<'db> HirFormatter<'_, 'db> {
     fn start_location_link(&mut self, location: ModuleDefId) {
         self.fmt.start_location_link(location);
     }
@@ -159,7 +153,7 @@
 
     fn format_bounds_with<T, F: FnOnce(&mut Self) -> T>(
         &mut self,
-        target: ProjectionTy,
+        target: AliasTy<'db>,
         format_bounds: F,
     ) -> T {
         match self.bounds_formatting_ctx {
@@ -181,52 +175,28 @@
         }
     }
 
-    fn render_lifetime(&self, lifetime: &Lifetime) -> bool {
+    fn render_region(&self, lifetime: Region<'db>) -> bool {
         match self.display_lifetimes {
             DisplayLifetime::Always => true,
-            DisplayLifetime::OnlyStatic => matches!(***lifetime.interned(), LifetimeData::Static),
+            DisplayLifetime::OnlyStatic => matches!(lifetime.kind(), RegionKind::ReStatic),
             DisplayLifetime::OnlyNamed => {
-                matches!(***lifetime.interned(), LifetimeData::Placeholder(_))
+                matches!(lifetime.kind(), RegionKind::ReEarlyParam(_))
             }
-            DisplayLifetime::OnlyNamedOrStatic => matches!(
-                ***lifetime.interned(),
-                LifetimeData::Static | LifetimeData::Placeholder(_)
-            ),
-            DisplayLifetime::Never => false,
-        }
-    }
-
-    fn render_region(&self, lifetime: crate::next_solver::Region<'_>) -> bool {
-        match self.display_lifetimes {
-            DisplayLifetime::Always => true,
-            DisplayLifetime::OnlyStatic => {
-                matches!(lifetime.kind(), rustc_type_ir::RegionKind::ReStatic)
+            DisplayLifetime::OnlyNamedOrStatic => {
+                matches!(lifetime.kind(), RegionKind::ReStatic | RegionKind::ReEarlyParam(_))
             }
-            DisplayLifetime::OnlyNamed => {
-                matches!(
-                    lifetime.kind(),
-                    rustc_type_ir::RegionKind::RePlaceholder(_)
-                        | rustc_type_ir::RegionKind::ReEarlyParam(_)
-                )
-            }
-            DisplayLifetime::OnlyNamedOrStatic => matches!(
-                lifetime.kind(),
-                rustc_type_ir::RegionKind::ReStatic
-                    | rustc_type_ir::RegionKind::RePlaceholder(_)
-                    | rustc_type_ir::RegionKind::ReEarlyParam(_)
-            ),
             DisplayLifetime::Never => false,
         }
     }
 }
 
-pub trait HirDisplay {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>;
+pub trait HirDisplay<'db> {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError>;
 
     /// Returns a `Display`able type that is human-readable.
     fn into_displayable<'a>(
         &'a self,
-        db: &'a dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         max_size: Option<usize>,
         limited_size: Option<usize>,
         omit_verbose_types: bool,
@@ -234,7 +204,7 @@
         display_kind: DisplayKind,
         closure_style: ClosureStyle,
         show_container_bounds: bool,
-    ) -> HirDisplayWrapper<'a, Self>
+    ) -> HirDisplayWrapper<'a, 'db, Self>
     where
         Self: Sized,
     {
@@ -260,9 +230,9 @@
     /// Use this for showing types to the user (e.g. diagnostics)
     fn display<'a>(
         &'a self,
-        db: &'a dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         display_target: DisplayTarget,
-    ) -> HirDisplayWrapper<'a, Self>
+    ) -> HirDisplayWrapper<'a, 'db, Self>
     where
         Self: Sized,
     {
@@ -284,10 +254,10 @@
     /// Use this for showing types to the user where space is constrained (e.g. doc popups)
     fn display_truncated<'a>(
         &'a self,
-        db: &'a dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         max_size: Option<usize>,
         display_target: DisplayTarget,
-    ) -> HirDisplayWrapper<'a, Self>
+    ) -> HirDisplayWrapper<'a, 'db, Self>
     where
         Self: Sized,
     {
@@ -309,10 +279,10 @@
     /// Use this for showing definitions which may contain too many items, like `trait`, `struct`, `enum`
     fn display_limited<'a>(
         &'a self,
-        db: &'a dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         limited_size: Option<usize>,
         display_target: DisplayTarget,
-    ) -> HirDisplayWrapper<'a, Self>
+    ) -> HirDisplayWrapper<'a, 'db, Self>
     where
         Self: Sized,
     {
@@ -334,13 +304,16 @@
     /// Use this when generating code (e.g. assists)
     fn display_source_code<'a>(
         &'a self,
-        db: &'a dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         module_id: ModuleId,
         allow_opaque: bool,
     ) -> Result<String, DisplaySourceCodeError> {
         let mut result = String::new();
+        let interner =
+            DbInterner::new_with(db, Some(module_id.krate()), module_id.containing_block());
         match self.hir_fmt(&mut HirFormatter {
             db,
+            interner,
             fmt: &mut result,
             buf: String::with_capacity(20),
             curr_size: 0,
@@ -364,9 +337,9 @@
     /// Returns a String representation of `self` for test purposes
     fn display_test<'a>(
         &'a self,
-        db: &'a dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         display_target: DisplayTarget,
-    ) -> HirDisplayWrapper<'a, Self>
+    ) -> HirDisplayWrapper<'a, 'db, Self>
     where
         Self: Sized,
     {
@@ -388,10 +361,10 @@
     /// the container for functions
     fn display_with_container_bounds<'a>(
         &'a self,
-        db: &'a dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         show_container_bounds: bool,
         display_target: DisplayTarget,
-    ) -> HirDisplayWrapper<'a, Self>
+    ) -> HirDisplayWrapper<'a, 'db, Self>
     where
         Self: Sized,
     {
@@ -410,7 +383,7 @@
     }
 }
 
-impl HirFormatter<'_> {
+impl<'db> HirFormatter<'_, 'db> {
     pub fn krate(&self) -> Crate {
         self.display_target.krate
     }
@@ -419,7 +392,7 @@
         self.display_target.edition
     }
 
-    pub fn write_joined<T: HirDisplay>(
+    pub fn write_joined<T: HirDisplay<'db>>(
         &mut self,
         iter: impl IntoIterator<Item = T>,
         sep: &str,
@@ -536,8 +509,8 @@
     }
 }
 
-pub struct HirDisplayWrapper<'a, T> {
-    db: &'a dyn HirDatabase,
+pub struct HirDisplayWrapper<'a, 'db, T> {
+    db: &'db dyn HirDatabase,
     t: &'a T,
     max_size: Option<usize>,
     limited_size: Option<usize>,
@@ -564,10 +537,17 @@
     Hide,
 }
 
-impl<T: HirDisplay> HirDisplayWrapper<'_, T> {
+impl<'db, T: HirDisplay<'db>> HirDisplayWrapper<'_, 'db, T> {
     pub fn write_to<F: HirWrite>(&self, f: &mut F) -> Result<(), HirDisplayError> {
+        let krate = self.display_target.krate;
+        let block = match self.display_kind {
+            DisplayKind::SourceCode { target_module_id, .. } => target_module_id.containing_block(),
+            DisplayKind::Diagnostics | DisplayKind::Test => None,
+        };
+        let interner = DbInterner::new_with(self.db, Some(krate), block);
         self.t.hir_fmt(&mut HirFormatter {
             db: self.db,
+            interner,
             fmt: f,
             buf: String::with_capacity(self.max_size.unwrap_or(20)),
             curr_size: 0,
@@ -594,9 +574,9 @@
     }
 }
 
-impl<T> fmt::Display for HirDisplayWrapper<'_, T>
+impl<'db, T> fmt::Display for HirDisplayWrapper<'_, 'db, T>
 where
-    T: HirDisplay,
+    T: HirDisplay<'db>,
 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self.write_to(f) {
@@ -614,196 +594,149 @@
 
 const TYPE_HINT_TRUNCATION: &str = "…";
 
-impl<T: HirDisplay> HirDisplay for &T {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db, T: HirDisplay<'db>> HirDisplay<'db> for &T {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         HirDisplay::hir_fmt(*self, f)
     }
 }
 
-impl<T: HirDisplay + Internable> HirDisplay for Interned<T> {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db, T: HirDisplay<'db> + Internable> HirDisplay<'db> for Interned<T> {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         HirDisplay::hir_fmt(self.as_ref(), f)
     }
 }
 
-impl HirDisplay for ProjectionTy {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-        if f.should_truncate() {
-            return write!(f, "{TYPE_HINT_TRUNCATION}");
-        }
-        let trait_ref = self.trait_ref(f.db);
-        let self_ty = trait_ref.self_type_parameter(Interner);
+fn write_projection<'db>(
+    f: &mut HirFormatter<'_, 'db>,
+    alias: &AliasTy<'db>,
+) -> Result<(), HirDisplayError> {
+    if f.should_truncate() {
+        return write!(f, "{TYPE_HINT_TRUNCATION}");
+    }
+    let trait_ref = alias.trait_ref(f.interner);
+    let self_ty = trait_ref.self_ty();
 
-        // if we are projection on a type parameter, check if the projection target has bounds
-        // itself, if so, we render them directly as `impl Bound` instead of the less useful
-        // `<Param as Trait>::Assoc`
-        if !f.display_kind.is_source_code()
-            && let TyKind::Placeholder(idx) = self_ty.kind(Interner)
-            && !f.bounds_formatting_ctx.contains(self)
-        {
-            let db = f.db;
-            let id = from_placeholder_idx(db, *idx).0;
-            let generics = generics(db, id.parent);
-
-            let substs = generics.placeholder_subst(db);
-            let bounds = db
-                .generic_predicates(id.parent)
-                .iter()
-                .map(|pred| pred.clone().substitute(Interner, &substs))
+    // if we are projection on a type parameter, check if the projection target has bounds
+    // itself, if so, we render them directly as `impl Bound` instead of the less useful
+    // `<Param as Trait>::Assoc`
+    if !f.display_kind.is_source_code()
+        && let TyKind::Param(param) = self_ty.kind()
+        && !f.bounds_formatting_ctx.contains(alias)
+    {
+        // FIXME: We shouldn't use `param.id`, it should be removed. We should know the
+        // `GenericDefId` from the formatted type (store it inside the `HirFormatter`).
+        let bounds =
+            f.db.generic_predicates(param.id.parent())
+                .instantiate_identity()
+                .into_iter()
+                .flatten()
                 .filter(|wc| {
-                    let ty = match wc.skip_binders() {
-                        WhereClause::Implemented(tr) => tr.self_type_parameter(Interner),
-                        WhereClause::TypeOutlives(t) => t.ty.clone(),
-                        // We shouldn't be here if these exist
-                        WhereClause::AliasEq(_) | WhereClause::LifetimeOutlives(_) => {
-                            return false;
-                        }
+                    let ty = match wc.kind().skip_binder() {
+                        ClauseKind::Trait(tr) => tr.self_ty(),
+                        ClauseKind::TypeOutlives(t) => t.0,
+                        _ => return false,
                     };
-                    let TyKind::Alias(AliasTy::Projection(proj)) = ty.kind(Interner) else {
+                    let TyKind::Alias(AliasTyKind::Projection, a) = ty.kind() else {
                         return false;
                     };
-                    proj == self
+                    a == *alias
                 })
                 .collect::<Vec<_>>();
-            if !bounds.is_empty() {
-                return f.format_bounds_with(self.clone(), |f| {
-                    write_bounds_like_dyn_trait_with_prefix(
-                        f,
-                        "impl",
-                        Either::Left(
-                            &TyKind::Alias(AliasTy::Projection(self.clone())).intern(Interner),
-                        ),
-                        &bounds,
-                        SizedByDefault::NotSized,
-                    )
-                });
-            }
+        if !bounds.is_empty() {
+            return f.format_bounds_with(*alias, |f| {
+                write_bounds_like_dyn_trait_with_prefix(
+                    f,
+                    "impl",
+                    Either::Left(Ty::new_alias(f.interner, AliasTyKind::Projection, *alias)),
+                    &bounds,
+                    SizedByDefault::NotSized,
+                )
+            });
         }
-
-        write!(f, "<")?;
-        self_ty.hir_fmt(f)?;
-        write!(f, " as ")?;
-        trait_ref.hir_fmt(f)?;
-        write!(
-            f,
-            ">::{}",
-            f.db.type_alias_signature(from_assoc_type_id(self.associated_ty_id))
-                .name
-                .display(f.db, f.edition())
-        )?;
-        let proj_params =
-            &self.substitution.as_slice(Interner)[trait_ref.substitution.len(Interner)..];
-        hir_fmt_generics(f, proj_params, None, None)
     }
+
+    write!(f, "<")?;
+    self_ty.hir_fmt(f)?;
+    write!(f, " as ")?;
+    trait_ref.hir_fmt(f)?;
+    write!(
+        f,
+        ">::{}",
+        f.db.type_alias_signature(alias.def_id.expect_type_alias()).name.display(f.db, f.edition())
+    )?;
+    let proj_params = &alias.args.as_slice()[trait_ref.args.len()..];
+    hir_fmt_generics(f, proj_params, None, None)
 }
 
-impl HirDisplay for OpaqueTy {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-        if f.should_truncate() {
-            return write!(f, "{TYPE_HINT_TRUNCATION}");
-        }
-
-        self.substitution.at(Interner, 0).hir_fmt(f)
-    }
-}
-
-impl HirDisplay for GenericArg {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-        match self.interned() {
-            crate::GenericArgData::Ty(ty) => ty.hir_fmt(f),
-            crate::GenericArgData::Lifetime(lt) => lt.hir_fmt(f),
-            crate::GenericArgData::Const(c) => c.hir_fmt(f),
+impl<'db> HirDisplay<'db> for GenericArg<'db> {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+        match self {
+            GenericArg::Ty(ty) => ty.hir_fmt(f),
+            GenericArg::Lifetime(lt) => lt.hir_fmt(f),
+            GenericArg::Const(c) => c.hir_fmt(f),
         }
     }
 }
 
-impl<'db> HirDisplay for crate::next_solver::GenericArg<'db> {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Const<'db> {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         match self.kind() {
-            rustc_type_ir::GenericArgKind::Type(ty) => ty.hir_fmt(f),
-            rustc_type_ir::GenericArgKind::Lifetime(lt) => lt.hir_fmt(f),
-            rustc_type_ir::GenericArgKind::Const(c) => c.hir_fmt(f),
-        }
-    }
-}
-
-impl HirDisplay for Const {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-        let c = self.to_nextsolver(DbInterner::new_with(f.db, None, None));
-        c.hir_fmt(f)
-    }
-}
-
-impl<'db> HirDisplay for crate::next_solver::Const<'db> {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-        match self.kind() {
-            rustc_type_ir::ConstKind::Placeholder(_) => write!(f, "<placeholder>"),
-            rustc_type_ir::ConstKind::Bound(db, bound_const) => {
+            ConstKind::Placeholder(_) => write!(f, "<placeholder>"),
+            ConstKind::Bound(BoundVarIndexKind::Bound(db), bound_const) => {
                 write!(f, "?{}.{}", db.as_u32(), bound_const.var.as_u32())
             }
-            rustc_type_ir::ConstKind::Infer(..) => write!(f, "#c#"),
-            rustc_type_ir::ConstKind::Param(param) => {
+            ConstKind::Bound(BoundVarIndexKind::Canonical, bound_const) => {
+                write!(f, "?c.{}", bound_const.var.as_u32())
+            }
+            ConstKind::Infer(..) => write!(f, "#c#"),
+            ConstKind::Param(param) => {
                 let generics = generics(f.db, param.id.parent());
                 let param_data = &generics[param.id.local_id()];
                 write!(f, "{}", param_data.name().unwrap().display(f.db, f.edition()))?;
                 Ok(())
             }
-            rustc_type_ir::ConstKind::Value(const_bytes) => render_const_scalar_ns(
+            ConstKind::Value(const_bytes) => render_const_scalar(
                 f,
                 &const_bytes.value.inner().memory,
                 &const_bytes.value.inner().memory_map,
                 const_bytes.ty,
             ),
-            rustc_type_ir::ConstKind::Unevaluated(unev) => {
+            ConstKind::Unevaluated(unev) => {
                 let c = match unev.def {
                     SolverDefId::ConstId(id) => GeneralConstId::ConstId(id),
                     SolverDefId::StaticId(id) => GeneralConstId::StaticId(id),
                     _ => unreachable!(),
                 };
                 write!(f, "{}", c.name(f.db))?;
-                hir_fmt_generics_ns(f, unev.args.as_slice(), c.generic_def(f.db), None)?;
+                hir_fmt_generics(f, unev.args.as_slice(), c.generic_def(f.db), None)?;
                 Ok(())
             }
-            rustc_type_ir::ConstKind::Error(..) => f.write_char('_'),
-            rustc_type_ir::ConstKind::Expr(..) => write!(f, "<const-expr>"),
+            ConstKind::Error(..) => f.write_char('_'),
+            ConstKind::Expr(..) => write!(f, "<const-expr>"),
         }
     }
 }
 
-fn render_const_scalar(
-    f: &mut HirFormatter<'_>,
+fn render_const_scalar<'db>(
+    f: &mut HirFormatter<'_, 'db>,
     b: &[u8],
-    memory_map: &MemoryMap<'_>,
-    ty: &Ty,
+    memory_map: &MemoryMap<'db>,
+    ty: Ty<'db>,
 ) -> Result<(), HirDisplayError> {
     let trait_env = TraitEnvironment::empty(f.krate());
-    let interner = DbInterner::new_with(f.db, Some(trait_env.krate), trait_env.block);
-    let ty = normalize(f.db, trait_env.clone(), ty.clone());
-    let ty = ty.to_nextsolver(interner);
-    render_const_scalar_inner(f, b, memory_map, ty, trait_env)
-}
-
-fn render_const_scalar_ns(
-    f: &mut HirFormatter<'_>,
-    b: &[u8],
-    memory_map: &MemoryMap<'_>,
-    ty: crate::next_solver::Ty<'_>,
-) -> Result<(), HirDisplayError> {
-    let trait_env = TraitEnvironment::empty(f.krate());
-    let interner = DbInterner::new_with(f.db, Some(trait_env.krate), trait_env.block);
-    let infcx = interner.infer_ctxt().build(rustc_type_ir::TypingMode::PostAnalysis);
+    let infcx = f.interner.infer_ctxt().build(TypingMode::PostAnalysis);
     let ty = infcx.at(&ObligationCause::new(), trait_env.env).deeply_normalize(ty).unwrap_or(ty);
     render_const_scalar_inner(f, b, memory_map, ty, trait_env)
 }
 
 fn render_const_scalar_inner<'db>(
-    f: &mut HirFormatter<'_>,
+    f: &mut HirFormatter<'_, 'db>,
     b: &[u8],
-    memory_map: &MemoryMap<'_>,
-    ty: crate::next_solver::Ty<'db>,
+    memory_map: &MemoryMap<'db>,
+    ty: Ty<'db>,
     trait_env: Arc<TraitEnvironment<'db>>,
 ) -> Result<(), HirDisplayError> {
-    use rustc_type_ir::TyKind;
+    use TyKind;
     match ty.kind() {
         TyKind::Bool => write!(f, "{}", b[0] != 0),
         TyKind::Char => {
@@ -822,7 +755,7 @@
             write!(f, "{it}")
         }
         TyKind::Float(fl) => match fl {
-            rustc_type_ir::FloatTy::F16 => {
+            FloatTy::F16 => {
                 // FIXME(#17451): Replace with builtins once they are stabilised.
                 let it = f16::from_bits(u16::from_le_bytes(b.try_into().unwrap()).into());
                 let s = it.to_string();
@@ -833,15 +766,15 @@
                     write!(f, "{s}")
                 }
             }
-            rustc_type_ir::FloatTy::F32 => {
+            FloatTy::F32 => {
                 let it = f32::from_le_bytes(b.try_into().unwrap());
                 write!(f, "{it:?}")
             }
-            rustc_type_ir::FloatTy::F64 => {
+            FloatTy::F64 => {
                 let it = f64::from_le_bytes(b.try_into().unwrap());
                 write!(f, "{it:?}")
             }
-            rustc_type_ir::FloatTy::F128 => {
+            FloatTy::F128 => {
                 // FIXME(#17451): Replace with builtins once they are stabilised.
                 let it = f128::from_bits(u128::from_le_bytes(b.try_into().unwrap()));
                 let s = it.to_string();
@@ -890,7 +823,7 @@
                         f.write_str(", ")?;
                     }
                     let offset = size_one * i;
-                    render_const_scalar_ns(f, &bytes[offset..offset + size_one], memory_map, ty)?;
+                    render_const_scalar(f, &bytes[offset..offset + size_one], memory_map, ty)?;
                 }
                 f.write_str("]")
             }
@@ -908,7 +841,7 @@
                     return f.write_str("<ref-data-not-available>");
                 };
                 f.write_str("&")?;
-                render_const_scalar_ns(f, bytes, memory_map, t)
+                render_const_scalar(f, bytes, memory_map, t)
             }
             TyKind::Adt(adt, _) if b.len() == 2 * size_of::<usize>() => match adt.def_id().0 {
                 hir_def::AdtId::StructId(s) => {
@@ -938,7 +871,7 @@
                     return f.write_str("<ref-data-not-available>");
                 };
                 f.write_str("&")?;
-                render_const_scalar_ns(f, bytes, memory_map, t)
+                render_const_scalar(f, bytes, memory_map, t)
             }
         },
         TyKind::Tuple(tys) => {
@@ -959,7 +892,7 @@
                     continue;
                 };
                 let size = layout.size.bytes_usize();
-                render_const_scalar_ns(f, &b[offset..offset + size], memory_map, ty)?;
+                render_const_scalar(f, &b[offset..offset + size], memory_map, ty)?;
             }
             f.write_str(")")
         }
@@ -1041,7 +974,7 @@
                     f.write_str(", ")?;
                 }
                 let offset = size_one * i;
-                render_const_scalar_ns(f, &b[offset..offset + size_one], memory_map, ty)?;
+                render_const_scalar(f, &b[offset..offset + size_one], memory_map, ty)?;
             }
             f.write_str("]")
         }
@@ -1067,28 +1000,24 @@
 
 fn render_variant_after_name<'db>(
     data: &VariantFields,
-    f: &mut HirFormatter<'_>,
-    field_types: &ArenaMap<LocalFieldId, Binders<Ty>>,
+    f: &mut HirFormatter<'_, 'db>,
+    field_types: &ArenaMap<LocalFieldId, EarlyBinder<'db, Ty<'db>>>,
     trait_env: Arc<TraitEnvironment<'db>>,
     layout: &Layout,
-    args: GenericArgs<'_>,
+    args: GenericArgs<'db>,
     b: &[u8],
-    memory_map: &MemoryMap<'_>,
+    memory_map: &MemoryMap<'db>,
 ) -> Result<(), HirDisplayError> {
-    let interner = DbInterner::new_with(f.db, Some(trait_env.krate), trait_env.block);
     match data.shape {
         FieldsShape::Record | FieldsShape::Tuple => {
-            let render_field = |f: &mut HirFormatter<'_>, id: LocalFieldId| {
+            let render_field = |f: &mut HirFormatter<'_, 'db>, id: LocalFieldId| {
                 let offset = layout.fields.offset(u32::from(id.into_raw()) as usize).bytes_usize();
-                let ty = field_types[id]
-                    .clone()
-                    .substitute(Interner, &convert_args_for_result(interner, args.as_slice()));
-                let Ok(layout) = f.db.layout_of_ty(ty.to_nextsolver(interner), trait_env.clone())
-                else {
+                let ty = field_types[id].instantiate(f.interner, args);
+                let Ok(layout) = f.db.layout_of_ty(ty, trait_env.clone()) else {
                     return f.write_str("<layout-error>");
                 };
                 let size = layout.size.bytes_usize();
-                render_const_scalar(f, &b[offset..offset + size], memory_map, &ty)
+                render_const_scalar(f, &b[offset..offset + size], memory_map, ty)
             };
             let mut it = data.fields().iter();
             if matches!(data.shape, FieldsShape::Record) {
@@ -1120,41 +1049,25 @@
     }
 }
 
-impl HirDisplay for BoundVar {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-        write!(f, "?{}.{}", self.debruijn.depth(), self.index)
-    }
-}
-
-impl HirDisplay for Ty {
+impl<'db> HirDisplay<'db> for Ty<'db> {
     fn hir_fmt(
         &self,
-        f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_>,
+        f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_, 'db>,
     ) -> Result<(), HirDisplayError> {
-        let ty = self.to_nextsolver(DbInterner::new_with(db, None, None));
-        ty.hir_fmt(f)
-    }
-}
-
-impl<'db> HirDisplay for crate::next_solver::Ty<'db> {
-    fn hir_fmt(
-        &self,
-        f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_>,
-    ) -> Result<(), HirDisplayError> {
-        let interner = DbInterner::new_with(db, None, None);
+        let interner = f.interner;
         if f.should_truncate() {
             return write!(f, "{TYPE_HINT_TRUNCATION}");
         }
 
-        use rustc_type_ir::TyKind;
+        use TyKind;
         match self.kind() {
             TyKind::Never => write!(f, "!")?,
             TyKind::Str => write!(f, "str")?,
             TyKind::Bool => write!(f, "bool")?,
             TyKind::Char => write!(f, "char")?,
-            TyKind::Float(t) => write!(f, "{}", primitive::float_ty_to_string_ns(t))?,
-            TyKind::Int(t) => write!(f, "{}", primitive::int_ty_to_string_ns(t))?,
-            TyKind::Uint(t) => write!(f, "{}", primitive::uint_ty_to_string_ns(t))?,
+            TyKind::Float(t) => write!(f, "{}", primitive::float_ty_to_string(t))?,
+            TyKind::Int(t) => write!(f, "{}", primitive::int_ty_to_string(t))?,
+            TyKind::Uint(t) => write!(f, "{}", primitive::uint_ty_to_string(t))?,
             TyKind::Slice(t) => {
                 write!(f, "[")?;
                 t.hir_fmt(f)?;
@@ -1164,14 +1077,14 @@
                 write!(f, "[")?;
                 t.hir_fmt(f)?;
                 write!(f, "; ")?;
-                convert_const_for_result(interner, c).hir_fmt(f)?;
+                c.hir_fmt(f)?;
                 write!(f, "]")?;
             }
             kind @ (TyKind::RawPtr(t, m) | TyKind::Ref(_, t, m)) => {
                 if let TyKind::Ref(l, _, _) = kind {
                     f.write_char('&')?;
                     if f.render_region(l) {
-                        convert_region_for_result(interner, l).hir_fmt(f)?;
+                        l.hir_fmt(f)?;
                         f.write_char(' ')?;
                     }
                     match m {
@@ -1190,32 +1103,18 @@
                 }
 
                 // FIXME: all this just to decide whether to use parentheses...
-                let contains_impl_fn = |bounds: &[QuantifiedWhereClause]| {
-                    bounds.iter().any(|bound| {
-                        if let WhereClause::Implemented(trait_ref) = bound.skip_binders() {
-                            let trait_ = trait_ref.hir_trait_id();
-                            fn_traits(db, trait_).any(|it| it == trait_)
-                        } else {
-                            false
-                        }
-                    })
-                };
-                let contains_impl_fn_ns = |bounds: &[BoundExistentialPredicate<'_>]| {
-                    bounds.iter().any(|bound| match bound.skip_binder() {
-                        rustc_type_ir::ExistentialPredicate::Trait(trait_ref) => {
-                            let trait_ = trait_ref.def_id.0;
-                            fn_traits(db, trait_).any(|it| it == trait_)
-                        }
-                        _ => false,
-                    })
-                };
                 let (preds_to_print, has_impl_fn_pred) = match t.kind() {
                     TyKind::Dynamic(bounds, region) => {
+                        let contains_impl_fn =
+                            bounds.iter().any(|bound| match bound.skip_binder() {
+                                ExistentialPredicate::Trait(trait_ref) => {
+                                    let trait_ = trait_ref.def_id.0;
+                                    fn_traits(db, trait_).any(|it| it == trait_)
+                                }
+                                _ => false,
+                            });
                         let render_lifetime = f.render_region(region);
-                        (
-                            bounds.len() + render_lifetime as usize,
-                            contains_impl_fn_ns(bounds.as_slice()),
-                        )
+                        (bounds.len() + render_lifetime as usize, contains_impl_fn)
                     }
                     TyKind::Alias(AliasTyKind::Opaque, ty) => {
                         let opaque_ty_id = match ty.def_id {
@@ -1227,26 +1126,23 @@
                             let datas = db
                                 .return_type_impl_traits(func)
                                 .expect("impl trait id without data");
-                            let data =
-                                (*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
-                            let bounds = data.substitute(
-                                Interner,
-                                &convert_args_for_result(interner, ty.args.as_slice()),
-                            );
-                            let mut len = bounds.skip_binders().len();
+                            let data = (*datas)
+                                .as_ref()
+                                .map_bound(|rpit| &rpit.impl_traits[idx].predicates);
+                            let bounds =
+                                || data.iter_instantiated_copied(f.interner, ty.args.as_slice());
+                            let mut len = bounds().count();
 
                             // Don't count Sized but count when it absent
                             // (i.e. when explicit ?Sized bound is set).
                             let default_sized = SizedByDefault::Sized { anchor: func.krate(db) };
-                            let sized_bounds = bounds
-                                .skip_binders()
-                                .iter()
+                            let sized_bounds = bounds()
                                 .filter(|b| {
                                     matches!(
-                                        b.skip_binders(),
-                                        WhereClause::Implemented(trait_ref)
+                                        b.kind().skip_binder(),
+                                        ClauseKind::Trait(trait_ref)
                                             if default_sized.is_sized_trait(
-                                                trait_ref.hir_trait_id(),
+                                                trait_ref.def_id().0,
                                                 db,
                                             ),
                                     )
@@ -1259,7 +1155,15 @@
                                 }
                             }
 
-                            (len, contains_impl_fn(bounds.skip_binders()))
+                            let contains_impl_fn = bounds().any(|bound| {
+                                if let ClauseKind::Trait(trait_ref) = bound.kind().skip_binder() {
+                                    let trait_ = trait_ref.def_id().0;
+                                    fn_traits(db, trait_).any(|it| it == trait_)
+                                } else {
+                                    false
+                                }
+                            });
+                            (len, contains_impl_fn)
                         } else {
                             (0, false)
                         }
@@ -1291,31 +1195,28 @@
                 }
             }
             TyKind::FnPtr(sig, header) => {
-                let sig = CallableSig::from_fn_sig_and_header(interner, sig, header);
+                let sig = sig.with(header);
                 sig.hir_fmt(f)?;
             }
             TyKind::FnDef(def, args) => {
                 let def = def.0;
-                let sig = db
-                    .callable_item_signature(def)
-                    .instantiate(interner, args)
-                    .skip_binder()
-                    .to_chalk(interner);
+                let sig = db.callable_item_signature(def).instantiate(interner, args);
 
                 if f.display_kind.is_source_code() {
                     // `FnDef` is anonymous and there's no surface syntax for it. Show it as a
                     // function pointer type.
                     return sig.hir_fmt(f);
                 }
-                if let Safety::Unsafe = sig.safety {
+                if let Safety::Unsafe = sig.safety() {
                     write!(f, "unsafe ")?;
                 }
-                if !matches!(sig.abi, FnAbi::Rust | FnAbi::RustCall) {
+                if !matches!(sig.abi(), FnAbi::Rust | FnAbi::RustCall) {
                     f.write_str("extern \"")?;
-                    f.write_str(sig.abi.as_str())?;
+                    f.write_str(sig.abi().as_str())?;
                     f.write_str("\" ")?;
                 }
 
+                let sig = sig.skip_binder();
                 write!(f, "fn ")?;
                 f.start_location_link(def.into());
                 match def {
@@ -1338,13 +1239,12 @@
                 };
                 f.end_location_link();
 
-                let parameters = convert_args_for_result(interner, args.as_slice());
-                if parameters.len(Interner) > 0 {
+                if args.len() > 0 {
                     let generic_def_id = GenericDefId::from_callable(db, def);
                     let generics = generics(db, generic_def_id);
                     let (parent_len, self_param, type_, const_, impl_, lifetime) =
                         generics.provenance_split();
-                    let parameters = parameters.as_slice(Interner);
+                    let parameters = args.as_slice();
                     debug_assert_eq!(
                         parameters.len(),
                         parent_len + self_param as usize + type_ + const_ + impl_ + lifetime
@@ -1389,9 +1289,9 @@
                     }
                 }
                 write!(f, "(")?;
-                f.write_joined(sig.params(), ", ")?;
+                f.write_joined(sig.inputs(), ", ")?;
                 write!(f, ")")?;
-                let ret = sig.ret();
+                let ret = sig.output();
                 if !ret.is_unit() {
                     write!(f, " -> ")?;
                     ret.hir_fmt(f)?;
@@ -1434,27 +1334,9 @@
                 }
                 f.end_location_link();
 
-                hir_fmt_generics(
-                    f,
-                    convert_args_for_result(interner, parameters.as_slice()).as_slice(Interner),
-                    Some(def.def_id().0.into()),
-                    None,
-                )?;
+                hir_fmt_generics(f, parameters.as_slice(), Some(def.def_id().0.into()), None)?;
             }
-            TyKind::Alias(AliasTyKind::Projection, alias_ty) => {
-                let type_alias = match alias_ty.def_id {
-                    SolverDefId::TypeAliasId(id) => id,
-                    _ => unreachable!(),
-                };
-                let parameters = convert_args_for_result(interner, alias_ty.args.as_slice());
-
-                let projection_ty = ProjectionTy {
-                    associated_ty_id: to_assoc_type_id(type_alias),
-                    substitution: parameters.clone(),
-                };
-
-                projection_ty.hir_fmt(f)?;
-            }
+            TyKind::Alias(AliasTyKind::Projection, alias_ty) => write_projection(f, &alias_ty)?,
             TyKind::Foreign(alias) => {
                 let type_alias = db.type_alias_signature(alias.0);
                 f.start_location_link(alias.0.into());
@@ -1466,7 +1348,6 @@
                     SolverDefId::InternedOpaqueTyId(id) => id,
                     _ => unreachable!(),
                 };
-                let parameters = convert_args_for_result(interner, alias_ty.args.as_slice());
                 if !f.display_kind.allows_opaque() {
                     return Err(HirDisplayError::DisplaySourceCodeError(
                         DisplaySourceCodeError::OpaqueType,
@@ -1478,14 +1359,16 @@
                         let datas =
                             db.return_type_impl_traits(func).expect("impl trait id without data");
                         let data =
-                            (*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
-                        let bounds = data.substitute(Interner, &parameters);
+                            (*datas).as_ref().map_bound(|rpit| &rpit.impl_traits[idx].predicates);
+                        let bounds = data
+                            .iter_instantiated_copied(interner, alias_ty.args.as_slice())
+                            .collect::<Vec<_>>();
                         let krate = func.krate(db);
                         write_bounds_like_dyn_trait_with_prefix(
                             f,
                             "impl",
-                            Either::Left(&convert_ty_for_result(interner, *self)),
-                            bounds.skip_binders(),
+                            Either::Left(*self),
+                            &bounds,
                             SizedByDefault::Sized { anchor: krate },
                         )?;
                         // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
@@ -1493,20 +1376,254 @@
                     ImplTraitId::TypeAliasImplTrait(alias, idx) => {
                         let datas =
                             db.type_alias_impl_traits(alias).expect("impl trait id without data");
-                        let data = (*datas).as_ref().map(|it| it.impl_traits[idx].bounds.clone());
-                        let bounds = data.substitute(Interner, &parameters);
+                        let data =
+                            (*datas).as_ref().map_bound(|rpit| &rpit.impl_traits[idx].predicates);
+                        let bounds = data
+                            .iter_instantiated_copied(interner, alias_ty.args.as_slice())
+                            .collect::<Vec<_>>();
                         let krate = alias.krate(db);
                         write_bounds_like_dyn_trait_with_prefix(
                             f,
                             "impl",
-                            Either::Left(&convert_ty_for_result(interner, *self)),
-                            bounds.skip_binders(),
+                            Either::Left(*self),
+                            &bounds,
                             SizedByDefault::Sized { anchor: krate },
                         )?;
                     }
-                    ImplTraitId::AsyncBlockTypeImplTrait(body, ..) => {
+                }
+            }
+            TyKind::Closure(id, substs) => {
+                let id = id.0;
+                if f.display_kind.is_source_code() {
+                    if !f.display_kind.allows_opaque() {
+                        return Err(HirDisplayError::DisplaySourceCodeError(
+                            DisplaySourceCodeError::OpaqueType,
+                        ));
+                    } else if f.closure_style != ClosureStyle::ImplFn {
+                        never!("Only `impl Fn` is valid for displaying closures in source code");
+                    }
+                }
+                match f.closure_style {
+                    ClosureStyle::Hide => return write!(f, "{TYPE_HINT_TRUNCATION}"),
+                    ClosureStyle::ClosureWithId => {
+                        return write!(
+                            f,
+                            "{{closure#{:?}}}",
+                            salsa::plumbing::AsId::as_id(&id).index()
+                        );
+                    }
+                    ClosureStyle::ClosureWithSubst => {
+                        write!(f, "{{closure#{:?}}}", salsa::plumbing::AsId::as_id(&id).index())?;
+                        return hir_fmt_generics(f, substs.as_slice(), None, None);
+                    }
+                    _ => (),
+                }
+                let sig = substs
+                    .split_closure_args_untupled()
+                    .closure_sig_as_fn_ptr_ty
+                    .callable_sig(interner);
+                if let Some(sig) = sig {
+                    let sig = sig.skip_binder();
+                    let InternedClosure(def, _) = db.lookup_intern_closure(id);
+                    let infer = db.infer(def);
+                    let (_, kind) = infer.closure_info(id);
+                    match f.closure_style {
+                        ClosureStyle::ImplFn => write!(f, "impl {kind:?}(")?,
+                        ClosureStyle::RANotation => write!(f, "|")?,
+                        _ => unreachable!(),
+                    }
+                    if sig.inputs().is_empty() {
+                    } else if f.should_truncate() {
+                        write!(f, "{TYPE_HINT_TRUNCATION}")?;
+                    } else {
+                        f.write_joined(sig.inputs(), ", ")?;
+                    };
+                    match f.closure_style {
+                        ClosureStyle::ImplFn => write!(f, ")")?,
+                        ClosureStyle::RANotation => write!(f, "|")?,
+                        _ => unreachable!(),
+                    }
+                    if f.closure_style == ClosureStyle::RANotation || !sig.output().is_unit() {
+                        write!(f, " -> ")?;
+                        sig.output().hir_fmt(f)?;
+                    }
+                } else {
+                    write!(f, "{{closure}}")?;
+                }
+            }
+            TyKind::CoroutineClosure(id, args) => {
+                let id = id.0;
+                if f.display_kind.is_source_code() {
+                    if !f.display_kind.allows_opaque() {
+                        return Err(HirDisplayError::DisplaySourceCodeError(
+                            DisplaySourceCodeError::OpaqueType,
+                        ));
+                    } else if f.closure_style != ClosureStyle::ImplFn {
+                        never!("Only `impl Fn` is valid for displaying closures in source code");
+                    }
+                }
+                match f.closure_style {
+                    ClosureStyle::Hide => return write!(f, "{TYPE_HINT_TRUNCATION}"),
+                    ClosureStyle::ClosureWithId => {
+                        return write!(
+                            f,
+                            "{{async closure#{:?}}}",
+                            salsa::plumbing::AsId::as_id(&id).index()
+                        );
+                    }
+                    ClosureStyle::ClosureWithSubst => {
+                        write!(
+                            f,
+                            "{{async closure#{:?}}}",
+                            salsa::plumbing::AsId::as_id(&id).index()
+                        )?;
+                        return hir_fmt_generics(f, args.as_slice(), None, None);
+                    }
+                    _ => (),
+                }
+                let CoroutineClosureArgsParts { closure_kind_ty, signature_parts_ty, .. } =
+                    args.split_coroutine_closure_args();
+                let kind = closure_kind_ty.to_opt_closure_kind().unwrap();
+                let kind = match kind {
+                    rustc_type_ir::ClosureKind::Fn => "AsyncFn",
+                    rustc_type_ir::ClosureKind::FnMut => "AsyncFnMut",
+                    rustc_type_ir::ClosureKind::FnOnce => "AsyncFnOnce",
+                };
+                let TyKind::FnPtr(coroutine_sig, _) = signature_parts_ty.kind() else {
+                    unreachable!("invalid coroutine closure signature");
+                };
+                let coroutine_sig = coroutine_sig.skip_binder();
+                let coroutine_inputs = coroutine_sig.inputs();
+                let TyKind::Tuple(coroutine_inputs) = coroutine_inputs.as_slice()[1].kind() else {
+                    unreachable!("invalid coroutine closure signature");
+                };
+                let TyKind::Tuple(coroutine_output) = coroutine_sig.output().kind() else {
+                    unreachable!("invalid coroutine closure signature");
+                };
+                let coroutine_output = coroutine_output.as_slice()[1];
+                match f.closure_style {
+                    ClosureStyle::ImplFn => write!(f, "impl {kind}(")?,
+                    ClosureStyle::RANotation => write!(f, "async |")?,
+                    _ => unreachable!(),
+                }
+                if coroutine_inputs.is_empty() {
+                } else if f.should_truncate() {
+                    write!(f, "{TYPE_HINT_TRUNCATION}")?;
+                } else {
+                    f.write_joined(coroutine_inputs, ", ")?;
+                };
+                match f.closure_style {
+                    ClosureStyle::ImplFn => write!(f, ")")?,
+                    ClosureStyle::RANotation => write!(f, "|")?,
+                    _ => unreachable!(),
+                }
+                if f.closure_style == ClosureStyle::RANotation || !coroutine_output.is_unit() {
+                    write!(f, " -> ")?;
+                    coroutine_output.hir_fmt(f)?;
+                }
+            }
+            TyKind::Placeholder(_) => write!(f, "{{placeholder}}")?,
+            TyKind::Param(param) => {
+                // FIXME: We should not access `param.id`, it should be removed, and we should know the
+                // parent from the formatted type.
+                let generics = generics(db, param.id.parent());
+                let param_data = &generics[param.id.local_id()];
+                match param_data {
+                    TypeOrConstParamData::TypeParamData(p) => match p.provenance {
+                        TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
+                            write!(
+                                f,
+                                "{}",
+                                p.name
+                                    .clone()
+                                    .unwrap_or_else(Name::missing)
+                                    .display(f.db, f.edition())
+                            )?
+                        }
+                        TypeParamProvenance::ArgumentImplTrait => {
+                            let bounds = db
+                                .generic_predicates(param.id.parent())
+                                .instantiate_identity()
+                                .into_iter()
+                                .flatten()
+                                .filter(|wc| match wc.kind().skip_binder() {
+                                    ClauseKind::Trait(tr) => tr.self_ty() == *self,
+                                    ClauseKind::Projection(proj) => proj.self_ty() == *self,
+                                    ClauseKind::TypeOutlives(to) => to.0 == *self,
+                                    _ => false,
+                                })
+                                .collect::<Vec<_>>();
+                            let krate = param.id.parent().module(db).krate();
+                            write_bounds_like_dyn_trait_with_prefix(
+                                f,
+                                "impl",
+                                Either::Left(*self),
+                                &bounds,
+                                SizedByDefault::Sized { anchor: krate },
+                            )?;
+                        }
+                    },
+                    TypeOrConstParamData::ConstParamData(p) => {
+                        write!(f, "{}", p.name.display(f.db, f.edition()))?;
+                    }
+                }
+            }
+            TyKind::Bound(BoundVarIndexKind::Bound(debruijn), ty) => {
+                write!(f, "?{}.{}", debruijn.as_usize(), ty.var.as_usize())?
+            }
+            TyKind::Bound(BoundVarIndexKind::Canonical, ty) => {
+                write!(f, "?c.{}", ty.var.as_usize())?
+            }
+            TyKind::Dynamic(bounds, region) => {
+                // We want to put auto traits after principal traits, regardless of their written order.
+                let mut bounds_to_display = SmallVec::<[_; 4]>::new();
+                let mut auto_trait_bounds = SmallVec::<[_; 4]>::new();
+                for bound in bounds.iter() {
+                    let clause = bound.with_self_ty(interner, *self);
+                    match bound.skip_binder() {
+                        ExistentialPredicate::Trait(_) | ExistentialPredicate::Projection(_) => {
+                            bounds_to_display.push(clause);
+                        }
+                        ExistentialPredicate::AutoTrait(_) => auto_trait_bounds.push(clause),
+                    }
+                }
+                bounds_to_display.append(&mut auto_trait_bounds);
+
+                if f.render_region(region) {
+                    bounds_to_display
+                        .push(rustc_type_ir::OutlivesPredicate(*self, region).upcast(interner));
+                }
+
+                write_bounds_like_dyn_trait_with_prefix(
+                    f,
+                    "dyn",
+                    Either::Left(*self),
+                    &bounds_to_display,
+                    SizedByDefault::NotSized,
+                )?;
+            }
+            TyKind::Error(_) => {
+                if f.display_kind.is_source_code() {
+                    f.write_char('_')?;
+                } else {
+                    write!(f, "{{unknown}}")?;
+                }
+            }
+            TyKind::Infer(..) => write!(f, "_")?,
+            TyKind::Coroutine(coroutine_id, subst) => {
+                let InternedCoroutine(owner, expr_id) = coroutine_id.0.loc(db);
+                let CoroutineArgsParts { resume_ty, yield_ty, return_ty, .. } =
+                    subst.split_coroutine_args();
+                let body = db.body(owner);
+                let expr = &body[expr_id];
+                match expr {
+                    hir_def::hir::Expr::Closure {
+                        closure_kind: hir_def::hir::ClosureKind::Async,
+                        ..
+                    }
+                    | hir_def::hir::Expr::Async { .. } => {
                         let future_trait =
-                            LangItem::Future.resolve_trait(db, body.module(db).krate());
+                            LangItem::Future.resolve_trait(db, owner.module(db).krate());
                         let output = future_trait.and_then(|t| {
                             t.trait_items(db)
                                 .associated_type_by_name(&Name::new_symbol_root(sym::Output))
@@ -1528,205 +1645,45 @@
                             f.end_location_link();
                         }
                         write!(f, " = ")?;
-                        parameters.at(Interner, 0).hir_fmt(f)?;
+                        return_ty.hir_fmt(f)?;
                         write!(f, ">")?;
                     }
-                }
-            }
-            TyKind::Closure(id, substs) => {
-                let id = id.0;
-                let substs = convert_args_for_result(interner, substs.as_slice());
-                if f.display_kind.is_source_code() {
-                    if !f.display_kind.allows_opaque() {
-                        return Err(HirDisplayError::DisplaySourceCodeError(
-                            DisplaySourceCodeError::OpaqueType,
-                        ));
-                    } else if f.closure_style != ClosureStyle::ImplFn {
-                        never!("Only `impl Fn` is valid for displaying closures in source code");
-                    }
-                }
-                match f.closure_style {
-                    ClosureStyle::Hide => return write!(f, "{TYPE_HINT_TRUNCATION}"),
-                    ClosureStyle::ClosureWithId => {
-                        return write!(
-                            f,
-                            "{{closure#{:?}}}",
-                            salsa::plumbing::AsId::as_id(&id).index()
-                        );
-                    }
-                    ClosureStyle::ClosureWithSubst => {
-                        write!(f, "{{closure#{:?}}}", salsa::plumbing::AsId::as_id(&id).index())?;
-                        return hir_fmt_generics(f, substs.as_slice(Interner), None, None);
-                    }
-                    _ => (),
-                }
-                let sig = ClosureSubst(&substs).sig_ty(db).callable_sig(db);
-                if let Some(sig) = sig {
-                    let InternedClosure(def, _) = db.lookup_intern_closure(id);
-                    let infer = db.infer(def);
-                    let (_, kind) = infer.closure_info(id);
-                    match f.closure_style {
-                        ClosureStyle::ImplFn => write!(f, "impl {kind:?}(")?,
-                        ClosureStyle::RANotation => write!(f, "|")?,
-                        _ => unreachable!(),
-                    }
-                    if sig.params().is_empty() {
-                    } else if f.should_truncate() {
-                        write!(f, "{TYPE_HINT_TRUNCATION}")?;
-                    } else {
-                        f.write_joined(sig.params(), ", ")?;
-                    };
-                    match f.closure_style {
-                        ClosureStyle::ImplFn => write!(f, ")")?,
-                        ClosureStyle::RANotation => write!(f, "|")?,
-                        _ => unreachable!(),
-                    }
-                    if f.closure_style == ClosureStyle::RANotation || !sig.ret().is_unit() {
+                    hir_def::hir::Expr::Closure {
+                        closure_kind: hir_def::hir::ClosureKind::Coroutine(..),
+                        ..
+                    } => {
+                        if f.display_kind.is_source_code() {
+                            return Err(HirDisplayError::DisplaySourceCodeError(
+                                DisplaySourceCodeError::Coroutine,
+                            ));
+                        }
+                        write!(f, "|")?;
+                        resume_ty.hir_fmt(f)?;
+                        write!(f, "|")?;
+
+                        write!(f, " yields ")?;
+                        yield_ty.hir_fmt(f)?;
+
                         write!(f, " -> ")?;
-                        // FIXME: We display `AsyncFn` as `-> impl Future`, but this is hard to fix because
-                        // we don't have a trait environment here, required to normalize `<Ret as Future>::Output`.
-                        sig.ret().hir_fmt(f)?;
+                        return_ty.hir_fmt(f)?;
                     }
-                } else {
-                    write!(f, "{{closure}}")?;
+                    _ => panic!("invalid expr for coroutine: {expr:?}"),
                 }
             }
-            TyKind::Placeholder(_) => write!(f, "{{placeholder}}")?,
-            TyKind::Param(param) => {
-                let generics = generics(db, param.id.parent());
-                let param_data = &generics[param.id.local_id()];
-                match param_data {
-                    TypeOrConstParamData::TypeParamData(p) => match p.provenance {
-                        TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
-                            write!(
-                                f,
-                                "{}",
-                                p.name
-                                    .clone()
-                                    .unwrap_or_else(Name::missing)
-                                    .display(f.db, f.edition())
-                            )?
-                        }
-                        TypeParamProvenance::ArgumentImplTrait => {
-                            let substs = generics.placeholder_subst(db);
-                            let bounds = db
-                                .generic_predicates(param.id.parent())
-                                .iter()
-                                .map(|pred| pred.clone().substitute(Interner, &substs))
-                                .filter(|wc| match wc.skip_binders() {
-                                    WhereClause::Implemented(tr) => {
-                                        tr.self_type_parameter(Interner)
-                                            == convert_ty_for_result(interner, *self)
-                                    }
-                                    WhereClause::AliasEq(AliasEq {
-                                        alias: AliasTy::Projection(proj),
-                                        ty: _,
-                                    }) => {
-                                        proj.self_type_parameter(db)
-                                            == convert_ty_for_result(interner, *self)
-                                    }
-                                    WhereClause::AliasEq(_) => false,
-                                    WhereClause::TypeOutlives(to) => {
-                                        to.ty == convert_ty_for_result(interner, *self)
-                                    }
-                                    WhereClause::LifetimeOutlives(_) => false,
-                                })
-                                .collect::<Vec<_>>();
-                            let krate = param.id.parent().module(db).krate();
-                            write_bounds_like_dyn_trait_with_prefix(
-                                f,
-                                "impl",
-                                Either::Left(&convert_ty_for_result(interner, *self)),
-                                &bounds,
-                                SizedByDefault::Sized { anchor: krate },
-                            )?;
-                        }
-                    },
-                    TypeOrConstParamData::ConstParamData(p) => {
-                        write!(f, "{}", p.name.display(f.db, f.edition()))?;
-                    }
-                }
-            }
-            TyKind::Bound(debruijn_index, ty) => {
-                let idx = chalk_ir::BoundVar {
-                    debruijn: chalk_ir::DebruijnIndex::new(debruijn_index.as_u32()),
-                    index: ty.var.as_usize(),
-                };
-                idx.hir_fmt(f)?
-            }
-            TyKind::Dynamic(..) => {
-                let ty = convert_ty_for_result(interner, *self);
-                let chalk_ir::TyKind::Dyn(dyn_ty) = ty.kind(Interner) else { unreachable!() };
-                // Reorder bounds to satisfy `write_bounds_like_dyn_trait()`'s expectation.
-                // FIXME: `Iterator::partition_in_place()` or `Vec::extract_if()` may make it
-                // more efficient when either of them hits stable.
-                let mut bounds: SmallVec<[_; 4]> =
-                    dyn_ty.bounds.skip_binders().iter(Interner).cloned().collect();
-                let (auto_traits, others): (SmallVec<[_; 4]>, _) =
-                    bounds.drain(1..).partition(|b| b.skip_binders().trait_id().is_some());
-                bounds.extend(others);
-                bounds.extend(auto_traits);
-
-                if f.render_lifetime(&dyn_ty.lifetime) {
-                    // we skip the binders in `write_bounds_like_dyn_trait_with_prefix`
-                    bounds.push(Binders::empty(
-                        Interner,
-                        chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives {
-                            ty: ty.clone(),
-                            lifetime: dyn_ty.lifetime.clone(),
-                        }),
-                    ));
-                }
-
-                write_bounds_like_dyn_trait_with_prefix(
-                    f,
-                    "dyn",
-                    Either::Left(&ty),
-                    &bounds,
-                    SizedByDefault::NotSized,
-                )?;
-            }
-            TyKind::Error(_) => {
-                if f.display_kind.is_source_code() {
-                    f.write_char('_')?;
-                } else {
-                    write!(f, "{{unknown}}")?;
-                }
-            }
-            TyKind::Infer(..) => write!(f, "_")?,
-            TyKind::Coroutine(_, subst) => {
-                if f.display_kind.is_source_code() {
-                    return Err(HirDisplayError::DisplaySourceCodeError(
-                        DisplaySourceCodeError::Coroutine,
-                    ));
-                }
-                let CoroutineArgsParts { resume_ty, yield_ty, return_ty, .. } =
-                    subst.split_coroutine_args();
-                write!(f, "|")?;
-                resume_ty.hir_fmt(f)?;
-                write!(f, "|")?;
-
-                write!(f, " yields ")?;
-                yield_ty.hir_fmt(f)?;
-
-                write!(f, " -> ")?;
-                return_ty.hir_fmt(f)?;
-            }
             TyKind::CoroutineWitness(..) => write!(f, "{{coroutine witness}}")?,
             TyKind::Pat(_, _) => write!(f, "{{pat}}")?,
             TyKind::UnsafeBinder(_) => write!(f, "{{unsafe binder}}")?,
-            TyKind::CoroutineClosure(_, _) => write!(f, "{{coroutine closure}}")?,
             TyKind::Alias(_, _) => write!(f, "{{alias}}")?,
         }
         Ok(())
     }
 }
 
-fn hir_fmt_generics(
-    f: &mut HirFormatter<'_>,
-    parameters: &[GenericArg],
+fn hir_fmt_generics<'db>(
+    f: &mut HirFormatter<'_, 'db>,
+    parameters: &[GenericArg<'db>],
     generic_def: Option<hir_def::GenericDefId>,
-    self_: Option<&Ty>,
+    self_: Option<Ty<'db>>,
 ) -> Result<(), HirDisplayError> {
     if parameters.is_empty() {
         return Ok(());
@@ -1743,70 +1700,23 @@
     Ok(())
 }
 
-fn hir_fmt_generics_ns<'db>(
-    f: &mut HirFormatter<'_>,
-    parameters: &[crate::next_solver::GenericArg<'db>],
+fn generic_args_sans_defaults<'ga, 'db>(
+    f: &mut HirFormatter<'_, 'db>,
     generic_def: Option<hir_def::GenericDefId>,
-    self_: Option<crate::next_solver::Ty<'db>>,
-) -> Result<(), HirDisplayError> {
-    if parameters.is_empty() {
-        return Ok(());
-    }
-
-    let parameters_to_write = generic_args_sans_defaults_ns(f, generic_def, parameters);
-
-    if !parameters_to_write.is_empty() {
-        write!(f, "<")?;
-        hir_fmt_generic_arguments_ns(f, parameters_to_write, self_)?;
-        write!(f, ">")?;
-    }
-
-    Ok(())
-}
-
-fn generic_args_sans_defaults<'ga>(
-    f: &mut HirFormatter<'_>,
-    generic_def: Option<hir_def::GenericDefId>,
-    parameters: &'ga [GenericArg],
-) -> &'ga [GenericArg] {
+    parameters: &'ga [GenericArg<'db>],
+) -> &'ga [GenericArg<'db>] {
     if f.display_kind.is_source_code() || f.omit_verbose_types() {
-        match generic_def
-            .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
-            .filter(|it| !it.is_empty())
-        {
+        match generic_def.map(|generic_def_id| f.db.generic_defaults(generic_def_id)) {
             None => parameters,
             Some(default_parameters) => {
-                let should_show = |arg: &GenericArg, i: usize| {
-                    let is_err = |arg: &GenericArg| match arg.data(Interner) {
-                        chalk_ir::GenericArgData::Lifetime(it) => {
-                            *it.data(Interner) == LifetimeData::Error
-                        }
-                        chalk_ir::GenericArgData::Ty(it) => *it.kind(Interner) == TyKind::Error,
-                        chalk_ir::GenericArgData::Const(it) => matches!(
-                            it.data(Interner).value,
-                            ConstValue::Concrete(ConcreteConst {
-                                interned: ConstScalar::Unknown,
-                                ..
-                            })
-                        ),
-                    };
-                    // if the arg is error like, render it to inform the user
-                    if is_err(arg) {
-                        return true;
-                    }
-                    // otherwise, if the arg is equal to the param default, hide it (unless the
-                    // default is an error which can happen for the trait Self type)
-                    match default_parameters.get(i) {
-                        None => true,
-                        Some(default_parameter) => {
-                            // !is_err(default_parameter.skip_binders())
-                            // &&
-                            arg != &default_parameter.clone().substitute(Interner, &parameters[..i])
-                        }
+                let should_show = |arg: GenericArg<'db>, i: usize| match default_parameters.get(i) {
+                    None => true,
+                    Some(default_parameter) => {
+                        arg != default_parameter.instantiate(f.interner, &parameters[..i])
                     }
                 };
                 let mut default_from = 0;
-                for (i, parameter) in parameters.iter().enumerate() {
+                for (i, &parameter) in parameters.iter().enumerate() {
                     if should_show(parameter, i) {
                         default_from = i + 1;
                     }
@@ -1820,114 +1730,30 @@
 }
 
 fn hir_fmt_generic_args<'db>(
-    f: &mut HirFormatter<'_>,
-    parameters: &[crate::next_solver::GenericArg<'db>],
+    f: &mut HirFormatter<'_, 'db>,
+    parameters: &[GenericArg<'db>],
     generic_def: Option<hir_def::GenericDefId>,
-    self_: Option<crate::next_solver::Ty<'db>>,
+    self_: Option<Ty<'db>>,
 ) -> Result<(), HirDisplayError> {
     if parameters.is_empty() {
         return Ok(());
     }
 
-    let parameters_to_write = generic_args_sans_defaults_ns(f, generic_def, parameters);
+    let parameters_to_write = generic_args_sans_defaults(f, generic_def, parameters);
 
     if !parameters_to_write.is_empty() {
         write!(f, "<")?;
-        hir_fmt_generic_arguments_ns(f, parameters_to_write, self_)?;
+        hir_fmt_generic_arguments(f, parameters_to_write, self_)?;
         write!(f, ">")?;
     }
 
     Ok(())
 }
 
-fn generic_args_sans_defaults_ns<'ga, 'db>(
-    f: &mut HirFormatter<'_>,
-    generic_def: Option<hir_def::GenericDefId>,
-    parameters: &'ga [crate::next_solver::GenericArg<'db>],
-) -> &'ga [crate::next_solver::GenericArg<'db>] {
-    let interner = DbInterner::new_with(f.db, Some(f.krate()), None);
-    if f.display_kind.is_source_code() || f.omit_verbose_types() {
-        match generic_def
-            .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
-            .filter(|it| !it.is_empty())
-        {
-            None => parameters,
-            Some(default_parameters) => {
-                let should_show = |arg: &crate::next_solver::GenericArg<'db>, i: usize| {
-                    let is_err = |arg: &crate::next_solver::GenericArg<'db>| match arg.kind() {
-                        rustc_type_ir::GenericArgKind::Lifetime(it) => {
-                            matches!(it.kind(), RegionKind::ReError(..))
-                        }
-                        rustc_type_ir::GenericArgKind::Type(it) => {
-                            matches!(it.kind(), rustc_type_ir::TyKind::Error(..))
-                        }
-                        rustc_type_ir::GenericArgKind::Const(it) => {
-                            matches!(it.kind(), rustc_type_ir::ConstKind::Error(..),)
-                        }
-                    };
-                    // if the arg is error like, render it to inform the user
-                    if is_err(arg) {
-                        return true;
-                    }
-                    // otherwise, if the arg is equal to the param default, hide it (unless the
-                    // default is an error which can happen for the trait Self type)
-                    match default_parameters.get(i) {
-                        None => true,
-                        Some(default_parameter) => {
-                            // !is_err(default_parameter.skip_binders())
-                            // &&
-                            arg != &default_parameter
-                                .clone()
-                                .substitute(
-                                    Interner,
-                                    &convert_args_for_result(interner, &parameters[..i]),
-                                )
-                                .to_nextsolver(interner)
-                        }
-                    }
-                };
-                let mut default_from = 0;
-                for (i, parameter) in parameters.iter().enumerate() {
-                    if should_show(parameter, i) {
-                        default_from = i + 1;
-                    }
-                }
-                &parameters[0..default_from]
-            }
-        }
-    } else {
-        parameters
-    }
-}
-
-fn hir_fmt_generic_arguments(
-    f: &mut HirFormatter<'_>,
-    parameters: &[GenericArg],
-    self_: Option<&Ty>,
-) -> Result<(), HirDisplayError> {
-    let mut first = true;
-    let lifetime_offset = parameters.iter().position(|arg| arg.lifetime(Interner).is_some());
-
-    let (ty_or_const, lifetimes) = match lifetime_offset {
-        Some(offset) => parameters.split_at(offset),
-        None => (parameters, &[][..]),
-    };
-    for generic_arg in lifetimes.iter().chain(ty_or_const) {
-        if !mem::take(&mut first) {
-            write!(f, ", ")?;
-        }
-        match self_ {
-            self_ @ Some(_) if generic_arg.ty(Interner) == self_ => write!(f, "Self")?,
-            _ => generic_arg.hir_fmt(f)?,
-        }
-    }
-    Ok(())
-}
-
-fn hir_fmt_generic_arguments_ns<'db>(
-    f: &mut HirFormatter<'_>,
-    parameters: &[crate::next_solver::GenericArg<'db>],
-    self_: Option<crate::next_solver::Ty<'db>>,
+fn hir_fmt_generic_arguments<'db>(
+    f: &mut HirFormatter<'_, 'db>,
+    parameters: &[GenericArg<'db>],
+    self_: Option<Ty<'db>>,
 ) -> Result<(), HirDisplayError> {
     let mut first = true;
     let lifetime_offset = parameters.iter().position(|arg| arg.region().is_some());
@@ -1948,9 +1774,28 @@
     Ok(())
 }
 
-impl HirDisplay for CallableSig {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-        let CallableSig { params_and_return: _, is_varargs, safety, abi: _ } = *self;
+fn hir_fmt_tys<'db>(
+    f: &mut HirFormatter<'_, 'db>,
+    tys: &[Ty<'db>],
+    self_: Option<Ty<'db>>,
+) -> Result<(), HirDisplayError> {
+    let mut first = true;
+
+    for ty in tys {
+        if !mem::take(&mut first) {
+            write!(f, ", ")?;
+        }
+        match self_ {
+            Some(self_) if *ty == self_ => write!(f, "Self")?,
+            _ => ty.hir_fmt(f)?,
+        }
+    }
+    Ok(())
+}
+
+impl<'db> HirDisplay<'db> for PolyFnSig<'db> {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+        let FnSig { inputs_and_output, c_variadic, safety, abi: _ } = self.skip_binder();
         if let Safety::Unsafe = safety {
             write!(f, "unsafe ")?;
         }
@@ -1961,16 +1806,16 @@
         //     f.write_str("\" ")?;
         // }
         write!(f, "fn(")?;
-        f.write_joined(self.params(), ", ")?;
-        if is_varargs {
-            if self.params().is_empty() {
+        f.write_joined(inputs_and_output.inputs(), ", ")?;
+        if c_variadic {
+            if inputs_and_output.inputs().is_empty() {
                 write!(f, "...")?;
             } else {
                 write!(f, ", ...")?;
             }
         }
         write!(f, ")")?;
-        let ret = self.ret();
+        let ret = inputs_and_output.output();
         if !ret.is_unit() {
             write!(f, " -> ")?;
             ret.hir_fmt(f)?;
@@ -1979,6 +1824,15 @@
     }
 }
 
+impl<'db> HirDisplay<'db> for Term<'db> {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+        match self {
+            Term::Ty(it) => it.hir_fmt(f),
+            Term::Const(it) => it.hir_fmt(f),
+        }
+    }
+}
+
 fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = TraitId> + '_ {
     let krate = trait_.lookup(db).container.krate();
     utils::fn_traits(db, krate)
@@ -2002,11 +1856,11 @@
     }
 }
 
-pub fn write_bounds_like_dyn_trait_with_prefix(
-    f: &mut HirFormatter<'_>,
+pub fn write_bounds_like_dyn_trait_with_prefix<'db>(
+    f: &mut HirFormatter<'_, 'db>,
     prefix: &str,
-    this: Either<&Ty, &Lifetime>,
-    predicates: &[QuantifiedWhereClause],
+    this: Either<Ty<'db>, Region<'db>>,
+    predicates: &[Clause<'db>],
     default_sized: SizedByDefault,
 ) -> Result<(), HirDisplayError> {
     write!(f, "{prefix}")?;
@@ -2020,10 +1874,10 @@
     }
 }
 
-fn write_bounds_like_dyn_trait(
-    f: &mut HirFormatter<'_>,
-    this: Either<&Ty, &Lifetime>,
-    predicates: &[QuantifiedWhereClause],
+fn write_bounds_like_dyn_trait<'db>(
+    f: &mut HirFormatter<'_, 'db>,
+    this: Either<Ty<'db>, Region<'db>>,
+    predicates: &[Clause<'db>],
     default_sized: SizedByDefault,
 ) -> Result<(), HirDisplayError> {
     // Note: This code is written to produce nice results (i.e.
@@ -2036,10 +1890,10 @@
     let mut angle_open = false;
     let mut is_fn_trait = false;
     let mut is_sized = false;
-    for p in predicates.iter() {
-        match p.skip_binders() {
-            WhereClause::Implemented(trait_ref) => {
-                let trait_ = trait_ref.hir_trait_id();
+    for p in predicates {
+        match p.kind().skip_binder() {
+            ClauseKind::Trait(trait_ref) => {
+                let trait_ = trait_ref.def_id().0;
                 if default_sized.is_sized_trait(trait_, f.db) {
                     is_sized = true;
                     if matches!(default_sized, SizedByDefault::Sized { .. }) {
@@ -2064,31 +1918,30 @@
                 write!(f, "{}", f.db.trait_signature(trait_).name.display(f.db, f.edition()))?;
                 f.end_location_link();
                 if is_fn_trait {
-                    if let [self_, params @ ..] = trait_ref.substitution.as_slice(Interner)
-                        && let Some(args) =
-                            params.first().and_then(|it| it.assert_ty_ref(Interner).as_tuple())
+                    if let [_self, params @ ..] = trait_ref.trait_ref.args.as_slice()
+                        && let Some(args) = params.first().and_then(|it| it.ty()?.as_tuple())
                     {
                         write!(f, "(")?;
-                        hir_fmt_generic_arguments(f, args.as_slice(Interner), self_.ty(Interner))?;
+                        hir_fmt_tys(f, args.as_slice(), Some(trait_ref.trait_ref.self_ty()))?;
                         write!(f, ")")?;
                     }
                 } else {
                     let params = generic_args_sans_defaults(
                         f,
                         Some(trait_.into()),
-                        trait_ref.substitution.as_slice(Interner),
+                        trait_ref.trait_ref.args.as_slice(),
                     );
-                    if let [self_, params @ ..] = params
+                    if let [_self, params @ ..] = params
                         && !params.is_empty()
                     {
                         write!(f, "<")?;
-                        hir_fmt_generic_arguments(f, params, self_.ty(Interner))?;
+                        hir_fmt_generic_arguments(f, params, Some(trait_ref.trait_ref.self_ty()))?;
                         // there might be assoc type bindings, so we leave the angle brackets open
                         angle_open = true;
                     }
                 }
             }
-            WhereClause::TypeOutlives(to) if Either::Left(&to.ty) == this => {
+            ClauseKind::TypeOutlives(to) if Either::Left(to.0) == this => {
                 if !is_fn_trait && angle_open {
                     write!(f, ">")?;
                     angle_open = false;
@@ -2096,10 +1949,9 @@
                 if !first {
                     write!(f, " + ")?;
                 }
-                to.lifetime.hir_fmt(f)?;
+                to.1.hir_fmt(f)?;
             }
-            WhereClause::TypeOutlives(_) => {}
-            WhereClause::LifetimeOutlives(lo) if Either::Right(&lo.a) == this => {
+            ClauseKind::RegionOutlives(lo) if Either::Right(lo.0) == this => {
                 if !is_fn_trait && angle_open {
                     write!(f, ">")?;
                     angle_open = false;
@@ -2107,17 +1959,16 @@
                 if !first {
                     write!(f, " + ")?;
                 }
-                lo.b.hir_fmt(f)?;
+                lo.1.hir_fmt(f)?;
             }
-            WhereClause::LifetimeOutlives(_) => {}
-            WhereClause::AliasEq(alias_eq) if is_fn_trait => {
+            ClauseKind::Projection(projection) if is_fn_trait => {
                 is_fn_trait = false;
-                if !alias_eq.ty.is_unit() {
+                if !projection.term.as_type().is_some_and(|it| it.is_unit()) {
                     write!(f, " -> ")?;
-                    alias_eq.ty.hir_fmt(f)?;
+                    projection.term.hir_fmt(f)?;
                 }
             }
-            WhereClause::AliasEq(AliasEq { ty, alias }) => {
+            ClauseKind::Projection(projection) => {
                 // in types in actual Rust, these will always come
                 // after the corresponding Implemented predicate
                 if angle_open {
@@ -2126,28 +1977,22 @@
                     write!(f, "<")?;
                     angle_open = true;
                 }
-                if let AliasTy::Projection(proj) = alias {
-                    let assoc_ty_id = from_assoc_type_id(proj.associated_ty_id);
-                    let type_alias = f.db.type_alias_signature(assoc_ty_id);
-                    f.start_location_link(assoc_ty_id.into());
-                    write!(f, "{}", type_alias.name.display(f.db, f.edition()))?;
-                    f.end_location_link();
+                let assoc_ty_id = projection.def_id().expect_type_alias();
+                let type_alias = f.db.type_alias_signature(assoc_ty_id);
+                f.start_location_link(assoc_ty_id.into());
+                write!(f, "{}", type_alias.name.display(f.db, f.edition()))?;
+                f.end_location_link();
 
-                    let proj_arg_count = generics(f.db, assoc_ty_id.into()).len_self();
-                    let parent_len = proj.substitution.len(Interner) - proj_arg_count;
-                    if proj_arg_count > 0 {
-                        write!(f, "<")?;
-                        hir_fmt_generic_arguments(
-                            f,
-                            &proj.substitution.as_slice(Interner)[parent_len..],
-                            None,
-                        )?;
-                        write!(f, ">")?;
-                    }
-                    write!(f, " = ")?;
+                let own_args = projection.projection_term.own_args(f.interner);
+                if !own_args.is_empty() {
+                    write!(f, "<")?;
+                    hir_fmt_generic_arguments(f, own_args.as_slice(), None)?;
+                    write!(f, ">")?;
                 }
-                ty.hir_fmt(f)?;
+                write!(f, " = ")?;
+                projection.term.hir_fmt(f)?;
             }
+            _ => {}
         }
         first = false;
     }
@@ -2177,154 +2022,52 @@
     Ok(())
 }
 
-impl HirDisplay for TraitRef {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-        let trait_ = self.hir_trait_id();
-        f.start_location_link(trait_.into());
-        write!(f, "{}", f.db.trait_signature(trait_).name.display(f.db, f.edition()))?;
-        f.end_location_link();
-        let substs = self.substitution.as_slice(Interner);
-        hir_fmt_generics(f, &substs[1..], None, substs[0].ty(Interner))
-    }
-}
-
-impl<'db> HirDisplay for crate::next_solver::TraitRef<'db> {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for TraitRef<'db> {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         let trait_ = self.def_id.0;
         f.start_location_link(trait_.into());
         write!(f, "{}", f.db.trait_signature(trait_).name.display(f.db, f.edition()))?;
         f.end_location_link();
         let substs = self.args.as_slice();
-        hir_fmt_generic_args(f, &substs[1..], None, substs[0].ty())
+        hir_fmt_generic_args(f, &substs[1..], None, Some(self.self_ty()))
     }
 }
 
-impl HirDisplay for WhereClause {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-        if f.should_truncate() {
-            return write!(f, "{TYPE_HINT_TRUNCATION}");
-        }
-
-        match self {
-            WhereClause::Implemented(trait_ref) => {
-                trait_ref.self_type_parameter(Interner).hir_fmt(f)?;
-                write!(f, ": ")?;
-                trait_ref.hir_fmt(f)?;
-            }
-            WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
-                write!(f, "<")?;
-                let trait_ref = &projection_ty.trait_ref(f.db);
-                trait_ref.self_type_parameter(Interner).hir_fmt(f)?;
-                write!(f, " as ")?;
-                trait_ref.hir_fmt(f)?;
-                write!(f, ">::",)?;
-                let type_alias = from_assoc_type_id(projection_ty.associated_ty_id);
-                f.start_location_link(type_alias.into());
-                write!(
-                    f,
-                    "{}",
-                    f.db.type_alias_signature(type_alias).name.display(f.db, f.edition()),
-                )?;
-                f.end_location_link();
-                write!(f, " = ")?;
-                ty.hir_fmt(f)?;
-            }
-            WhereClause::AliasEq(_) => write!(f, "{{error}}")?,
-
-            // FIXME implement these
-            WhereClause::TypeOutlives(..) => {}
-            WhereClause::LifetimeOutlives(..) => {}
-        }
-        Ok(())
-    }
-}
-
-impl HirDisplay for LifetimeOutlives {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-        self.a.hir_fmt(f)?;
-        write!(f, ": ")?;
-        self.b.hir_fmt(f)
-    }
-}
-
-impl HirDisplay for Lifetime {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-        self.interned().hir_fmt(f)
-    }
-}
-
-impl HirDisplay for LifetimeData {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-        match self {
-            LifetimeData::Placeholder(idx) => {
-                let id = lt_from_placeholder_idx(f.db, *idx).0;
-                let generics = generics(f.db, id.parent);
-                let param_data = &generics[id.local_id];
-                write!(f, "{}", param_data.name.display(f.db, f.edition()))?;
-                Ok(())
-            }
-            LifetimeData::BoundVar(idx) => idx.hir_fmt(f),
-            LifetimeData::InferenceVar(_) => write!(f, "_"),
-            LifetimeData::Static => write!(f, "'static"),
-            LifetimeData::Error => {
-                if cfg!(test) {
-                    write!(f, "'?")
-                } else {
-                    write!(f, "'_")
-                }
-            }
-            LifetimeData::Erased => write!(f, "'<erased>"),
-            LifetimeData::Phantom(void, _) => match *void {},
-        }
-    }
-}
-
-impl<'db> HirDisplay for crate::next_solver::Region<'db> {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Region<'db> {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         match self.kind() {
-            rustc_type_ir::RegionKind::ReEarlyParam(param) => {
+            RegionKind::ReEarlyParam(param) => {
                 let generics = generics(f.db, param.id.parent);
                 let param_data = &generics[param.id.local_id];
                 write!(f, "{}", param_data.name.display(f.db, f.edition()))?;
                 Ok(())
             }
-            rustc_type_ir::RegionKind::ReBound(db, idx) => {
+            RegionKind::ReBound(BoundVarIndexKind::Bound(db), idx) => {
                 write!(f, "?{}.{}", db.as_u32(), idx.var.as_u32())
             }
-            rustc_type_ir::RegionKind::ReVar(_) => write!(f, "_"),
-            rustc_type_ir::RegionKind::ReStatic => write!(f, "'static"),
-            rustc_type_ir::RegionKind::ReError(..) => {
+            RegionKind::ReBound(BoundVarIndexKind::Canonical, idx) => {
+                write!(f, "?c.{}", idx.var.as_u32())
+            }
+            RegionKind::ReVar(_) => write!(f, "_"),
+            RegionKind::ReStatic => write!(f, "'static"),
+            RegionKind::ReError(..) => {
                 if cfg!(test) {
                     write!(f, "'?")
                 } else {
                     write!(f, "'_")
                 }
             }
-            rustc_type_ir::RegionKind::ReErased => write!(f, "'<erased>"),
-            rustc_type_ir::RegionKind::RePlaceholder(_) => write!(f, "<placeholder>"),
-            rustc_type_ir::RegionKind::ReLateParam(_) => write!(f, "<late-param>"),
+            RegionKind::ReErased => write!(f, "'<erased>"),
+            RegionKind::RePlaceholder(_) => write!(f, "<placeholder>"),
+            RegionKind::ReLateParam(_) => write!(f, "<late-param>"),
         }
     }
 }
 
-impl HirDisplay for DomainGoal {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-        match self {
-            DomainGoal::Holds(wc) => {
-                write!(f, "Holds(")?;
-                wc.hir_fmt(f)?;
-                write!(f, ")")?;
-            }
-            _ => write!(f, "_")?,
-        }
-        Ok(())
-    }
-}
-
-pub fn write_visibility(
+pub fn write_visibility<'db>(
     module_id: ModuleId,
     vis: Visibility,
-    f: &mut HirFormatter<'_>,
+    f: &mut HirFormatter<'_, 'db>,
 ) -> Result<(), HirDisplayError> {
     match vis {
         Visibility::Public => write!(f, "pub "),
@@ -2346,28 +2089,30 @@
     }
 }
 
-pub trait HirDisplayWithExpressionStore {
+pub trait HirDisplayWithExpressionStore<'db> {
     fn hir_fmt(
         &self,
-        f: &mut HirFormatter<'_>,
+        f: &mut HirFormatter<'_, 'db>,
         store: &ExpressionStore,
     ) -> Result<(), HirDisplayError>;
 }
 
-impl<T: ?Sized + HirDisplayWithExpressionStore> HirDisplayWithExpressionStore for &'_ T {
+impl<'db, T: ?Sized + HirDisplayWithExpressionStore<'db>> HirDisplayWithExpressionStore<'db>
+    for &'_ T
+{
     fn hir_fmt(
         &self,
-        f: &mut HirFormatter<'_>,
+        f: &mut HirFormatter<'_, 'db>,
         store: &ExpressionStore,
     ) -> Result<(), HirDisplayError> {
         T::hir_fmt(&**self, f, store)
     }
 }
 
-pub fn hir_display_with_store<'a, T: HirDisplayWithExpressionStore + 'a>(
+pub fn hir_display_with_store<'a, 'db, T: HirDisplayWithExpressionStore<'db> + 'a>(
     value: T,
     store: &'a ExpressionStore,
-) -> impl HirDisplay + 'a {
+) -> impl HirDisplay<'db> + 'a {
     ExpressionStoreAdapter(value, store)
 }
 
@@ -2379,15 +2124,15 @@
     }
 }
 
-impl<T: HirDisplayWithExpressionStore> HirDisplay for ExpressionStoreAdapter<'_, T> {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db, T: HirDisplayWithExpressionStore<'db>> HirDisplay<'db> for ExpressionStoreAdapter<'_, T> {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         T::hir_fmt(&self.0, f, self.1)
     }
 }
-impl HirDisplayWithExpressionStore for LifetimeRefId {
+impl<'db> HirDisplayWithExpressionStore<'db> for LifetimeRefId {
     fn hir_fmt(
         &self,
-        f: &mut HirFormatter<'_>,
+        f: &mut HirFormatter<'_, 'db>,
         store: &ExpressionStore,
     ) -> Result<(), HirDisplayError> {
         match &store[*self] {
@@ -2407,10 +2152,10 @@
     }
 }
 
-impl HirDisplayWithExpressionStore for TypeRefId {
+impl<'db> HirDisplayWithExpressionStore<'db> for TypeRefId {
     fn hir_fmt(
         &self,
-        f: &mut HirFormatter<'_>,
+        f: &mut HirFormatter<'_, 'db>,
         store: &ExpressionStore,
     ) -> Result<(), HirDisplayError> {
         match &store[*self] {
@@ -2536,10 +2281,10 @@
     }
 }
 
-impl HirDisplayWithExpressionStore for ConstRef {
+impl<'db> HirDisplayWithExpressionStore<'db> for ConstRef {
     fn hir_fmt(
         &self,
-        f: &mut HirFormatter<'_>,
+        f: &mut HirFormatter<'_, 'db>,
         _store: &ExpressionStore,
     ) -> Result<(), HirDisplayError> {
         // FIXME
@@ -2549,10 +2294,10 @@
     }
 }
 
-impl HirDisplayWithExpressionStore for TypeBound {
+impl<'db> HirDisplayWithExpressionStore<'db> for TypeBound {
     fn hir_fmt(
         &self,
-        f: &mut HirFormatter<'_>,
+        f: &mut HirFormatter<'_, 'db>,
         store: &ExpressionStore,
     ) -> Result<(), HirDisplayError> {
         match self {
@@ -2593,10 +2338,10 @@
     }
 }
 
-impl HirDisplayWithExpressionStore for Path {
+impl<'db> HirDisplayWithExpressionStore<'db> for Path {
     fn hir_fmt(
         &self,
-        f: &mut HirFormatter<'_>,
+        f: &mut HirFormatter<'_, 'db>,
         store: &ExpressionStore,
     ) -> Result<(), HirDisplayError> {
         match (self.type_anchor(), self.kind()) {
@@ -2745,10 +2490,10 @@
     }
 }
 
-impl HirDisplayWithExpressionStore for hir_def::expr_store::path::GenericArg {
+impl<'db> HirDisplayWithExpressionStore<'db> for hir_def::expr_store::path::GenericArg {
     fn hir_fmt(
         &self,
-        f: &mut HirFormatter<'_>,
+        f: &mut HirFormatter<'_, 'db>,
         store: &ExpressionStore,
     ) -> Result<(), HirDisplayError> {
         match self {
diff --git a/crates/hir-ty/src/drop.rs b/crates/hir-ty/src/drop.rs
index aaf2747..b09d1fb 100644
--- a/crates/hir-ty/src/drop.rs
+++ b/crates/hir-ty/src/drop.rs
@@ -85,7 +85,7 @@
                     {
                         return DropGlue::None;
                     }
-                    db.field_types_ns(id.into())
+                    db.field_types(id.into())
                         .iter()
                         .map(|(_, field_ty)| {
                             has_drop_glue_impl(
@@ -105,7 +105,7 @@
                     .variants
                     .iter()
                     .map(|&(variant, _, _)| {
-                        db.field_types_ns(variant.into())
+                        db.field_types(variant.into())
                             .iter()
                             .map(|(_, field_ty)| {
                                 has_drop_glue_impl(
diff --git a/crates/hir-ty/src/dyn_compatibility.rs b/crates/hir-ty/src/dyn_compatibility.rs
index b2406a0..437141e 100644
--- a/crates/hir-ty/src/dyn_compatibility.rs
+++ b/crates/hir-ty/src/dyn_compatibility.rs
@@ -7,7 +7,6 @@
     TypeAliasId, TypeOrConstParamId, TypeParamId, hir::generics::LocalTypeOrConstParamId,
     lang_item::LangItem, signatures::TraitFlags,
 };
-use intern::Symbol;
 use rustc_hash::FxHashSet;
 use rustc_type_ir::{
     AliasTyKind, ClauseKind, PredicatePolarity, TypeSuperVisitable as _, TypeVisitable as _,
@@ -19,10 +18,10 @@
 use crate::{
     ImplTraitId,
     db::{HirDatabase, InternedOpaqueTyId},
-    lower_nextsolver::associated_ty_item_bounds,
+    lower::associated_ty_item_bounds,
     next_solver::{
-        Clause, Clauses, DbInterner, GenericArgs, ParamEnv, SolverDefId, TraitPredicate, TraitRef,
-        TypingMode, infer::DbInternerInferExt, mk_param,
+        Binder, Clause, Clauses, DbInterner, EarlyBinder, GenericArgs, Goal, ParamEnv, ParamTy,
+        SolverDefId, TraitPredicate, TraitRef, Ty, TypingMode, infer::DbInternerInferExt, mk_param,
     },
     traits::next_trait_solve_in_ctxt,
 };
@@ -137,7 +136,7 @@
     };
 
     let interner = DbInterner::new_with(db, Some(krate), None);
-    let predicates = db.generic_predicates_ns(def);
+    let predicates = db.generic_predicates(def);
     // FIXME: We should use `explicit_predicates_of` here, which hasn't been implemented to
     // rust-analyzer yet
     // https://github.com/rust-lang/rust/blob/ddaf12390d3ffb7d5ba74491a48f3cd528e5d777/compiler/rustc_hir_analysis/src/collect/predicates_of.rs#L490
@@ -163,7 +162,7 @@
 // but we don't have good way to render such locations.
 // So, just return single boolean value for existence of such `Self` reference
 fn predicates_reference_self(db: &dyn HirDatabase, trait_: TraitId) -> bool {
-    db.generic_predicates_ns(trait_.into())
+    db.generic_predicates(trait_.into())
         .iter()
         .any(|pred| predicate_references_self(db, trait_, pred, AllowSelfProjection::No))
 }
@@ -379,7 +378,7 @@
         }) = pred
             && let trait_data = db.trait_signature(pred_trait_ref.def_id.0)
             && trait_data.flags.contains(TraitFlags::AUTO)
-            && let rustc_type_ir::TyKind::Param(crate::next_solver::ParamTy { index: 0, .. }) =
+            && let rustc_type_ir::TyKind::Param(ParamTy { index: 0, .. }) =
                 pred_trait_ref.self_ty().kind()
         {
             continue;
@@ -398,10 +397,7 @@
     db: &dyn HirDatabase,
     trait_: TraitId,
     func: FunctionId,
-    sig: &crate::next_solver::EarlyBinder<
-        'db,
-        crate::next_solver::Binder<'db, rustc_type_ir::FnSig<DbInterner<'db>>>,
-    >,
+    sig: &EarlyBinder<'db, Binder<'db, rustc_type_ir::FnSig<DbInterner<'db>>>>,
 ) -> bool {
     let sig = sig.instantiate_identity();
 
@@ -410,10 +406,8 @@
         parent: trait_.into(),
         local_id: LocalTypeOrConstParamId::from_raw(la_arena::RawIdx::from_u32(0)),
     });
-    let self_param_ty = crate::next_solver::Ty::new(
-        interner,
-        rustc_type_ir::TyKind::Param(crate::next_solver::ParamTy { index: 0, id: self_param_id }),
-    );
+    let self_param_ty =
+        Ty::new(interner, rustc_type_ir::TyKind::Param(ParamTy { index: 0, id: self_param_id }));
 
     // `self: Self` can't be dispatched on, but this is already considered dyn-compatible
     // See rustc's comment on https://github.com/rust-lang/rust/blob/3f121b9461cce02a703a0e7e450568849dfaa074/compiler/rustc_trait_selection/src/traits/object_safety.rs#L433-L437
@@ -441,21 +435,20 @@
 
     // Type `U`
     // FIXME: That seems problematic to fake a generic param like that?
-    let unsized_self_ty =
-        crate::next_solver::Ty::new_param(interner, self_param_id, u32::MAX, Symbol::empty());
+    let unsized_self_ty = Ty::new_param(interner, self_param_id, u32::MAX);
     // `Receiver[Self => U]`
     let unsized_receiver_ty = receiver_for_self_ty(interner, func, receiver_ty, unsized_self_ty);
 
     let param_env = {
-        let generic_predicates = &*db.generic_predicates_ns(func.into());
+        let generic_predicates = &*db.generic_predicates(func.into());
 
         // Self: Unsize<U>
         let unsize_predicate =
             TraitRef::new(interner, unsize_did.into(), [self_param_ty, unsized_self_ty]);
 
         // U: Trait<Arg1, ..., ArgN>
-        let args = GenericArgs::for_item(interner, trait_.into(), |name, index, kind, _| {
-            if index == 0 { unsized_self_ty.into() } else { mk_param(interner, index, name, kind) }
+        let args = GenericArgs::for_item(interner, trait_.into(), |index, kind, _| {
+            if index == 0 { unsized_self_ty.into() } else { mk_param(interner, index, kind) }
         });
         let trait_predicate = TraitRef::new_from_args(interner, trait_.into(), args);
 
@@ -477,7 +470,7 @@
     // Receiver: DispatchFromDyn<Receiver[Self => U]>
     let predicate =
         TraitRef::new(interner, dispatch_from_dyn_did.into(), [receiver_ty, unsized_receiver_ty]);
-    let goal = crate::next_solver::Goal::new(interner, param_env, predicate);
+    let goal = Goal::new(interner, param_env, predicate);
 
     let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis());
     // the receiver is dispatchable iff the obligation holds
@@ -488,26 +481,19 @@
 fn receiver_for_self_ty<'db>(
     interner: DbInterner<'db>,
     func: FunctionId,
-    receiver_ty: crate::next_solver::Ty<'db>,
-    self_ty: crate::next_solver::Ty<'db>,
-) -> crate::next_solver::Ty<'db> {
-    let args = crate::next_solver::GenericArgs::for_item(
-        interner,
-        SolverDefId::FunctionId(func),
-        |name, index, kind, _| {
-            if index == 0 { self_ty.into() } else { mk_param(interner, index, name, kind) }
-        },
-    );
+    receiver_ty: Ty<'db>,
+    self_ty: Ty<'db>,
+) -> Ty<'db> {
+    let args = GenericArgs::for_item(interner, SolverDefId::FunctionId(func), |index, kind, _| {
+        if index == 0 { self_ty.into() } else { mk_param(interner, index, kind) }
+    });
 
-    crate::next_solver::EarlyBinder::bind(receiver_ty).instantiate(interner, args)
+    EarlyBinder::bind(receiver_ty).instantiate(interner, args)
 }
 
 fn contains_illegal_impl_trait_in_trait<'db>(
     db: &'db dyn HirDatabase,
-    sig: &crate::next_solver::EarlyBinder<
-        'db,
-        crate::next_solver::Binder<'db, rustc_type_ir::FnSig<DbInterner<'db>>>,
-    >,
+    sig: &EarlyBinder<'db, Binder<'db, rustc_type_ir::FnSig<DbInterner<'db>>>>,
 ) -> Option<MethodViolationCode> {
     struct OpaqueTypeCollector(FxHashSet<InternedOpaqueTyId>);
 
diff --git a/crates/hir-ty/src/generics.rs b/crates/hir-ty/src/generics.rs
index e179e41..26e03aa 100644
--- a/crates/hir-ty/src/generics.rs
+++ b/crates/hir-ty/src/generics.rs
@@ -9,7 +9,6 @@
 //! where parent follows the same scheme.
 use std::ops;
 
-use chalk_ir::{BoundVar, DebruijnIndex, cast::Cast as _};
 use hir_def::{
     ConstParamId, GenericDefId, GenericParamId, ItemContainerId, LifetimeParamId, Lookup,
     TypeOrConstParamId, TypeParamId,
@@ -23,8 +22,6 @@
 use itertools::chain;
 use triomphe::Arc;
 
-use crate::{Interner, Substitution, db::HirDatabase, lt_to_placeholder_idx, to_placeholder_idx};
-
 pub fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
     let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def)));
     let (params, store) = db.generic_params_and_store(def);
@@ -130,11 +127,16 @@
 
     /// 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 parent = self.len_parent();
         let child = self.params.len();
         parent + child
     }
 
+    #[inline]
+    pub(crate) fn len_parent(&self) -> usize {
+        self.parent_generics().map_or(0, Generics::len)
+    }
+
     /// Returns numbers of generic parameters excluding those from parent.
     pub(crate) fn len_self(&self) -> usize {
         self.params.len()
@@ -225,50 +227,6 @@
     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 fn placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution {
-        Substitution::from_iter(
-            Interner,
-            self.iter_id().enumerate().map(|(index, id)| match id {
-                GenericParamId::TypeParamId(id) => {
-                    to_placeholder_idx(db, id.into(), index as u32).to_ty(Interner).cast(Interner)
-                }
-                GenericParamId::ConstParamId(id) => to_placeholder_idx(db, id.into(), index as u32)
-                    .to_const(Interner, db.const_param_ty(id))
-                    .cast(Interner),
-                GenericParamId::LifetimeParamId(id) => {
-                    lt_to_placeholder_idx(db, id, index as u32).to_lifetime(Interner).cast(Interner)
-                }
-            }),
-        )
-    }
 }
 
 pub(crate) fn trait_self_param_idx(db: &dyn DefDatabase, def: GenericDefId) -> Option<usize> {
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 7249868..361e665 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -55,29 +55,24 @@
 use triomphe::Arc;
 
 use crate::{
-    ImplTraitId, IncorrectGenericsLenKind, Interner, PathLoweringDiagnostic, TargetFeatures,
-    TraitEnvironment,
+    ImplTraitId, IncorrectGenericsLenKind, PathLoweringDiagnostic, TargetFeatures,
     db::{HirDatabase, InternedClosureId, InternedOpaqueTyId},
-    generics::Generics,
     infer::{
         coerce::{CoerceMany, DynamicCoerceMany},
         diagnostics::{Diagnostics, InferenceTyLoweringContext as TyLoweringContext},
         expr::ExprIsRead,
         unify::InferenceTable,
     },
-    lower::diagnostics::TyLoweringDiagnostic,
-    lower_nextsolver::{ImplTraitIdx, ImplTraitLoweringMode, LifetimeElisionKind},
+    lower::{
+        ImplTraitIdx, ImplTraitLoweringMode, LifetimeElisionKind, diagnostics::TyLoweringDiagnostic,
+    },
     mir::MirSpan,
     next_solver::{
         AliasTy, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, Region, Ty, TyKind,
         Tys,
         abi::Safety,
         fold::fold_tys,
-        infer::{
-            DefineOpaqueTypes,
-            traits::{Obligation, ObligationCause},
-        },
-        mapping::{ChalkToNextSolver, NextSolverToChalk},
+        infer::traits::{Obligation, ObligationCause},
     },
     traits::FnTrait,
     utils::TargetFeatureIsSafeInTarget,
@@ -166,31 +161,6 @@
     })
 }
 
-/// Fully normalize all the types found within `ty` in context of `owner` body definition.
-///
-/// This is appropriate to use only after type-check: it assumes
-/// that normalization will succeed, for example.
-#[tracing::instrument(level = "debug", skip(db))]
-pub(crate) fn normalize(
-    db: &dyn HirDatabase,
-    trait_env: Arc<TraitEnvironment<'_>>,
-    ty: crate::Ty,
-) -> crate::Ty {
-    // FIXME: TypeFlags::HAS_CT_PROJECTION is not implemented in chalk, so TypeFlags::HAS_PROJECTION only
-    // works for the type case, so we check array unconditionally. Remove the array part
-    // when the bug in chalk becomes fixed.
-    if !ty.data(Interner).flags.intersects(crate::TypeFlags::HAS_PROJECTION)
-        && !matches!(ty.kind(Interner), crate::TyKind::Array(..))
-    {
-        return ty;
-    }
-    let mut table = unify::InferenceTable::new(db, trait_env);
-
-    let ty_with_vars = table.normalize_associated_types_in(ty.to_nextsolver(table.interner()));
-    table.select_obligations_where_possible();
-    table.resolve_completely(ty_with_vars).to_chalk(table.interner())
-}
-
 /// Binding modes inferred for patterns.
 /// <https://doc.rust-lang.org/reference/patterns.html#binding-modes>
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
@@ -789,8 +759,7 @@
     /// and resolve the path via its methods. This will ensure proper error reporting.
     pub(crate) resolver: Resolver<'db>,
     target_features: OnceCell<(TargetFeatures, TargetFeatureIsSafeInTarget)>,
-    generic_def: GenericDefId,
-    generics: OnceCell<Generics>,
+    pub(crate) generic_def: GenericDefId,
     table: unify::InferenceTable<'db>,
     /// The traits in scope, disregarding block modules. This is used for caching purposes.
     traits_in_scope: FxHashSet<TraitId>,
@@ -899,7 +868,6 @@
             return_ty: types.error, // set in collect_* calls
             types,
             target_features: OnceCell::new(),
-            generics: OnceCell::new(),
             table,
             tuple_field_accesses_rev: Default::default(),
             resume_yield_tys: None,
@@ -928,10 +896,6 @@
         }
     }
 
-    pub(crate) fn generics(&self) -> &Generics {
-        self.generics.get_or_init(|| crate::generics::generics(self.db, self.generic_def))
-    }
-
     #[inline]
     fn krate(&self) -> Crate {
         self.resolver.krate()
@@ -1159,7 +1123,7 @@
                     GenericArgs::for_item_with_defaults(
                         self.interner(),
                         va_list.into(),
-                        |_, _, id, _| self.table.next_var_for_param(id),
+                        |_, id, _| self.table.next_var_for_param(id),
                     ),
                 ),
                 None => self.err_ty(),
@@ -1195,7 +1159,7 @@
                     },
                 );
                 let return_ty = self.insert_type_vars(return_ty);
-                if let Some(rpits) = self.db.return_type_impl_traits_ns(func) {
+                if let Some(rpits) = self.db.return_type_impl_traits(func) {
                     let mut mode = ImplTraitReplacingMode::ReturnPosition(FxHashSet::default());
                     let result = self.insert_inference_vars_for_impl_trait(return_ty, &mut mode);
                     if let ImplTraitReplacingMode::ReturnPosition(taits) = mode {
@@ -1263,14 +1227,12 @@
                     if matches!(mode, ImplTraitReplacingMode::TypeAlias) {
                         // RPITs don't have `tait_coercion_table`, so use inserted inference
                         // vars for them.
-                        if let Some(ty) =
-                            self.result.type_of_rpit.get(idx.to_nextsolver(self.interner()))
-                        {
+                        if let Some(ty) = self.result.type_of_rpit.get(idx) {
                             return *ty;
                         }
                         return ty;
                     }
-                    (self.db.return_type_impl_traits_ns(def), idx)
+                    (self.db.return_type_impl_traits(def), idx)
                 }
                 ImplTraitId::TypeAliasImplTrait(def, idx) => {
                     if let ImplTraitReplacingMode::ReturnPosition(taits) = mode {
@@ -1279,17 +1241,15 @@
                         taits.insert(ty);
                         return ty;
                     }
-                    (self.db.type_alias_impl_traits_ns(def), idx)
+                    (self.db.type_alias_impl_traits(def), idx)
                 }
-                _ => unreachable!(),
             };
             let Some(impl_traits) = impl_traits else {
                 return ty;
             };
-            let bounds = (*impl_traits).as_ref().map_bound(|its| {
-                its.impl_traits[idx.to_nextsolver(self.interner())].predicates.as_slice()
-            });
-            let var = match self.result.type_of_rpit.entry(idx.to_nextsolver(self.interner())) {
+            let bounds =
+                (*impl_traits).as_ref().map_bound(|its| its.impl_traits[idx].predicates.as_slice());
+            let var = match self.result.type_of_rpit.entry(idx) {
                 Entry::Occupied(entry) => return *entry.get(),
                 Entry::Vacant(entry) => *entry.insert(self.table.next_ty_var()),
             };
@@ -1640,8 +1600,7 @@
             match ty.kind() {
                 TyKind::Adt(adt_def, substs) => match adt_def.def_id().0 {
                     AdtId::StructId(struct_id) => {
-                        match self.db.field_types_ns(struct_id.into()).values().next_back().copied()
-                        {
+                        match self.db.field_types(struct_id.into()).values().next_back().copied() {
                             Some(field) => {
                                 ty = field.instantiate(self.interner(), substs);
                             }
@@ -1702,7 +1661,7 @@
             .table
             .infer_ctxt
             .at(&ObligationCause::new(), self.table.trait_env.env)
-            .eq(DefineOpaqueTypes::Yes, expected, actual)
+            .eq(expected, actual)
             .map(|infer_ok| self.table.register_infer_ok(infer_ok));
         if let Err(_err) = result {
             // FIXME: Emit diagnostic.
diff --git a/crates/hir-ty/src/infer/cast.rs b/crates/hir-ty/src/infer/cast.rs
index 990281a..c128977 100644
--- a/crates/hir-ty/src/infer/cast.rs
+++ b/crates/hir-ty/src/infer/cast.rs
@@ -394,7 +394,7 @@
             let struct_data = id.fields(ctx.db);
             if let Some((last_field, _)) = struct_data.fields().iter().last() {
                 let last_field_ty =
-                    ctx.db.field_types_ns(id.into())[last_field].instantiate(ctx.interner(), subst);
+                    ctx.db.field_types(id.into())[last_field].instantiate(ctx.interner(), subst);
                 pointer_kind(last_field_ty, ctx)
             } else {
                 Ok(Some(PointerKind::Thin))
diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs
index 2637ed6..06f8307 100644
--- a/crates/hir-ty/src/infer/closure.rs
+++ b/crates/hir-ty/src/infer/closure.rs
@@ -11,8 +11,9 @@
     type_ref::TypeRefId,
 };
 use rustc_type_ir::{
-    ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, Interner, TypeSuperVisitable,
-    TypeVisitable, TypeVisitableExt, TypeVisitor,
+    ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, CoroutineClosureArgs,
+    CoroutineClosureArgsParts, Interner, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
+    TypeVisitor,
     inherent::{BoundExistentialPredicates, GenericArgs as _, IntoKind, SliceLike, Ty as _},
 };
 use tracing::debug;
@@ -22,11 +23,12 @@
     db::{InternedClosure, InternedCoroutine},
     infer::{BreakableKind, Diverges, coerce::CoerceMany},
     next_solver::{
-        AliasTy, Binder, ClauseKind, DbInterner, ErrorGuaranteed, FnSig, GenericArgs, PolyFnSig,
-        PolyProjectionPredicate, Predicate, PredicateKind, SolverDefId, Ty, TyKind,
+        AliasTy, Binder, BoundRegionKind, BoundVarKind, BoundVarKinds, ClauseKind, DbInterner,
+        ErrorGuaranteed, FnSig, GenericArgs, PolyFnSig, PolyProjectionPredicate, Predicate,
+        PredicateKind, SolverDefId, Ty, TyKind,
         abi::Safety,
         infer::{
-            BoundRegionConversionTime, DefineOpaqueTypes, InferOk, InferResult,
+            BoundRegionConversionTime, InferOk, InferResult,
             traits::{ObligationCause, PredicateObligations},
         },
         util::explicit_item_bounds,
@@ -72,6 +74,8 @@
         let sig_ty = Ty::new_fn_ptr(interner, bound_sig);
 
         let parent_args = GenericArgs::identity_for_item(interner, self.generic_def.into());
+        // FIXME: Make this an infer var and infer it later.
+        let tupled_upvars_ty = self.types.unit;
         let (id, ty, resume_yield_tys) = match closure_kind {
             ClosureKind::Coroutine(_) => {
                 let yield_ty = self.table.next_ty_var();
@@ -80,11 +84,11 @@
                 // FIXME: Infer the upvars later.
                 let parts = CoroutineArgsParts {
                     parent_args,
-                    kind_ty: Ty::new_unit(interner),
+                    kind_ty: self.types.unit,
                     resume_ty,
                     yield_ty,
                     return_ty: body_ret_ty,
-                    tupled_upvars_ty: Ty::new_unit(interner),
+                    tupled_upvars_ty,
                 };
 
                 let coroutine_id =
@@ -97,9 +101,7 @@
 
                 (None, coroutine_ty, Some((resume_ty, yield_ty)))
             }
-            // FIXME(next-solver): `ClosureKind::Async` should really be a separate arm that creates a `CoroutineClosure`.
-            // But for now we treat it as a closure.
-            ClosureKind::Closure | ClosureKind::Async => {
+            ClosureKind::Closure => {
                 let closure_id = self.db.intern_closure(InternedClosure(self.owner, tgt_expr));
                 match expected_kind {
                     Some(kind) => {
@@ -117,7 +119,7 @@
                     }
                     None => {}
                 };
-                // FIXME: Infer the kind and the upvars later when needed.
+                // FIXME: Infer the kind later if needed.
                 let parts = ClosureArgsParts {
                     parent_args,
                     closure_kind_ty: Ty::from_closure_kind(
@@ -125,7 +127,7 @@
                         expected_kind.unwrap_or(rustc_type_ir::ClosureKind::Fn),
                     ),
                     closure_sig_as_fn_ptr_ty: sig_ty,
-                    tupled_upvars_ty: Ty::new_unit(interner),
+                    tupled_upvars_ty,
                 };
                 let closure_ty = Ty::new_closure(
                     interner,
@@ -136,6 +138,61 @@
                 self.add_current_closure_dependency(closure_id);
                 (Some(closure_id), closure_ty, None)
             }
+            ClosureKind::Async => {
+                // async closures always return the type ascribed after the `->` (if present),
+                // and yield `()`.
+                let bound_return_ty = bound_sig.skip_binder().output();
+                let bound_yield_ty = self.types.unit;
+                // rustc uses a special lang item type for the resume ty. I don't believe this can cause us problems.
+                let resume_ty = self.types.unit;
+
+                // FIXME: Infer the kind later if needed.
+                let closure_kind_ty = Ty::from_closure_kind(
+                    interner,
+                    expected_kind.unwrap_or(rustc_type_ir::ClosureKind::Fn),
+                );
+
+                // FIXME: Infer captures later.
+                // `for<'env> fn() -> ()`, for no captures.
+                let coroutine_captures_by_ref_ty = Ty::new_fn_ptr(
+                    interner,
+                    Binder::bind_with_vars(
+                        interner.mk_fn_sig([], self.types.unit, false, Safety::Safe, FnAbi::Rust),
+                        BoundVarKinds::new_from_iter(
+                            interner,
+                            [BoundVarKind::Region(BoundRegionKind::ClosureEnv)],
+                        ),
+                    ),
+                );
+                let closure_args = CoroutineClosureArgs::new(
+                    interner,
+                    CoroutineClosureArgsParts {
+                        parent_args,
+                        closure_kind_ty,
+                        signature_parts_ty: Ty::new_fn_ptr(
+                            interner,
+                            bound_sig.map_bound(|sig| {
+                                interner.mk_fn_sig(
+                                    [
+                                        resume_ty,
+                                        Ty::new_tup_from_iter(interner, sig.inputs().iter()),
+                                    ],
+                                    Ty::new_tup(interner, &[bound_yield_ty, bound_return_ty]),
+                                    sig.c_variadic,
+                                    sig.safety,
+                                    sig.abi,
+                                )
+                            }),
+                        ),
+                        tupled_upvars_ty,
+                        coroutine_captures_by_ref_ty,
+                    },
+                );
+
+                let coroutine_id =
+                    self.db.intern_coroutine(InternedCoroutine(self.owner, tgt_expr)).into();
+                (None, Ty::new_coroutine_closure(interner, coroutine_id, closure_args.args), None)
+            }
         };
 
         // Now go through the argument patterns
@@ -307,7 +364,7 @@
                         .table
                         .infer_ctxt
                         .at(&ObligationCause::new(), self.table.trait_env.env)
-                        .eq(DefineOpaqueTypes::Yes, inferred_fnptr_sig, generalized_fnptr_sig)
+                        .eq(inferred_fnptr_sig, generalized_fnptr_sig)
                         .map(|infer_ok| self.table.register_infer_ok(infer_ok));
 
                     let resolved_sig =
@@ -692,18 +749,16 @@
                 let InferOk { value: (), obligations } = table
                     .infer_ctxt
                     .at(&cause, table.trait_env.env)
-                    .eq(DefineOpaqueTypes::Yes, expected_ty, supplied_ty)?;
+                    .eq(expected_ty, supplied_ty)?;
                 all_obligations.extend(obligations);
             }
 
             let supplied_output_ty = supplied_sig.output();
             let cause = ObligationCause::new();
-            let InferOk { value: (), obligations } =
-                table.infer_ctxt.at(&cause, table.trait_env.env).eq(
-                    DefineOpaqueTypes::Yes,
-                    expected_sigs.liberated_sig.output(),
-                    supplied_output_ty,
-                )?;
+            let InferOk { value: (), obligations } = table
+                .infer_ctxt
+                .at(&cause, table.trait_env.env)
+                .eq(expected_sigs.liberated_sig.output(), supplied_output_ty)?;
             all_obligations.extend(obligations);
 
             let inputs = supplied_sig
diff --git a/crates/hir-ty/src/infer/coerce.rs b/crates/hir-ty/src/infer/coerce.rs
index 4620da7..78889cc 100644
--- a/crates/hir-ty/src/infer/coerce.rs
+++ b/crates/hir-ty/src/infer/coerce.rs
@@ -63,7 +63,7 @@
         GenericArgs, PolyFnSig, PredicateKind, Region, RegionKind, SolverDefId, TraitRef, Ty,
         TyKind,
         infer::{
-            DefineOpaqueTypes, InferCtxt, InferOk, InferResult,
+            InferCtxt, InferOk, InferResult,
             relate::RelateResult,
             select::{ImplSource, SelectionError},
             traits::{Obligation, ObligationCause, PredicateObligation, PredicateObligations},
@@ -149,7 +149,7 @@
             let res = if this.use_lub {
                 at.lub(b, a)
             } else {
-                at.sup(DefineOpaqueTypes::Yes, b, a)
+                at.sup(b, a)
                     .map(|InferOk { value: (), obligations }| InferOk { value: b, obligations })
             };
 
@@ -1460,19 +1460,12 @@
             //
             // Another example is `break` with no argument expression.
             assert!(expression_ty.is_unit(), "if let hack without unit type");
-            icx.table
-                .infer_ctxt
-                .at(cause, icx.table.trait_env.env)
-                .eq(
-                    // needed for tests/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs
-                    DefineOpaqueTypes::Yes,
-                    expected,
-                    found,
-                )
-                .map(|infer_ok| {
+            icx.table.infer_ctxt.at(cause, icx.table.trait_env.env).eq(expected, found).map(
+                |infer_ok| {
                     icx.table.register_infer_ok(infer_ok);
                     expression_ty
-                })
+                },
+            )
         };
 
         debug!(?result);
diff --git a/crates/hir-ty/src/infer/diagnostics.rs b/crates/hir-ty/src/infer/diagnostics.rs
index 39e70c2..844eb02 100644
--- a/crates/hir-ty/src/infer/diagnostics.rs
+++ b/crates/hir-ty/src/infer/diagnostics.rs
@@ -15,8 +15,8 @@
 use crate::{
     InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringDiagnostic,
     db::HirDatabase,
-    lower_nextsolver::path::{PathDiagnosticCallback, PathLoweringContext},
-    lower_nextsolver::{LifetimeElisionKind, TyLoweringContext},
+    lower::path::{PathDiagnosticCallback, PathLoweringContext},
+    lower::{LifetimeElisionKind, TyLoweringContext},
 };
 
 // Unfortunately, this struct needs to use interior mutability (but we encapsulate it)
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index 179eacc..fd4e374 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -18,7 +18,7 @@
 use intern::sym;
 use rustc_ast_ir::Mutability;
 use rustc_type_ir::{
-    AliasTyKind, InferTy, Interner,
+    CoroutineArgs, CoroutineArgsParts, InferTy, Interner,
     inherent::{AdtDef, GenericArgs as _, IntoKind, SliceLike, Ty as _},
 };
 use syntax::ast::RangeOp;
@@ -29,6 +29,7 @@
     IncorrectGenericsLenKind, Rawness, TraitEnvironment,
     autoderef::overloaded_deref_ty,
     consteval,
+    db::InternedCoroutine,
     generics::generics,
     infer::{
         AllowTwoPhase, BreakableKind,
@@ -37,16 +38,16 @@
         pat::contains_explicit_ref_binding,
     },
     lang_items::lang_items_for_bin_op,
-    lower_nextsolver::{
+    lower::{
         LifetimeElisionKind, lower_mutability,
         path::{GenericArgsLowerer, TypeLikeConst, substs_from_args_and_bindings},
     },
     method_resolution::{self, VisibleFromModule},
     next_solver::{
-        AliasTy, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, TraitRef, Ty, TyKind,
+        Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, TraitRef, Ty, TyKind,
         TypeError,
         infer::{
-            DefineOpaqueTypes, InferOk,
+            InferOk,
             traits::{Obligation, ObligationCause},
         },
         obligation_ctxt::ObligationCtxt,
@@ -564,7 +565,7 @@
                 match def_id {
                     _ if fields.is_empty() => {}
                     Some(def) => {
-                        let field_types = self.db.field_types_ns(def);
+                        let field_types = self.db.field_types(def);
                         let variant_data = def.fields(self.db);
                         let visibilities = self.db.field_visibilities(def);
                         for field in fields.iter() {
@@ -1132,18 +1133,26 @@
         inner_ty: Ty<'db>,
         tgt_expr: ExprId,
     ) -> Ty<'db> {
-        // Use the first type parameter as the output type of future.
-        // existential type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType>
-        let impl_trait_id = crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, tgt_expr);
-        let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
-        Ty::new_alias(
+        let coroutine_id = InternedCoroutine(self.owner, tgt_expr);
+        let coroutine_id = self.db.intern_coroutine(coroutine_id).into();
+        let parent_args = GenericArgs::identity_for_item(self.interner(), self.generic_def.into());
+        Ty::new_coroutine(
             self.interner(),
-            AliasTyKind::Opaque,
-            AliasTy::new(
+            coroutine_id,
+            CoroutineArgs::new(
                 self.interner(),
-                opaque_ty_id,
-                GenericArgs::new_from_iter(self.interner(), [inner_ty.into()]),
-            ),
+                CoroutineArgsParts {
+                    parent_args,
+                    kind_ty: self.types.unit,
+                    // rustc uses a special lang item type for the resume ty. I don't believe this can cause us problems.
+                    resume_ty: self.types.unit,
+                    yield_ty: self.types.unit,
+                    return_ty: inner_ty,
+                    // FIXME: Infer upvars.
+                    tupled_upvars_ty: self.types.unit,
+                },
+            )
+            .args,
         )
     }
 
@@ -1333,7 +1342,7 @@
                     self.interner(),
                     box_id.into(),
                     [inner_ty.into()],
-                    |_, _, id, _| self.table.next_var_for_param(id),
+                    |_, id, _| self.table.next_var_for_param(id),
                 ),
             )
         } else {
@@ -1622,7 +1631,7 @@
                 }
                 return None;
             }
-            let ty = self.db.field_types_ns(field_id.parent)[field_id.local_id]
+            let ty = self.db.field_types(field_id.parent)[field_id.local_id]
                 .instantiate(interner, parameters);
             Some((Either::Left(field_id), ty))
         });
@@ -1637,7 +1646,7 @@
             None => {
                 let (field_id, subst) = private_field?;
                 let adjustments = autoderef.adjust_steps();
-                let ty = self.db.field_types_ns(field_id.parent)[field_id.local_id]
+                let ty = self.db.field_types(field_id.parent)[field_id.local_id]
                     .instantiate(self.interner(), subst);
                 let ty = self.process_remote_user_written_ty(ty);
 
@@ -2122,7 +2131,7 @@
                 .table
                 .infer_ctxt
                 .at(&ObligationCause::new(), this.table.trait_env.env)
-                .eq(DefineOpaqueTypes::Yes, formal_input_ty, coerced_ty);
+                .eq(formal_input_ty, coerced_ty);
 
             // If neither check failed, the types are compatible
             match formal_ty_error {
@@ -2320,7 +2329,7 @@
         let callable_ty = self.table.try_structurally_resolve_type(callable_ty);
         if let TyKind::FnDef(fn_def, parameters) = callable_ty.kind() {
             let generic_predicates =
-                self.db.generic_predicates_ns(GenericDefId::from_callable(self.db, fn_def.0));
+                self.db.generic_predicates(GenericDefId::from_callable(self.db, fn_def.0));
             if let Some(predicates) = generic_predicates.instantiate(self.interner(), parameters) {
                 let interner = self.interner();
                 let param_env = self.table.trait_env.env;
diff --git a/crates/hir-ty/src/infer/mutability.rs b/crates/hir-ty/src/infer/mutability.rs
index 9edbc9d..71a9c94 100644
--- a/crates/hir-ty/src/infer/mutability.rs
+++ b/crates/hir-ty/src/infer/mutability.rs
@@ -18,7 +18,7 @@
 use crate::{
     Adjust, Adjustment, AutoBorrow, OverloadedDeref,
     infer::{Expectation, InferenceContext, expr::ExprIsRead},
-    lower_nextsolver::lower_mutability,
+    lower::lower_mutability,
     next_solver::TyKind,
 };
 
diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs
index 452ae31..8019844 100644
--- a/crates/hir-ty/src/infer/pat.rs
+++ b/crates/hir-ty/src/infer/pat.rs
@@ -19,7 +19,7 @@
         AllowTwoPhase, BindingMode, Expectation, InferenceContext, TypeMismatch,
         coerce::CoerceNever, expr::ExprIsRead,
     },
-    lower_nextsolver::lower_mutability,
+    lower::lower_mutability,
     next_solver::{GenericArgs, Ty, TyKind},
 };
 
@@ -59,7 +59,7 @@
         match def {
             _ if subs.is_empty() => {}
             Some(def) => {
-                let field_types = self.db.field_types_ns(def);
+                let field_types = self.db.field_types(def);
                 let variant_data = def.fields(self.db);
                 let visibilities = self.db.field_visibilities(def);
 
@@ -128,7 +128,7 @@
         match def {
             _ if subs.len() == 0 => {}
             Some(def) => {
-                let field_types = self.db.field_types_ns(def);
+                let field_types = self.db.field_types(def);
                 let variant_data = def.fields(self.db);
                 let visibilities = self.db.field_visibilities(def);
 
@@ -358,7 +358,7 @@
                             self.interner(),
                             box_adt.into(),
                             std::iter::once(inner_ty.into()).chain(alloc_ty.map(Into::into)),
-                            |_, _, id, _| self.table.next_var_for_param(id),
+                            |_, id, _| self.table.next_var_for_param(id),
                         ),
                     )
                 }
diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs
index f70ed90..2dae7cb 100644
--- a/crates/hir-ty/src/infer/path.rs
+++ b/crates/hir-ty/src/infer/path.rs
@@ -13,7 +13,7 @@
     InferenceDiagnostic, ValueTyDefId,
     generics::generics,
     infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext,
-    lower_nextsolver::LifetimeElisionKind,
+    lower::LifetimeElisionKind,
     method_resolution::{self, VisibleFromModule},
     next_solver::{
         GenericArg, GenericArgs, TraitRef, Ty,
@@ -118,7 +118,7 @@
             self.interner(),
             generic_def.into(),
             self_subst.iter().flat_map(|it| it.iter()).chain(substs.iter().skip(parent_substs_len)),
-            |_, _, id, _| GenericArg::error_from_id(self.interner(), id),
+            |_, id, _| GenericArg::error_from_id(self.interner(), id),
         );
 
         Some(ValuePathResolution::GenericDef(value_def, generic_def, substs))
@@ -221,7 +221,7 @@
         def: GenericDefId,
         subst: GenericArgs<'db>,
     ) {
-        let predicates = self.db.generic_predicates_ns(def);
+        let predicates = self.db.generic_predicates(def);
         let interner = self.interner();
         let param_env = self.table.trait_env.env;
         if let Some(predicates) = predicates.instantiate(self.interner(), subst) {
@@ -352,7 +352,7 @@
                     self.interner(),
                     trait_.into(),
                     [ty.into()],
-                    |_, _, id, _| self.table.next_var_for_param(id),
+                    |_, id, _| self.table.next_var_for_param(id),
                 );
                 let trait_ref = TraitRef::new(self.interner(), trait_.into(), args);
                 self.table.register_predicate(Obligation::new(
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs
index 8f754f0..a18cdda 100644
--- a/crates/hir-ty/src/infer/unify.rs
+++ b/crates/hir-ty/src/infer/unify.rs
@@ -25,7 +25,7 @@
         SolverDefId, SolverDefIds, TraitRef, Ty, TyKind, TypingMode,
         fulfill::{FulfillmentCtxt, NextSolverError},
         infer::{
-            DbInternerInferExt, DefineOpaqueTypes, InferCtxt, InferOk, InferResult,
+            DbInternerInferExt, InferCtxt, InferOk, InferResult,
             at::ToTrace,
             snapshot::CombinedSnapshot,
             traits::{Obligation, ObligationCause, PredicateObligation},
@@ -148,7 +148,7 @@
     let ((ty1_with_vars, ty2_with_vars), _) = infcx.instantiate_canonical(tys);
     let mut ctxt = ObligationCtxt::new(&infcx);
     let can_unify = at
-        .eq(DefineOpaqueTypes::No, ty1_with_vars, ty2_with_vars)
+        .eq(ty1_with_vars, ty2_with_vars)
         .map(|infer_ok| ctxt.register_infer_ok_obligations(infer_ok))
         .is_ok();
     can_unify && select(&mut ctxt).is_empty()
@@ -452,11 +452,7 @@
     /// Unify two relatable values (e.g. `Ty`) and return new trait goals arising from it, so the
     /// caller needs to deal with them.
     pub(crate) fn try_unify<T: ToTrace<'db>>(&mut self, t1: T, t2: T) -> InferResult<'db, ()> {
-        self.infer_ctxt.at(&ObligationCause::new(), self.trait_env.env).eq(
-            DefineOpaqueTypes::Yes,
-            t1,
-            t2,
-        )
+        self.infer_ctxt.at(&ObligationCause::new(), self.trait_env.env).eq(t1, t2)
     }
 
     pub(crate) fn shallow_resolve(&self, ty: Ty<'db>) -> Ty<'db> {
@@ -804,7 +800,7 @@
             while let Some((AdtId::StructId(id), subst)) = ty.as_adt() {
                 let struct_data = id.fields(self.db);
                 if let Some((last_field, _)) = struct_data.fields().iter().next_back() {
-                    let last_field_ty = self.db.field_types_ns(id.into())[last_field]
+                    let last_field_ty = self.db.field_types(id.into())[last_field]
                         .instantiate(self.interner(), subst);
                     if structs.contains(&ty) {
                         // A struct recursively contains itself as a tail field somewhere.
diff --git a/crates/hir-ty/src/inhabitedness.rs b/crates/hir-ty/src/inhabitedness.rs
index 826f19c..5e742bb 100644
--- a/crates/hir-ty/src/inhabitedness.rs
+++ b/crates/hir-ty/src/inhabitedness.rs
@@ -1,60 +1,62 @@
 //! Type inhabitedness logic.
 use std::ops::ControlFlow::{self, Break, Continue};
 
-use chalk_ir::{
-    DebruijnIndex,
-    visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
-};
 use hir_def::{AdtId, EnumVariantId, ModuleId, VariantId, visibility::Visibility};
 use rustc_hash::FxHashSet;
+use rustc_type_ir::{
+    TypeSuperVisitable, TypeVisitable, TypeVisitor,
+    inherent::{AdtDef, IntoKind},
+};
 use triomphe::Arc;
 
 use crate::{
-    AliasTy, Binders, Interner, Substitution, TraitEnvironment, Ty, TyKind,
+    TraitEnvironment,
     consteval::try_const_usize,
     db::HirDatabase,
-    next_solver::{DbInterner, mapping::ChalkToNextSolver},
+    next_solver::{
+        DbInterner, EarlyBinder, GenericArgs, Ty, TyKind,
+        infer::{InferCtxt, traits::ObligationCause},
+        obligation_ctxt::ObligationCtxt,
+    },
 };
 
 // FIXME: Turn this into a query, it can be quite slow
 /// Checks whether a type is visibly uninhabited from a particular module.
-pub(crate) fn is_ty_uninhabited_from(
-    db: &dyn HirDatabase,
-    ty: &Ty,
+pub(crate) fn is_ty_uninhabited_from<'db>(
+    infcx: &InferCtxt<'db>,
+    ty: Ty<'db>,
     target_mod: ModuleId,
-    env: Arc<TraitEnvironment<'_>>,
+    env: Arc<TraitEnvironment<'db>>,
 ) -> bool {
     let _p = tracing::info_span!("is_ty_uninhabited_from", ?ty).entered();
-    let mut uninhabited_from =
-        UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default(), env };
-    let inhabitedness = ty.visit_with(&mut uninhabited_from, DebruijnIndex::INNERMOST);
+    let mut uninhabited_from = UninhabitedFrom::new(infcx, target_mod, env);
+    let inhabitedness = ty.visit_with(&mut uninhabited_from);
     inhabitedness == BREAK_VISIBLY_UNINHABITED
 }
 
 // FIXME: Turn this into a query, it can be quite slow
 /// Checks whether a variant is visibly uninhabited from a particular module.
-pub(crate) fn is_enum_variant_uninhabited_from(
-    db: &dyn HirDatabase,
+pub(crate) fn is_enum_variant_uninhabited_from<'db>(
+    infcx: &InferCtxt<'db>,
     variant: EnumVariantId,
-    subst: &Substitution,
+    subst: GenericArgs<'db>,
     target_mod: ModuleId,
-    env: Arc<TraitEnvironment<'_>>,
+    env: Arc<TraitEnvironment<'db>>,
 ) -> bool {
     let _p = tracing::info_span!("is_enum_variant_uninhabited_from").entered();
 
-    let mut uninhabited_from =
-        UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default(), env };
+    let mut uninhabited_from = UninhabitedFrom::new(infcx, target_mod, env);
     let inhabitedness = uninhabited_from.visit_variant(variant.into(), subst);
     inhabitedness == BREAK_VISIBLY_UNINHABITED
 }
 
-struct UninhabitedFrom<'a> {
+struct UninhabitedFrom<'a, 'db> {
     target_mod: ModuleId,
-    recursive_ty: FxHashSet<Ty>,
+    recursive_ty: FxHashSet<Ty<'db>>,
     // guard for preventing stack overflow in non trivial non terminating types
     max_depth: usize,
-    db: &'a dyn HirDatabase,
-    env: Arc<TraitEnvironment<'a>>,
+    infcx: &'a InferCtxt<'db>,
+    env: Arc<TraitEnvironment<'db>>,
 }
 
 const CONTINUE_OPAQUELY_INHABITED: ControlFlow<VisiblyUninhabited> = Continue(());
@@ -62,63 +64,73 @@
 #[derive(PartialEq, Eq)]
 struct VisiblyUninhabited;
 
-impl TypeVisitor<Interner> for UninhabitedFrom<'_> {
-    type BreakTy = VisiblyUninhabited;
+impl<'db> TypeVisitor<DbInterner<'db>> for UninhabitedFrom<'_, 'db> {
+    type Result = ControlFlow<VisiblyUninhabited>;
 
-    fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = VisiblyUninhabited> {
-        self
-    }
-
-    fn visit_ty(
-        &mut self,
-        ty: &Ty,
-        outer_binder: DebruijnIndex,
-    ) -> ControlFlow<VisiblyUninhabited> {
-        if self.recursive_ty.contains(ty) || self.max_depth == 0 {
+    fn visit_ty(&mut self, mut ty: Ty<'db>) -> ControlFlow<VisiblyUninhabited> {
+        if self.recursive_ty.contains(&ty) || self.max_depth == 0 {
             // rustc considers recursive types always inhabited. I think it is valid to consider
             // recursive types as always uninhabited, but we should do what rustc is doing.
             return CONTINUE_OPAQUELY_INHABITED;
         }
-        self.recursive_ty.insert(ty.clone());
+        self.recursive_ty.insert(ty);
         self.max_depth -= 1;
-        let interner = DbInterner::new_with(self.db, None, None);
-        let r = match ty.kind(Interner) {
-            TyKind::Adt(adt, subst) => self.visit_adt(adt.0, subst),
+
+        if matches!(ty.kind(), TyKind::Alias(..)) {
+            let mut ocx = ObligationCtxt::new(self.infcx);
+            match ocx.structurally_normalize_ty(&ObligationCause::dummy(), self.env.env, ty) {
+                Ok(it) => ty = it,
+                Err(_) => return CONTINUE_OPAQUELY_INHABITED,
+            }
+        }
+
+        let r = match ty.kind() {
+            TyKind::Adt(adt, subst) => self.visit_adt(adt.def_id().0, subst),
             TyKind::Never => BREAK_VISIBLY_UNINHABITED,
-            TyKind::Tuple(..) => ty.super_visit_with(self, outer_binder),
-            TyKind::Array(item_ty, len) => {
-                match try_const_usize(self.db, len.to_nextsolver(interner)) {
-                    Some(0) | None => CONTINUE_OPAQUELY_INHABITED,
-                    Some(1..) => item_ty.super_visit_with(self, outer_binder),
-                }
-            }
-            TyKind::Alias(AliasTy::Projection(projection)) => {
-                // FIXME: I think this currently isn't used for monomorphized bodies, so there is no need to handle
-                // `TyKind::AssociatedType`, but perhaps in the future it will.
-                let normalized = self.db.normalize_projection(projection.clone(), self.env.clone());
-                self.visit_ty(&normalized, outer_binder)
-            }
+            TyKind::Tuple(..) => ty.super_visit_with(self),
+            TyKind::Array(item_ty, len) => match try_const_usize(self.infcx.interner.db, len) {
+                Some(0) | None => CONTINUE_OPAQUELY_INHABITED,
+                Some(1..) => item_ty.visit_with(self),
+            },
             _ => CONTINUE_OPAQUELY_INHABITED,
         };
-        self.recursive_ty.remove(ty);
+        self.recursive_ty.remove(&ty);
         self.max_depth += 1;
         r
     }
-
-    fn interner(&self) -> Interner {
-        Interner
-    }
 }
 
-impl UninhabitedFrom<'_> {
-    fn visit_adt(&mut self, adt: AdtId, subst: &Substitution) -> ControlFlow<VisiblyUninhabited> {
+impl<'a, 'db> UninhabitedFrom<'a, 'db> {
+    fn new(
+        infcx: &'a InferCtxt<'db>,
+        target_mod: ModuleId,
+        env: Arc<TraitEnvironment<'db>>,
+    ) -> Self {
+        Self { target_mod, recursive_ty: FxHashSet::default(), max_depth: 500, infcx, env }
+    }
+
+    #[inline]
+    fn interner(&self) -> DbInterner<'db> {
+        self.infcx.interner
+    }
+
+    #[inline]
+    fn db(&self) -> &'db dyn HirDatabase {
+        self.interner().db
+    }
+
+    fn visit_adt(
+        &mut self,
+        adt: AdtId,
+        subst: GenericArgs<'db>,
+    ) -> ControlFlow<VisiblyUninhabited> {
         // An ADT is uninhabited iff all its variants uninhabited.
         match adt {
             // rustc: For now, `union`s are never considered uninhabited.
             AdtId::UnionId(_) => CONTINUE_OPAQUELY_INHABITED,
             AdtId::StructId(s) => self.visit_variant(s.into(), subst),
             AdtId::EnumId(e) => {
-                let enum_data = e.enum_variants(self.db);
+                let enum_data = e.enum_variants(self.db());
 
                 for &(variant, _, _) in enum_data.variants.iter() {
                     let variant_inhabitedness = self.visit_variant(variant.into(), subst);
@@ -135,17 +147,17 @@
     fn visit_variant(
         &mut self,
         variant: VariantId,
-        subst: &Substitution,
+        subst: GenericArgs<'db>,
     ) -> ControlFlow<VisiblyUninhabited> {
-        let variant_data = variant.fields(self.db);
+        let variant_data = variant.fields(self.db());
         let fields = variant_data.fields();
         if fields.is_empty() {
             return CONTINUE_OPAQUELY_INHABITED;
         }
 
         let is_enum = matches!(variant, VariantId::EnumVariantId(..));
-        let field_tys = self.db.field_types(variant);
-        let field_vis = if is_enum { None } else { Some(self.db.field_visibilities(variant)) };
+        let field_tys = self.db().field_types(variant);
+        let field_vis = if is_enum { None } else { Some(self.db().field_visibilities(variant)) };
 
         for (fid, _) in fields.iter() {
             self.visit_field(field_vis.as_ref().map(|it| it[fid]), &field_tys[fid], subst)?;
@@ -156,12 +168,12 @@
     fn visit_field(
         &mut self,
         vis: Option<Visibility>,
-        ty: &Binders<Ty>,
-        subst: &Substitution,
+        ty: &EarlyBinder<'db, Ty<'db>>,
+        subst: GenericArgs<'db>,
     ) -> ControlFlow<VisiblyUninhabited> {
-        if vis.is_none_or(|it| it.is_visible_from(self.db, self.target_mod)) {
-            let ty = ty.clone().substitute(Interner, subst);
-            ty.visit_with(self, DebruijnIndex::INNERMOST)
+        if vis.is_none_or(|it| it.is_visible_from(self.db(), self.target_mod)) {
+            let ty = ty.instantiate(self.interner(), subst);
+            ty.visit_with(self)
         } else {
             CONTINUE_OPAQUELY_INHABITED
         }
diff --git a/crates/hir-ty/src/interner.rs b/crates/hir-ty/src/interner.rs
deleted file mode 100644
index 57ef552..0000000
--- a/crates/hir-ty/src/interner.rs
+++ /dev/null
@@ -1,403 +0,0 @@
-//! Implementation of the Chalk `Interner` trait, which allows customizing the
-//! representation of the various objects Chalk deals with (types, goals etc.).
-
-use crate::{
-    AliasTy, CanonicalVarKind, CanonicalVarKinds, ClosureId, Const, ConstData, ConstScalar, FnAbi,
-    FnDefId, GenericArg, GenericArgData, Goal, GoalData, InEnvironment, Lifetime, LifetimeData,
-    OpaqueTy, OpaqueTyId, ProgramClause, ProjectionTy, QuantifiedWhereClause,
-    QuantifiedWhereClauses, Substitution, Ty, TyKind, VariableKind, chalk_db, tls,
-};
-use chalk_ir::{ProgramClauseImplication, SeparatorTraitRef, Variance};
-use hir_def::TypeAliasId;
-use intern::{Interned, impl_internable};
-use smallvec::SmallVec;
-use std::fmt;
-use triomphe::Arc;
-
-type TyData = chalk_ir::TyData<Interner>;
-type VariableKinds = chalk_ir::VariableKinds<Interner>;
-type Goals = chalk_ir::Goals<Interner>;
-type ProgramClauseData = chalk_ir::ProgramClauseData<Interner>;
-type Constraint = chalk_ir::Constraint<Interner>;
-type Constraints = chalk_ir::Constraints<Interner>;
-type ProgramClauses = chalk_ir::ProgramClauses<Interner>;
-
-#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
-pub struct Interner;
-
-#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Clone)]
-pub struct InternedWrapper<T>(pub(crate) T);
-
-impl<T: fmt::Debug> fmt::Debug for InternedWrapper<T> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Debug::fmt(&self.0, f)
-    }
-}
-
-#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Clone)]
-pub struct InternedWrapperNoDebug<T>(pub(crate) T);
-
-impl<T> std::ops::Deref for InternedWrapper<T> {
-    type Target = T;
-
-    fn deref(&self) -> &Self::Target {
-        &self.0
-    }
-}
-
-impl_internable!(
-    InternedWrapper<Vec<VariableKind>>,
-    InternedWrapper<SmallVec<[GenericArg; 2]>>,
-    InternedWrapper<TyData>,
-    InternedWrapper<LifetimeData>,
-    InternedWrapper<ConstData>,
-    InternedWrapper<ConstScalar>,
-    InternedWrapper<Vec<CanonicalVarKind>>,
-    InternedWrapper<Box<[ProgramClause]>>,
-    InternedWrapper<Vec<QuantifiedWhereClause>>,
-    InternedWrapper<SmallVec<[Variance; 16]>>,
-);
-
-impl chalk_ir::interner::Interner for Interner {
-    type InternedType = Interned<InternedWrapper<TyData>>;
-    type InternedLifetime = Interned<InternedWrapper<LifetimeData>>;
-    type InternedConst = Interned<InternedWrapper<ConstData>>;
-    type InternedConcreteConst = ConstScalar;
-    type InternedGenericArg = GenericArgData;
-    // We could do the following, but that saves "only" 20mb on self while increasing inference
-    // time by ~2.5%
-    // type InternedGoal = Interned<InternedWrapper<GoalData>>;
-    type InternedGoal = Arc<GoalData>;
-    type InternedGoals = Vec<Goal>;
-    type InternedSubstitution = Interned<InternedWrapper<SmallVec<[GenericArg; 2]>>>;
-    type InternedProgramClauses = Interned<InternedWrapper<Box<[ProgramClause]>>>;
-    type InternedProgramClause = ProgramClauseData;
-    type InternedQuantifiedWhereClauses = Interned<InternedWrapper<Vec<QuantifiedWhereClause>>>;
-    type InternedVariableKinds = Interned<InternedWrapper<Vec<VariableKind>>>;
-    type InternedCanonicalVarKinds = Interned<InternedWrapper<Vec<CanonicalVarKind>>>;
-    type InternedConstraints = Vec<InEnvironment<Constraint>>;
-    type InternedVariances = SmallVec<[Variance; 16]>;
-    type DefId = salsa::Id;
-    type InternedAdtId = hir_def::AdtId;
-    type Identifier = TypeAliasId;
-    type FnAbi = FnAbi;
-
-    fn debug_adt_id(
-        type_kind_id: chalk_db::AdtId,
-        fmt: &mut fmt::Formatter<'_>,
-    ) -> Option<fmt::Result> {
-        tls::with_current_program(|prog| Some(prog?.debug_struct_id(type_kind_id, fmt)))
-    }
-
-    fn debug_trait_id(
-        type_kind_id: chalk_db::TraitId,
-        fmt: &mut fmt::Formatter<'_>,
-    ) -> Option<fmt::Result> {
-        tls::with_current_program(|prog| Some(prog?.debug_trait_id(type_kind_id, fmt)))
-    }
-
-    fn debug_assoc_type_id(
-        id: chalk_db::AssocTypeId,
-        fmt: &mut fmt::Formatter<'_>,
-    ) -> Option<fmt::Result> {
-        tls::with_current_program(|prog| Some(prog?.debug_assoc_type_id(id, fmt)))
-    }
-
-    fn debug_opaque_ty_id(
-        opaque_ty_id: OpaqueTyId,
-        fmt: &mut fmt::Formatter<'_>,
-    ) -> Option<fmt::Result> {
-        Some(write!(fmt, "OpaqueTy#{:?}", opaque_ty_id.0))
-    }
-
-    fn debug_fn_def_id(fn_def_id: FnDefId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
-        tls::with_current_program(|prog| Some(prog?.debug_fn_def_id(fn_def_id, fmt)))
-    }
-
-    fn debug_closure_id(
-        _fn_def_id: ClosureId,
-        _fmt: &mut fmt::Formatter<'_>,
-    ) -> Option<fmt::Result> {
-        None
-    }
-
-    fn debug_alias(alias: &AliasTy, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
-        use std::fmt::Debug;
-        match alias {
-            AliasTy::Projection(projection_ty) => Interner::debug_projection_ty(projection_ty, fmt),
-            AliasTy::Opaque(opaque_ty) => Some(opaque_ty.fmt(fmt)),
-        }
-    }
-
-    fn debug_projection_ty(
-        proj: &ProjectionTy,
-        fmt: &mut fmt::Formatter<'_>,
-    ) -> Option<fmt::Result> {
-        tls::with_current_program(|prog| Some(prog?.debug_projection_ty(proj, fmt)))
-            .or_else(|| Some(fmt.write_str("ProjectionTy")))
-    }
-
-    fn debug_opaque_ty(opaque_ty: &OpaqueTy, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
-        Some(write!(fmt, "{:?}", opaque_ty.opaque_ty_id))
-    }
-
-    fn debug_ty(ty: &Ty, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
-        Some(write!(fmt, "{:?}", ty.data(Interner)))
-    }
-
-    fn debug_lifetime(lifetime: &Lifetime, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
-        Some(write!(fmt, "{:?}", lifetime.data(Interner)))
-    }
-
-    fn debug_const(constant: &Const, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
-        Some(write!(fmt, "{:?}", constant.data(Interner)))
-    }
-
-    fn debug_generic_arg(
-        parameter: &GenericArg,
-        fmt: &mut fmt::Formatter<'_>,
-    ) -> Option<fmt::Result> {
-        Some(write!(fmt, "{:?}", parameter.data(Interner).inner_debug()))
-    }
-
-    fn debug_variable_kinds(
-        variable_kinds: &VariableKinds,
-        fmt: &mut fmt::Formatter<'_>,
-    ) -> Option<fmt::Result> {
-        Some(write!(fmt, "{:?}", variable_kinds.as_slice(Interner)))
-    }
-
-    fn debug_variable_kinds_with_angles(
-        variable_kinds: &VariableKinds,
-        fmt: &mut fmt::Formatter<'_>,
-    ) -> Option<fmt::Result> {
-        Some(write!(fmt, "{:?}", variable_kinds.inner_debug(Interner)))
-    }
-
-    fn debug_canonical_var_kinds(
-        canonical_var_kinds: &CanonicalVarKinds,
-        fmt: &mut fmt::Formatter<'_>,
-    ) -> Option<fmt::Result> {
-        Some(write!(fmt, "{:?}", canonical_var_kinds.as_slice(Interner)))
-    }
-    fn debug_goal(goal: &Goal, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
-        let goal_data = goal.data(Interner);
-        Some(write!(fmt, "{goal_data:?}"))
-    }
-    fn debug_goals(goals: &Goals, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
-        Some(write!(fmt, "{:?}", goals.debug(Interner)))
-    }
-    fn debug_program_clause_implication(
-        pci: &ProgramClauseImplication<Self>,
-        fmt: &mut fmt::Formatter<'_>,
-    ) -> Option<fmt::Result> {
-        Some(write!(fmt, "{:?}", pci.debug(Interner)))
-    }
-    fn debug_program_clause(
-        clause: &ProgramClause,
-        fmt: &mut fmt::Formatter<'_>,
-    ) -> Option<fmt::Result> {
-        Some(write!(fmt, "{:?}", clause.data(Interner)))
-    }
-    fn debug_program_clauses(
-        clauses: &ProgramClauses,
-        fmt: &mut fmt::Formatter<'_>,
-    ) -> Option<fmt::Result> {
-        Some(write!(fmt, "{:?}", clauses.as_slice(Interner)))
-    }
-    fn debug_substitution(
-        substitution: &Substitution,
-        fmt: &mut fmt::Formatter<'_>,
-    ) -> Option<fmt::Result> {
-        Some(write!(fmt, "{:?}", substitution.debug(Interner)))
-    }
-    fn debug_separator_trait_ref(
-        separator_trait_ref: &SeparatorTraitRef<'_, Interner>,
-        fmt: &mut fmt::Formatter<'_>,
-    ) -> Option<fmt::Result> {
-        Some(write!(fmt, "{:?}", separator_trait_ref.debug(Interner)))
-    }
-
-    fn debug_quantified_where_clauses(
-        clauses: &QuantifiedWhereClauses,
-        fmt: &mut fmt::Formatter<'_>,
-    ) -> Option<fmt::Result> {
-        Some(write!(fmt, "{:?}", clauses.as_slice(Interner)))
-    }
-
-    fn debug_constraints(
-        _clauses: &Constraints,
-        _fmt: &mut fmt::Formatter<'_>,
-    ) -> Option<fmt::Result> {
-        None
-    }
-
-    fn intern_ty(self, kind: TyKind) -> Self::InternedType {
-        let flags = kind.compute_flags(self);
-        Interned::new(InternedWrapper(TyData { kind, flags }))
-    }
-
-    fn ty_data(self, ty: &Self::InternedType) -> &TyData {
-        &ty.0
-    }
-
-    fn intern_lifetime(self, lifetime: LifetimeData) -> Self::InternedLifetime {
-        Interned::new(InternedWrapper(lifetime))
-    }
-
-    fn lifetime_data(self, lifetime: &Self::InternedLifetime) -> &LifetimeData {
-        &lifetime.0
-    }
-
-    fn intern_const(self, constant: ConstData) -> Self::InternedConst {
-        Interned::new(InternedWrapper(constant))
-    }
-
-    fn const_data(self, constant: &Self::InternedConst) -> &ConstData {
-        &constant.0
-    }
-
-    fn const_eq(
-        self,
-        _ty: &Self::InternedType,
-        c1: &Self::InternedConcreteConst,
-        c2: &Self::InternedConcreteConst,
-    ) -> bool {
-        !matches!(c1, ConstScalar::Bytes(..)) || !matches!(c2, ConstScalar::Bytes(..)) || (c1 == c2)
-    }
-
-    fn intern_generic_arg(self, parameter: GenericArgData) -> Self::InternedGenericArg {
-        parameter
-    }
-
-    fn generic_arg_data(self, parameter: &Self::InternedGenericArg) -> &GenericArgData {
-        parameter
-    }
-
-    fn intern_goal(self, goal: GoalData) -> Self::InternedGoal {
-        Arc::new(goal)
-    }
-
-    fn goal_data(self, goal: &Self::InternedGoal) -> &GoalData {
-        goal
-    }
-
-    fn intern_goals<E>(
-        self,
-        data: impl IntoIterator<Item = Result<Goal, E>>,
-    ) -> Result<Self::InternedGoals, E> {
-        // let hash =
-        //     std::hash::BuildHasher::hash_one(&BuildHasherDefault::<FxHasher>::default(), &goal);
-        // Interned::new(InternedWrapper(PreHashedWrapper(goal, hash)))
-        data.into_iter().collect()
-    }
-
-    fn goals_data(self, goals: &Self::InternedGoals) -> &[Goal] {
-        goals
-    }
-
-    fn intern_substitution<E>(
-        self,
-        data: impl IntoIterator<Item = Result<GenericArg, E>>,
-    ) -> Result<Self::InternedSubstitution, E> {
-        Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
-    }
-
-    fn substitution_data(self, substitution: &Self::InternedSubstitution) -> &[GenericArg] {
-        &substitution.as_ref().0
-    }
-
-    fn intern_program_clause(self, data: ProgramClauseData) -> Self::InternedProgramClause {
-        data
-    }
-
-    fn program_clause_data(self, clause: &Self::InternedProgramClause) -> &ProgramClauseData {
-        clause
-    }
-
-    fn intern_program_clauses<E>(
-        self,
-        data: impl IntoIterator<Item = Result<ProgramClause, E>>,
-    ) -> Result<Self::InternedProgramClauses, E> {
-        Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
-    }
-
-    fn program_clauses_data(self, clauses: &Self::InternedProgramClauses) -> &[ProgramClause] {
-        clauses
-    }
-
-    fn intern_quantified_where_clauses<E>(
-        self,
-        data: impl IntoIterator<Item = Result<QuantifiedWhereClause, E>>,
-    ) -> Result<Self::InternedQuantifiedWhereClauses, E> {
-        Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
-    }
-
-    fn quantified_where_clauses_data(
-        self,
-        clauses: &Self::InternedQuantifiedWhereClauses,
-    ) -> &[QuantifiedWhereClause] {
-        clauses
-    }
-
-    fn intern_generic_arg_kinds<E>(
-        self,
-        data: impl IntoIterator<Item = Result<VariableKind, E>>,
-    ) -> Result<Self::InternedVariableKinds, E> {
-        Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
-    }
-
-    fn variable_kinds_data(self, parameter_kinds: &Self::InternedVariableKinds) -> &[VariableKind] {
-        &parameter_kinds.as_ref().0
-    }
-
-    fn intern_canonical_var_kinds<E>(
-        self,
-        data: impl IntoIterator<Item = Result<CanonicalVarKind, E>>,
-    ) -> Result<Self::InternedCanonicalVarKinds, E> {
-        Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
-    }
-
-    fn canonical_var_kinds_data(
-        self,
-        canonical_var_kinds: &Self::InternedCanonicalVarKinds,
-    ) -> &[CanonicalVarKind] {
-        canonical_var_kinds
-    }
-    fn intern_constraints<E>(
-        self,
-        data: impl IntoIterator<Item = Result<InEnvironment<Constraint>, E>>,
-    ) -> Result<Self::InternedConstraints, E> {
-        data.into_iter().collect()
-    }
-    fn constraints_data(
-        self,
-        constraints: &Self::InternedConstraints,
-    ) -> &[InEnvironment<Constraint>] {
-        constraints
-    }
-
-    fn intern_variances<E>(
-        self,
-        data: impl IntoIterator<Item = Result<Variance, E>>,
-    ) -> Result<Self::InternedVariances, E> {
-        data.into_iter().collect::<Result<_, _>>()
-    }
-
-    fn variances_data(self, variances: &Self::InternedVariances) -> &[Variance] {
-        variances
-    }
-}
-
-impl chalk_ir::interner::HasInterner for Interner {
-    type Interner = Self;
-}
-
-#[macro_export]
-macro_rules! has_interner {
-    ($t:ty) => {
-        impl HasInterner for $t {
-            type Interner = $crate::Interner;
-        }
-    };
-}
diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs
index a857602..fc0b9d3 100644
--- a/crates/hir-ty/src/layout.rs
+++ b/crates/hir-ty/src/layout.rs
@@ -138,7 +138,7 @@
     // * #[repr(simd)] struct S([T; 4])
     //
     // where T is a primitive scalar (integer/float/pointer).
-    let fields = db.field_types_ns(id.into());
+    let fields = db.field_types(id.into());
     let mut fields = fields.iter();
     let Some(TyKind::Array(e_ty, e_len)) = fields
         .next()
@@ -401,7 +401,7 @@
     fd: LocalFieldId,
     args: &GenericArgs<'a>,
 ) -> Ty<'a> {
-    db.field_types_ns(def)[fd].instantiate(DbInterner::new_with(db, None, None), args)
+    db.field_types(def)[fd].instantiate(DbInterner::new_with(db, None, None), args)
 }
 
 fn scalar_unit(dl: &TargetDataLayout, value: Primitive) -> Scalar {
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index 734483a..25579e0 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -23,23 +23,16 @@
 
 extern crate self as hir_ty;
 
-mod builder;
-mod chalk_db;
-mod chalk_ext;
 mod infer;
 mod inhabitedness;
-mod interner;
 mod lower;
-mod lower_nextsolver;
-mod mapping;
 pub mod next_solver;
+mod specialization;
 mod target_feature;
-mod tls;
 mod utils;
 
 pub mod autoderef;
 pub mod consteval;
-mod consteval_chalk;
 pub mod db;
 pub mod diagnostics;
 pub mod display;
@@ -61,42 +54,32 @@
 
 use std::hash::Hash;
 
-use chalk_ir::{
-    VariableKinds,
-    fold::{Shift, TypeFoldable},
-    interner::HasInterner,
-};
-use hir_def::{CallableDefId, GeneralConstId, TypeOrConstParamId, hir::ExprId, type_ref::Rawness};
+use hir_def::{CallableDefId, TypeOrConstParamId, type_ref::Rawness};
 use hir_expand::name::Name;
 use indexmap::{IndexMap, map::Entry};
 use intern::{Symbol, sym};
-use la_arena::{Arena, Idx};
 use mir::{MirEvalError, VTableMap};
 use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
 use rustc_type_ir::{
-    TypeSuperVisitable, TypeVisitableExt, UpcastFrom,
+    BoundVarIndexKind, TypeSuperVisitable, TypeVisitableExt, UpcastFrom,
     inherent::{IntoKind, SliceLike, Ty as _},
 };
 use syntax::ast::{ConstArg, make};
 use traits::FnTrait;
 use triomphe::Arc;
 
-#[cfg(not(debug_assertions))]
-use crate::next_solver::ErrorGuaranteed;
 use crate::{
     db::HirDatabase,
     display::{DisplayTarget, HirDisplay},
-    generics::Generics,
     infer::unify::InferenceTable,
     next_solver::{
-        DbInterner,
-        mapping::{ChalkToNextSolver, NextSolverToChalk, convert_ty_for_result},
+        AliasTy, Binder, BoundConst, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, Canonical,
+        CanonicalVarKind, CanonicalVars, Const, ConstKind, DbInterner, FnSig, PolyFnSig, Predicate,
+        Region, RegionKind, TraitRef, Ty, TyKind, Tys, abi,
     },
 };
 
 pub use autoderef::autoderef;
-pub use builder::{ParamKind, TyBuilder};
-pub use chalk_ext::*;
 pub use infer::{
     Adjust, Adjustment, AutoBorrow, BindingMode, InferenceDiagnostic, InferenceResult,
     InferenceTyDiagnosticSource, OverloadedDeref, PointerCast,
@@ -104,15 +87,9 @@
     closure::analysis::{CaptureKind, CapturedItem},
     could_coerce, could_unify, could_unify_deeply,
 };
-pub use interner::Interner;
-pub use lower::{ImplTraitLoweringMode, ParamLoweringMode, TyDefId, ValueTyDefId, diagnostics::*};
-pub use lower_nextsolver::{
-    LifetimeElisionKind, TyLoweringContext, associated_type_shorthand_candidates,
-};
-pub use mapping::{
-    ToChalk, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
-    lt_from_placeholder_idx, lt_to_placeholder_idx, to_assoc_type_id, to_chalk_trait_id,
-    to_foreign_def_id, to_placeholder_idx, to_placeholder_idx_no_index,
+pub use lower::{
+    LifetimeElisionKind, TyDefId, TyLoweringContext, ValueTyDefId,
+    associated_type_shorthand_candidates, diagnostics::*,
 };
 pub use method_resolution::check_orphan_rules;
 pub use next_solver::interner::{attach_db, attach_db_allow_change, with_attached_db};
@@ -122,79 +99,6 @@
     TargetFeatureIsSafeInTarget, Unsafety, all_super_traits, direct_super_traits,
     is_fn_unsafe_to_call, target_feature_is_safe_in_target,
 };
-pub use variance::Variance;
-
-use chalk_ir::{AdtId, BoundVar, DebruijnIndex, Safety, Scalar};
-
-pub(crate) type ForeignDefId = chalk_ir::ForeignDefId<Interner>;
-pub(crate) type AssocTypeId = chalk_ir::AssocTypeId<Interner>;
-pub(crate) type FnDefId = chalk_ir::FnDefId<Interner>;
-pub(crate) type ClosureId = chalk_ir::ClosureId<Interner>;
-pub(crate) type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>;
-pub(crate) type PlaceholderIndex = chalk_ir::PlaceholderIndex;
-
-pub(crate) type CanonicalVarKinds = chalk_ir::CanonicalVarKinds<Interner>;
-
-pub(crate) type VariableKind = chalk_ir::VariableKind<Interner>;
-/// Represents generic parameters and an item bound by them. When the item has parent, the binders
-/// also contain the generic parameters for its parent. See chalk's documentation for details.
-///
-/// One thing to keep in mind when working with `Binders` (and `Substitution`s, which represent
-/// generic arguments) in rust-analyzer is that the ordering within *is* significant - the generic
-/// parameters/arguments for an item MUST come before those for its parent. This is to facilitate
-/// the integration with chalk-solve, which mildly puts constraints as such. See #13335 for its
-/// motivation in detail.
-pub(crate) type Binders<T> = chalk_ir::Binders<T>;
-/// Interned list of generic arguments for an item. When an item has parent, the `Substitution` for
-/// it contains generic arguments for both its parent and itself. See chalk's documentation for
-/// details.
-///
-/// See `Binders` for the constraint on the ordering.
-pub(crate) type Substitution = chalk_ir::Substitution<Interner>;
-pub(crate) type GenericArg = chalk_ir::GenericArg<Interner>;
-pub(crate) type GenericArgData = chalk_ir::GenericArgData<Interner>;
-
-pub(crate) type Ty = chalk_ir::Ty<Interner>;
-pub type TyKind = chalk_ir::TyKind<Interner>;
-pub(crate) type TypeFlags = chalk_ir::TypeFlags;
-pub(crate) type DynTy = chalk_ir::DynTy<Interner>;
-pub(crate) type FnPointer = chalk_ir::FnPointer<Interner>;
-pub(crate) use chalk_ir::FnSubst; // a re-export so we don't lose the tuple constructor
-
-pub type AliasTy = chalk_ir::AliasTy<Interner>;
-
-pub(crate) type ProjectionTy = chalk_ir::ProjectionTy<Interner>;
-pub(crate) type OpaqueTy = chalk_ir::OpaqueTy<Interner>;
-
-pub(crate) type Lifetime = chalk_ir::Lifetime<Interner>;
-pub(crate) type LifetimeData = chalk_ir::LifetimeData<Interner>;
-pub(crate) type LifetimeOutlives = chalk_ir::LifetimeOutlives<Interner>;
-
-pub(crate) type ConstValue = chalk_ir::ConstValue<Interner>;
-
-pub(crate) type Const = chalk_ir::Const<Interner>;
-pub(crate) type ConstData = chalk_ir::ConstData<Interner>;
-pub(crate) type ConcreteConst = chalk_ir::ConcreteConst<Interner>;
-
-pub(crate) type TraitRef = chalk_ir::TraitRef<Interner>;
-pub(crate) type QuantifiedWhereClause = Binders<WhereClause>;
-pub(crate) type Canonical<T> = chalk_ir::Canonical<T>;
-
-pub(crate) type ChalkTraitId = chalk_ir::TraitId<Interner>;
-pub(crate) type QuantifiedWhereClauses = chalk_ir::QuantifiedWhereClauses<Interner>;
-
-pub(crate) type FnSig = chalk_ir::FnSig<Interner>;
-
-pub(crate) type InEnvironment<T> = chalk_ir::InEnvironment<T>;
-pub type AliasEq = chalk_ir::AliasEq<Interner>;
-pub type WhereClause = chalk_ir::WhereClause<Interner>;
-
-pub(crate) type DomainGoal = chalk_ir::DomainGoal<Interner>;
-pub(crate) type Goal = chalk_ir::Goal<Interner>;
-
-pub(crate) type CanonicalVarKind = chalk_ir::CanonicalVarKind<Interner>;
-pub(crate) type GoalData = chalk_ir::GoalData<Interner>;
-pub(crate) type ProgramClause = chalk_ir::ProgramClause<Interner>;
 
 /// A constant can have reference to other things. Memory map job is holding
 /// the necessary bits of memory of the const eval session to keep the constant
@@ -229,7 +133,7 @@
 }
 
 impl<'db> MemoryMap<'db> {
-    pub fn vtable_ty(&self, id: usize) -> Result<crate::next_solver::Ty<'db>, MirEvalError<'db>> {
+    pub fn vtable_ty(&self, id: usize) -> Result<Ty<'db>, MirEvalError<'db>> {
         match self {
             MemoryMap::Empty | MemoryMap::Simple(_) => Err(MirEvalError::InvalidVTableId(id)),
             MemoryMap::Complex(cm) => cm.vtable.ty(id),
@@ -279,118 +183,11 @@
     }
 }
 
-// FIXME(next-solver): add a lifetime to this
-/// A concrete constant value
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum ConstScalar {
-    Bytes(Box<[u8]>, MemoryMap<'static>),
-    // FIXME: this is a hack to get around chalk not being able to represent unevaluatable
-    // constants
-    UnevaluatedConst(GeneralConstId, Substitution),
-    /// Case of an unknown value that rustc might know but we don't
-    // FIXME: this is a hack to get around chalk not being able to represent unevaluatable
-    // constants
-    // https://github.com/rust-lang/rust-analyzer/pull/8813#issuecomment-840679177
-    // https://rust-lang.zulipchat.com/#narrow/stream/144729-wg-traits/topic/Handling.20non.20evaluatable.20constants'.20equality/near/238386348
-    Unknown,
-}
-
-impl Hash for ConstScalar {
-    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
-        core::mem::discriminant(self).hash(state);
-        if let ConstScalar::Bytes(b, _) = self {
-            b.hash(state)
-        }
-    }
-}
-
-/// A concrete constant value
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum ConstScalarNs<'db> {
-    Bytes(Box<[u8]>, MemoryMap<'db>),
-    // FIXME: this is a hack to get around chalk not being able to represent unevaluatable
-    // constants
-    UnevaluatedConst(GeneralConstId, Substitution),
-    /// Case of an unknown value that rustc might know but we don't
-    // FIXME: this is a hack to get around chalk not being able to represent unevaluatable
-    // constants
-    // https://github.com/rust-lang/rust-analyzer/pull/8813#issuecomment-840679177
-    // https://rust-lang.zulipchat.com/#narrow/stream/144729-wg-traits/topic/Handling.20non.20evaluatable.20constants'.20equality/near/238386348
-    Unknown,
-}
-
-impl Hash for ConstScalarNs<'_> {
-    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
-        core::mem::discriminant(self).hash(state);
-        if let ConstScalarNs::Bytes(b, _) = self {
-            b.hash(state)
-        }
-    }
-}
-
 /// 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, id.parent).type_or_const_param_idx(id)
 }
 
-pub(crate) fn wrap_empty_binders<T>(value: T) -> Binders<T>
-where
-    T: TypeFoldable<Interner> + HasInterner<Interner = Interner>,
-{
-    Binders::empty(Interner, value.shifted_in_from(Interner, DebruijnIndex::ONE))
-}
-
-pub(crate) fn make_single_type_binders<T: HasInterner<Interner = Interner>>(
-    value: T,
-) -> Binders<T> {
-    Binders::new(
-        chalk_ir::VariableKinds::from_iter(
-            Interner,
-            std::iter::once(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)),
-        ),
-        value,
-    )
-}
-
-pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>(
-    db: &dyn HirDatabase,
-    generics: &Generics,
-    value: T,
-) -> Binders<T> {
-    Binders::new(variable_kinds_from_iter(db, generics.iter_id()), value)
-}
-
-pub(crate) fn variable_kinds_from_iter(
-    db: &dyn HirDatabase,
-    iter: impl Iterator<Item = hir_def::GenericParamId>,
-) -> VariableKinds<Interner> {
-    VariableKinds::from_iter(
-        Interner,
-        iter.map(|x| match x {
-            hir_def::GenericParamId::ConstParamId(id) => {
-                chalk_ir::VariableKind::Const(db.const_param_ty(id))
-            }
-            hir_def::GenericParamId::TypeParamId(_) => {
-                chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
-            }
-            hir_def::GenericParamId::LifetimeParamId(_) => chalk_ir::VariableKind::Lifetime,
-        }),
-    )
-}
-
-// 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.
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub struct CallableSig {
-    params_and_return: Arc<[Ty]>,
-    is_varargs: bool,
-    safety: Safety,
-    abi: FnAbi,
-}
-
-has_interner!(CallableSig);
-
 #[derive(Debug, Copy, Clone, Eq)]
 pub enum FnAbi {
     Aapcs,
@@ -534,195 +331,23 @@
     }
 }
 
-/// A polymorphic function signature.
-pub type PolyFnSig = Binders<CallableSig>;
-
-impl CallableSig {
-    pub fn from_params_and_return(
-        params: impl Iterator<Item = Ty>,
-        ret: Ty,
-        is_varargs: bool,
-        safety: Safety,
-        abi: FnAbi,
-    ) -> CallableSig {
-        let mut params_and_return = Vec::with_capacity(params.size_hint().0 + 1);
-        params_and_return.extend(params);
-        params_and_return.push(ret);
-        CallableSig { params_and_return: params_and_return.into(), is_varargs, safety, abi }
-    }
-
-    pub fn from_def(db: &dyn HirDatabase, def: FnDefId, substs: &Substitution) -> CallableSig {
-        let callable_def = ToChalk::from_chalk(db, def);
-        let interner = DbInterner::new_with(db, None, None);
-        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
-        let sig = db.callable_item_signature(callable_def);
-        sig.instantiate(interner, args).skip_binder().to_chalk(interner)
-    }
-    pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig {
-        CallableSig {
-            // FIXME: what to do about lifetime params? -> return PolyFnSig
-            params_and_return: Arc::from_iter(
-                fn_ptr
-                    .substitution
-                    .clone()
-                    .shifted_out_to(Interner, DebruijnIndex::ONE)
-                    .expect("unexpected lifetime vars in fn ptr")
-                    .0
-                    .as_slice(Interner)
-                    .iter()
-                    .map(|arg| arg.assert_ty_ref(Interner).clone()),
-            ),
-            is_varargs: fn_ptr.sig.variadic,
-            safety: fn_ptr.sig.safety,
-            abi: fn_ptr.sig.abi,
-        }
-    }
-    pub fn from_fn_sig_and_header<'db>(
-        interner: DbInterner<'db>,
-        sig: crate::next_solver::Binder<'db, rustc_type_ir::FnSigTys<DbInterner<'db>>>,
-        header: rustc_type_ir::FnHeader<DbInterner<'db>>,
-    ) -> CallableSig {
-        CallableSig {
-            // FIXME: what to do about lifetime params? -> return PolyFnSig
-            params_and_return: Arc::from_iter(
-                sig.skip_binder()
-                    .inputs_and_output
-                    .iter()
-                    .map(|t| convert_ty_for_result(interner, t)),
-            ),
-            is_varargs: header.c_variadic,
-            safety: match header.safety {
-                next_solver::abi::Safety::Safe => chalk_ir::Safety::Safe,
-                next_solver::abi::Safety::Unsafe => chalk_ir::Safety::Unsafe,
-            },
-            abi: header.abi,
-        }
-    }
-
-    pub fn to_fn_ptr(&self) -> FnPointer {
-        FnPointer {
-            num_binders: 0,
-            sig: FnSig { abi: self.abi, safety: self.safety, variadic: self.is_varargs },
-            substitution: FnSubst(Substitution::from_iter(
-                Interner,
-                self.params_and_return.iter().cloned(),
-            )),
-        }
-    }
-
-    pub fn abi(&self) -> FnAbi {
-        self.abi
-    }
-
-    pub fn params(&self) -> &[Ty] {
-        &self.params_and_return[0..self.params_and_return.len() - 1]
-    }
-
-    pub fn ret(&self) -> &Ty {
-        &self.params_and_return[self.params_and_return.len() - 1]
-    }
-}
-
-impl TypeFoldable<Interner> for CallableSig {
-    fn try_fold_with<E>(
-        self,
-        folder: &mut dyn chalk_ir::fold::FallibleTypeFolder<Interner, Error = E>,
-        outer_binder: DebruijnIndex,
-    ) -> Result<Self, E> {
-        let vec = self.params_and_return.to_vec();
-        let folded = vec.try_fold_with(folder, outer_binder)?;
-        Ok(CallableSig {
-            params_and_return: folded.into(),
-            is_varargs: self.is_varargs,
-            safety: self.safety,
-            abi: self.abi,
-        })
-    }
-}
-
 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
-pub enum ImplTraitId {
-    ReturnTypeImplTrait(hir_def::FunctionId, ImplTraitIdx), // FIXME(next-solver): Should be crate::nextsolver::ImplTraitIdx.
-    TypeAliasImplTrait(hir_def::TypeAliasId, ImplTraitIdx),
-    AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId),
-}
-
-#[derive(PartialEq, Eq, Debug, Hash)]
-pub struct ImplTraits {
-    pub(crate) impl_traits: Arena<ImplTrait>,
-}
-
-has_interner!(ImplTraits);
-
-#[derive(PartialEq, Eq, Debug, Hash)]
-pub struct ImplTrait {
-    pub(crate) bounds: Binders<Vec<QuantifiedWhereClause>>,
-}
-
-pub type ImplTraitIdx = Idx<ImplTrait>;
-
-pub fn static_lifetime() -> Lifetime {
-    LifetimeData::Static.intern(Interner)
-}
-
-pub fn error_lifetime() -> Lifetime {
-    LifetimeData::Error.intern(Interner)
-}
-
-pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>(
-    t: T,
-    for_ty: impl FnMut(BoundVar, DebruijnIndex) -> Ty,
-    for_const: impl FnMut(Ty, BoundVar, DebruijnIndex) -> Const,
-) -> T {
-    use chalk_ir::fold::TypeFolder;
-
-    #[derive(chalk_derive::FallibleTypeFolder)]
-    #[has_interner(Interner)]
-    struct FreeVarFolder<
-        F1: FnMut(BoundVar, DebruijnIndex) -> Ty,
-        F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const,
-    >(F1, F2);
-    impl<F1: FnMut(BoundVar, DebruijnIndex) -> Ty, F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const>
-        TypeFolder<Interner> for FreeVarFolder<F1, F2>
-    {
-        fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner> {
-            self
-        }
-
-        fn interner(&self) -> Interner {
-            Interner
-        }
-
-        fn fold_free_var_ty(&mut self, bound_var: BoundVar, outer_binder: DebruijnIndex) -> Ty {
-            self.0(bound_var, outer_binder)
-        }
-
-        fn fold_free_var_const(
-            &mut self,
-            ty: Ty,
-            bound_var: BoundVar,
-            outer_binder: DebruijnIndex,
-        ) -> Const {
-            self.1(ty, bound_var, outer_binder)
-        }
-    }
-    t.fold_with(&mut FreeVarFolder(for_ty, for_const), DebruijnIndex::INNERMOST)
+pub enum ImplTraitId<'db> {
+    ReturnTypeImplTrait(hir_def::FunctionId, next_solver::ImplTraitIdx<'db>),
+    TypeAliasImplTrait(hir_def::TypeAliasId, next_solver::ImplTraitIdx<'db>),
 }
 
 /// 'Canonicalizes' the `t` by replacing any errors with new variables. Also
 /// ensures there are no unbound variables or inference variables anywhere in
 /// the `t`.
-pub fn replace_errors_with_variables<'db, T>(
-    interner: DbInterner<'db>,
-    t: &T,
-) -> crate::next_solver::Canonical<'db, T>
+pub fn replace_errors_with_variables<'db, T>(interner: DbInterner<'db>, t: &T) -> Canonical<'db, T>
 where
     T: rustc_type_ir::TypeFoldable<DbInterner<'db>> + Clone,
 {
     use rustc_type_ir::{FallibleTypeFolder, TypeSuperFoldable};
     struct ErrorReplacer<'db> {
         interner: DbInterner<'db>,
-        vars: Vec<crate::next_solver::CanonicalVarKind<'db>>,
+        vars: Vec<CanonicalVarKind<'db>>,
         binder: rustc_type_ir::DebruijnIndex,
     }
     impl<'db> FallibleTypeFolder<DbInterner<'db>> for ErrorReplacer<'db> {
@@ -735,10 +360,7 @@
             self.interner
         }
 
-        fn try_fold_binder<T>(
-            &mut self,
-            t: crate::next_solver::Binder<'db, T>,
-        ) -> Result<crate::next_solver::Binder<'db, T>, Self::Error>
+        fn try_fold_binder<T>(&mut self, t: Binder<'db, T>) -> Result<Binder<'db, T>, Self::Error>
         where
             T: rustc_type_ir::TypeFoldable<DbInterner<'db>>,
         {
@@ -748,10 +370,7 @@
             result
         }
 
-        fn try_fold_ty(
-            &mut self,
-            t: crate::next_solver::Ty<'db>,
-        ) -> Result<crate::next_solver::Ty<'db>, Self::Error> {
+        fn try_fold_ty(&mut self, t: Ty<'db>) -> Result<Ty<'db>, Self::Error> {
             if !t.has_type_flags(
                 rustc_type_ir::TypeFlags::HAS_ERROR
                     | rustc_type_ir::TypeFlags::HAS_TY_INFER
@@ -764,34 +383,28 @@
             #[cfg(debug_assertions)]
             let error = || Err(());
             #[cfg(not(debug_assertions))]
-            let error = || Ok(crate::next_solver::Ty::new_error(self.interner, ErrorGuaranteed));
+            let error = || Ok(Ty::new_error(self.interner, crate::next_solver::ErrorGuaranteed));
 
             match t.kind() {
-                crate::next_solver::TyKind::Error(_) => {
+                TyKind::Error(_) => {
                     let var = rustc_type_ir::BoundVar::from_usize(self.vars.len());
-                    self.vars.push(crate::next_solver::CanonicalVarKind::Ty {
+                    self.vars.push(CanonicalVarKind::Ty {
                         ui: rustc_type_ir::UniverseIndex::ZERO,
                         sub_root: var,
                     });
-                    Ok(crate::next_solver::Ty::new_bound(
+                    Ok(Ty::new_bound(
                         self.interner,
                         self.binder,
-                        crate::next_solver::BoundTy {
-                            var,
-                            kind: crate::next_solver::BoundTyKind::Anon,
-                        },
+                        BoundTy { var, kind: BoundTyKind::Anon },
                     ))
                 }
-                crate::next_solver::TyKind::Infer(_) => error(),
-                crate::next_solver::TyKind::Bound(index, _) if index > self.binder => error(),
+                TyKind::Infer(_) => error(),
+                TyKind::Bound(BoundVarIndexKind::Bound(index), _) if index > self.binder => error(),
                 _ => t.try_super_fold_with(self),
             }
         }
 
-        fn try_fold_const(
-            &mut self,
-            ct: crate::next_solver::Const<'db>,
-        ) -> Result<crate::next_solver::Const<'db>, Self::Error> {
+        fn try_fold_const(&mut self, ct: Const<'db>) -> Result<Const<'db>, Self::Error> {
             if !ct.has_type_flags(
                 rustc_type_ir::TypeFlags::HAS_ERROR
                     | rustc_type_ir::TypeFlags::HAS_TY_INFER
@@ -804,52 +417,42 @@
             #[cfg(debug_assertions)]
             let error = || Err(());
             #[cfg(not(debug_assertions))]
-            let error = || Ok(crate::next_solver::Const::error(self.interner));
+            let error = || Ok(Const::error(self.interner));
 
             match ct.kind() {
-                crate::next_solver::ConstKind::Error(_) => {
+                ConstKind::Error(_) => {
                     let var = rustc_type_ir::BoundVar::from_usize(self.vars.len());
-                    self.vars.push(crate::next_solver::CanonicalVarKind::Const(
-                        rustc_type_ir::UniverseIndex::ZERO,
-                    ));
-                    Ok(crate::next_solver::Const::new_bound(
-                        self.interner,
-                        self.binder,
-                        crate::next_solver::BoundConst { var },
-                    ))
+                    self.vars.push(CanonicalVarKind::Const(rustc_type_ir::UniverseIndex::ZERO));
+                    Ok(Const::new_bound(self.interner, self.binder, BoundConst { var }))
                 }
-                crate::next_solver::ConstKind::Infer(_) => error(),
-                crate::next_solver::ConstKind::Bound(index, _) if index > self.binder => error(),
+                ConstKind::Infer(_) => error(),
+                ConstKind::Bound(BoundVarIndexKind::Bound(index), _) if index > self.binder => {
+                    error()
+                }
                 _ => ct.try_super_fold_with(self),
             }
         }
 
-        fn try_fold_region(
-            &mut self,
-            region: crate::next_solver::Region<'db>,
-        ) -> Result<crate::next_solver::Region<'db>, Self::Error> {
+        fn try_fold_region(&mut self, region: Region<'db>) -> Result<Region<'db>, Self::Error> {
             #[cfg(debug_assertions)]
             let error = || Err(());
             #[cfg(not(debug_assertions))]
-            let error = || Ok(crate::next_solver::Region::error(self.interner));
+            let error = || Ok(Region::error(self.interner));
 
             match region.kind() {
-                crate::next_solver::RegionKind::ReError(_) => {
+                RegionKind::ReError(_) => {
                     let var = rustc_type_ir::BoundVar::from_usize(self.vars.len());
-                    self.vars.push(crate::next_solver::CanonicalVarKind::Region(
-                        rustc_type_ir::UniverseIndex::ZERO,
-                    ));
-                    Ok(crate::next_solver::Region::new_bound(
+                    self.vars.push(CanonicalVarKind::Region(rustc_type_ir::UniverseIndex::ZERO));
+                    Ok(Region::new_bound(
                         self.interner,
                         self.binder,
-                        crate::next_solver::BoundRegion {
-                            var,
-                            kind: crate::next_solver::BoundRegionKind::Anon,
-                        },
+                        BoundRegion { var, kind: BoundRegionKind::Anon },
                     ))
                 }
-                crate::next_solver::RegionKind::ReVar(_) => error(),
-                crate::next_solver::RegionKind::ReBound(index, _) if index > self.binder => error(),
+                RegionKind::ReVar(_) => error(),
+                RegionKind::ReBound(BoundVarIndexKind::Bound(index), _) if index > self.binder => {
+                    error()
+                }
                 _ => Ok(region),
             }
         }
@@ -861,18 +464,18 @@
         Ok(t) => t,
         Err(_) => panic!("Encountered unbound or inference vars in {t:?}"),
     };
-    crate::next_solver::Canonical {
+    Canonical {
         value,
         max_universe: rustc_type_ir::UniverseIndex::ZERO,
-        variables: crate::next_solver::CanonicalVars::new_from_iter(interner, error_replacer.vars),
+        variables: CanonicalVars::new_from_iter(interner, error_replacer.vars),
     }
 }
 
 pub fn callable_sig_from_fn_trait<'db>(
-    self_ty: crate::next_solver::Ty<'db>,
+    self_ty: Ty<'db>,
     trait_env: Arc<TraitEnvironment<'db>>,
     db: &'db dyn HirDatabase,
-) -> Option<(FnTrait, crate::next_solver::PolyFnSig<'db>)> {
+) -> Option<(FnTrait, PolyFnSig<'db>)> {
     let krate = trait_env.krate;
     let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?;
     let output_assoc_type = fn_once_trait
@@ -880,54 +483,46 @@
         .associated_type_by_name(&Name::new_symbol_root(sym::Output))?;
 
     let mut table = InferenceTable::new(db, trait_env.clone());
-    let b = TyBuilder::trait_ref(db, fn_once_trait);
-    if b.remaining() != 2 {
-        return None;
-    }
 
     // Register two obligations:
     // - Self: FnOnce<?args_ty>
     // - <Self as FnOnce<?args_ty>>::Output == ?ret_ty
     let args_ty = table.next_ty_var();
     let args = [self_ty, args_ty];
-    let trait_ref = crate::next_solver::TraitRef::new(table.interner(), fn_once_trait.into(), args);
-    let projection = crate::next_solver::Ty::new_alias(
+    let trait_ref = TraitRef::new(table.interner(), fn_once_trait.into(), args);
+    let projection = Ty::new_alias(
         table.interner(),
         rustc_type_ir::AliasTyKind::Projection,
-        crate::next_solver::AliasTy::new(table.interner(), output_assoc_type.into(), args),
+        AliasTy::new(table.interner(), output_assoc_type.into(), args),
     );
 
-    let pred = crate::next_solver::Predicate::upcast_from(trait_ref, table.interner());
+    let pred = Predicate::upcast_from(trait_ref, table.interner());
     if !table.try_obligation(pred).no_solution() {
         table.register_obligation(pred);
         let return_ty = table.normalize_alias_ty(projection);
         for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] {
             let fn_x_trait = fn_x.get_id(db, krate)?;
-            let trait_ref =
-                crate::next_solver::TraitRef::new(table.interner(), fn_x_trait.into(), args);
+            let trait_ref = TraitRef::new(table.interner(), fn_x_trait.into(), args);
             if !table
-                .try_obligation(crate::next_solver::Predicate::upcast_from(
-                    trait_ref,
-                    table.interner(),
-                ))
+                .try_obligation(Predicate::upcast_from(trait_ref, table.interner()))
                 .no_solution()
             {
                 let ret_ty = table.resolve_completely(return_ty);
                 let args_ty = table.resolve_completely(args_ty);
-                let crate::next_solver::TyKind::Tuple(params) = args_ty.kind() else {
+                let TyKind::Tuple(params) = args_ty.kind() else {
                     return None;
                 };
-                let inputs_and_output = crate::next_solver::Tys::new_from_iter(
+                let inputs_and_output = Tys::new_from_iter(
                     table.interner(),
                     params.iter().chain(std::iter::once(ret_ty)),
                 );
 
                 return Some((
                     fn_x,
-                    crate::next_solver::Binder::dummy(crate::next_solver::FnSig {
+                    Binder::dummy(FnSig {
                         inputs_and_output,
                         c_variadic: false,
-                        safety: crate::next_solver::abi::Safety::Safe,
+                        safety: abi::Safety::Safe,
                         abi: FnAbi::RustCall,
                     }),
                 ));
@@ -946,16 +541,16 @@
 impl<'db> rustc_type_ir::TypeVisitor<DbInterner<'db>> for ParamCollector {
     type Result = ();
 
-    fn visit_ty(&mut self, ty: crate::next_solver::Ty<'db>) -> Self::Result {
-        if let crate::next_solver::TyKind::Param(param) = ty.kind() {
+    fn visit_ty(&mut self, ty: Ty<'db>) -> Self::Result {
+        if let TyKind::Param(param) = ty.kind() {
             self.params.insert(param.id.into());
         }
 
         ty.super_visit_with(self);
     }
 
-    fn visit_const(&mut self, konst: crate::next_solver::Const<'db>) -> Self::Result {
-        if let crate::next_solver::ConstKind::Param(param) = konst.kind() {
+    fn visit_const(&mut self, konst: Const<'db>) -> Self::Result {
+        if let ConstKind::Param(param) = konst.kind() {
             self.params.insert(param.id.into());
         }
 
@@ -974,7 +569,7 @@
 }
 
 pub fn known_const_to_ast<'db>(
-    konst: crate::next_solver::Const<'db>,
+    konst: Const<'db>,
     db: &'db dyn HirDatabase,
     display_target: DisplayTarget,
 ) -> Option<ConstArg> {
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index b18d713..a181ae0 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -11,82 +11,93 @@
 use std::{
     cell::OnceCell,
     iter, mem,
-    ops::{self, Not as _},
+    ops::{self, Deref, Not as _},
 };
 
 use base_db::Crate;
-use chalk_ir::{
-    Mutability, Safety, TypeOutlives,
-    cast::Cast,
-    fold::{Shift, TypeFoldable},
-    interner::HasInterner,
-};
-
 use either::Either;
 use hir_def::{
-    AdtId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId,
-    GenericParamId, LocalFieldId, Lookup, StaticId, StructId, TypeAliasId, TypeOrConstParamId,
+    AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId,
+    FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
+    LocalFieldId, Lookup, StaticId, StructId, TypeAliasId, TypeOrConstParamId, TypeParamId,
     UnionId, VariantId,
     builtin_type::BuiltinType,
-    expr_store::{ExpressionStore, path::Path},
-    hir::generics::{GenericParamDataRef, TypeOrConstParamData, WherePredicate},
+    expr_store::{ExpressionStore, HygieneId, path::Path},
+    hir::generics::{
+        GenericParamDataRef, TypeOrConstParamData, TypeParamProvenance, WherePredicate,
+    },
+    item_tree::FieldsShape,
     lang_item::LangItem,
-    resolver::{HasResolver, LifetimeNs, Resolver, TypeNs},
-    signatures::TraitFlags,
+    resolver::{HasResolver, LifetimeNs, Resolver, TypeNs, ValueNs},
+    signatures::{FunctionSignature, TraitFlags, TypeAliasFlags},
     type_ref::{
-        ConstRef, LifetimeRefId, LiteralConstRef, PathId, TraitBoundModifier, TypeBound, TypeRef,
-        TypeRefId,
+        ConstRef, LifetimeRefId, LiteralConstRef, PathId, TraitBoundModifier,
+        TraitRef as HirTraitRef, TypeBound, TypeRef, TypeRefId,
     },
 };
 use hir_expand::name::Name;
-use la_arena::{Arena, ArenaMap};
+use la_arena::{Arena, ArenaMap, Idx};
+use path::{PathDiagnosticCallback, PathLoweringContext};
+use rustc_ast_ir::Mutability;
 use rustc_hash::FxHashSet;
+use rustc_pattern_analysis::Captures;
+use rustc_type_ir::{
+    AliasTyKind, BoundVarIndexKind, ConstKind, DebruijnIndex, ExistentialPredicate,
+    ExistentialProjection, ExistentialTraitRef, FnSig, OutlivesPredicate,
+    TyKind::{self},
+    TypeVisitableExt,
+    inherent::{GenericArg as _, GenericArgs as _, IntoKind as _, Region as _, SliceLike, Ty as _},
+};
+use salsa::plumbing::AsId;
+use smallvec::{SmallVec, smallvec};
 use stdx::{impl_from, never};
 use triomphe::{Arc, ThinArc};
 
 use crate::{
-    AliasTy, Binders, BoundVar, Const, DebruijnIndex, DynTy, FnAbi, FnPointer, FnSig, FnSubst,
-    ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime, LifetimeData, LifetimeOutlives,
-    QuantifiedWhereClause, QuantifiedWhereClauses, Substitution, TraitRef, TraitRefExt, Ty,
-    TyBuilder, TyKind, WhereClause, all_super_traits,
-    consteval_chalk::{intern_const_ref, path_to_const, unknown_const, unknown_const_as_generic},
+    FnAbi, ImplTraitId, TraitEnvironment, TyLoweringDiagnostic, TyLoweringDiagnosticKind,
+    consteval::intern_const_ref,
     db::HirDatabase,
-    error_lifetime,
     generics::{Generics, generics, trait_self_param_idx},
-    lower::{
-        diagnostics::*,
-        path::{PathDiagnosticCallback, PathLoweringContext},
-    },
-    make_binders,
-    mapping::{from_chalk_trait_id, lt_to_placeholder_idx},
     next_solver::{
-        DbInterner,
-        mapping::{ChalkToNextSolver, NextSolverToChalk},
+        AliasTy, Binder, BoundExistentialPredicates, Clause, Clauses, Const, DbInterner,
+        EarlyBinder, EarlyParamRegion, ErrorGuaranteed, GenericArg, GenericArgs, ParamConst,
+        ParamEnv, PolyFnSig, Predicate, Region, SolverDefId, TraitPredicate, TraitRef, Ty, Tys,
+        UnevaluatedConst, abi::Safety,
     },
-    static_lifetime, to_chalk_trait_id, to_placeholder_idx,
-    utils::all_super_trait_refs,
-    variable_kinds_from_iter,
 };
 
+pub(crate) struct PathDiagnosticCallbackData(pub(crate) TypeRefId);
+
+#[derive(PartialEq, Eq, Debug, Hash)]
+pub struct ImplTraits<'db> {
+    pub(crate) impl_traits: Arena<ImplTrait<'db>>,
+}
+
+#[derive(PartialEq, Eq, Debug, Hash)]
+pub struct ImplTrait<'db> {
+    pub(crate) predicates: Vec<Clause<'db>>,
+}
+
+pub type ImplTraitIdx<'db> = Idx<ImplTrait<'db>>;
+
 #[derive(Debug, Default)]
-struct ImplTraitLoweringState {
+struct ImplTraitLoweringState<'db> {
     /// When turning `impl Trait` into opaque types, we have to collect the
     /// bounds at the same time to get the IDs correct (without becoming too
     /// complicated).
     mode: ImplTraitLoweringMode,
     // This is structured as a struct with fields and not as an enum because it helps with the borrow checker.
-    opaque_type_data: Arena<ImplTrait>,
+    opaque_type_data: Arena<ImplTrait<'db>>,
 }
-impl ImplTraitLoweringState {
-    fn new(mode: ImplTraitLoweringMode) -> ImplTraitLoweringState {
+
+impl<'db> ImplTraitLoweringState<'db> {
+    fn new(mode: ImplTraitLoweringMode) -> ImplTraitLoweringState<'db> {
         Self { mode, opaque_type_data: Arena::new() }
     }
 }
 
-pub(crate) struct PathDiagnosticCallbackData(pub(crate) TypeRefId);
-
 #[derive(Debug, Clone)]
-pub(crate) enum LifetimeElisionKind {
+pub enum LifetimeElisionKind<'db> {
     /// Create a new anonymous lifetime parameter and reference it.
     ///
     /// If `report_in_path`, report an error when encountering lifetime elision in a path:
@@ -104,75 +115,109 @@
     AnonymousCreateParameter { report_in_path: bool },
 
     /// Replace all anonymous lifetimes by provided lifetime.
-    Elided(Lifetime),
+    Elided(Region<'db>),
 
     /// Give a hard error when either `&` or `'_` is written. Used to
     /// rule out things like `where T: Foo<'_>`. Does not imply an
     /// error on default object bounds (e.g., `Box<dyn Foo>`).
     AnonymousReportError,
 
+    /// Resolves elided lifetimes to `'static` if there are no other lifetimes in scope,
+    /// otherwise give a warning that the previous behavior of introducing a new early-bound
+    /// lifetime is a bug and will be removed (if `only_lint` is enabled).
+    StaticIfNoLifetimeInScope { only_lint: bool },
+
+    /// Signal we cannot find which should be the anonymous lifetime.
+    ElisionFailure,
+
     /// Infer all elided lifetimes.
     Infer,
 }
 
-impl LifetimeElisionKind {
+impl<'db> LifetimeElisionKind<'db> {
     #[inline]
-    pub(crate) fn for_fn_ret() -> LifetimeElisionKind {
+    pub(crate) fn for_const(
+        interner: DbInterner<'db>,
+        const_parent: ItemContainerId,
+    ) -> LifetimeElisionKind<'db> {
+        match const_parent {
+            ItemContainerId::ExternBlockId(_) | ItemContainerId::ModuleId(_) => {
+                LifetimeElisionKind::Elided(Region::new_static(interner))
+            }
+            ItemContainerId::ImplId(_) => {
+                LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: true }
+            }
+            ItemContainerId::TraitId(_) => {
+                LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: false }
+            }
+        }
+    }
+
+    #[inline]
+    pub(crate) fn for_fn_params(data: &FunctionSignature) -> LifetimeElisionKind<'db> {
+        LifetimeElisionKind::AnonymousCreateParameter { report_in_path: data.is_async() }
+    }
+
+    #[inline]
+    pub(crate) fn for_fn_ret(interner: DbInterner<'db>) -> LifetimeElisionKind<'db> {
         // FIXME: We should use the elided lifetime here, or `ElisionFailure`.
-        LifetimeElisionKind::Elided(error_lifetime())
+        LifetimeElisionKind::Elided(Region::error(interner))
     }
 }
 
 #[derive(Debug)]
-pub(crate) struct TyLoweringContext<'db> {
+pub struct TyLoweringContext<'db, 'a> {
     pub db: &'db dyn HirDatabase,
-    resolver: &'db Resolver<'db>,
-    store: &'db ExpressionStore,
+    interner: DbInterner<'db>,
+    resolver: &'a Resolver<'db>,
+    store: &'a ExpressionStore,
     def: GenericDefId,
     generics: OnceCell<Generics>,
     in_binders: DebruijnIndex,
-    /// Note: Conceptually, it's thinkable that we could be in a location where
-    /// some type params should be represented as placeholders, and others
-    /// should be converted to variables. I think in practice, this isn't
-    /// possible currently, so this should be fine for now.
-    pub type_param_mode: ParamLoweringMode,
-    impl_trait_mode: ImplTraitLoweringState,
+    impl_trait_mode: ImplTraitLoweringState<'db>,
     /// Tracks types with explicit `?Sized` bounds.
-    pub(crate) unsized_types: FxHashSet<Ty>,
+    pub(crate) unsized_types: FxHashSet<Ty<'db>>,
     pub(crate) diagnostics: Vec<TyLoweringDiagnostic>,
-    lifetime_elision: LifetimeElisionKind,
+    lifetime_elision: LifetimeElisionKind<'db>,
+    /// When lowering the defaults for generic params, this contains the index of the currently lowered param.
+    /// We disallow referring to later params, or to ADT's `Self`.
+    lowering_param_default: Option<u32>,
 }
 
-impl<'db> TyLoweringContext<'db> {
-    pub(crate) fn new(
+impl<'db, 'a> TyLoweringContext<'db, 'a> {
+    pub fn new(
         db: &'db dyn HirDatabase,
-        resolver: &'db Resolver<'db>,
-        store: &'db ExpressionStore,
+        resolver: &'a Resolver<'db>,
+        store: &'a ExpressionStore,
         def: GenericDefId,
-        lifetime_elision: LifetimeElisionKind,
+        lifetime_elision: LifetimeElisionKind<'db>,
     ) -> Self {
         let impl_trait_mode = ImplTraitLoweringState::new(ImplTraitLoweringMode::Disallowed);
-        let type_param_mode = ParamLoweringMode::Placeholder;
-        let in_binders = DebruijnIndex::INNERMOST;
+        let in_binders = DebruijnIndex::ZERO;
         Self {
             db,
+            interner: DbInterner::new_with(db, Some(resolver.krate()), None),
             resolver,
             def,
             generics: Default::default(),
             store,
             in_binders,
             impl_trait_mode,
-            type_param_mode,
             unsized_types: FxHashSet::default(),
             diagnostics: Vec::new(),
             lifetime_elision,
+            lowering_param_default: None,
         }
     }
 
+    pub(crate) fn set_lifetime_elision(&mut self, lifetime_elision: LifetimeElisionKind<'db>) {
+        self.lifetime_elision = lifetime_elision;
+    }
+
     pub(crate) fn with_debruijn<T>(
         &mut self,
         debruijn: DebruijnIndex,
-        f: impl FnOnce(&mut TyLoweringContext<'_>) -> T,
+        f: impl FnOnce(&mut TyLoweringContext<'db, '_>) -> T,
     ) -> T {
         let old_debruijn = mem::replace(&mut self.in_binders, debruijn);
         let result = f(self);
@@ -183,28 +228,22 @@
     pub(crate) fn with_shifted_in<T>(
         &mut self,
         debruijn: DebruijnIndex,
-        f: impl FnOnce(&mut TyLoweringContext<'_>) -> T,
+        f: impl FnOnce(&mut TyLoweringContext<'db, '_>) -> T,
     ) -> T {
-        self.with_debruijn(self.in_binders.shifted_in_from(debruijn), f)
-    }
-
-    fn with_lifetime_elision<T>(
-        &mut self,
-        lifetime_elision: LifetimeElisionKind,
-        f: impl FnOnce(&mut TyLoweringContext<'_>) -> T,
-    ) -> T {
-        let old_lifetime_elision = mem::replace(&mut self.lifetime_elision, lifetime_elision);
-        let result = f(self);
-        self.lifetime_elision = old_lifetime_elision;
-        result
+        self.with_debruijn(self.in_binders.shifted_in(debruijn.as_u32()), f)
     }
 
     pub(crate) fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self {
         Self { impl_trait_mode: ImplTraitLoweringState::new(impl_trait_mode), ..self }
     }
 
-    pub(crate) fn with_type_param_mode(self, type_param_mode: ParamLoweringMode) -> Self {
-        Self { type_param_mode, ..self }
+    pub(crate) fn impl_trait_mode(&mut self, impl_trait_mode: ImplTraitLoweringMode) -> &mut Self {
+        self.impl_trait_mode = ImplTraitLoweringState::new(impl_trait_mode);
+        self
+    }
+
+    pub(crate) fn lowering_param_default(&mut self, index: u32) {
+        self.lowering_param_default = Some(index);
     }
 
     pub(crate) fn push_diagnostic(&mut self, type_ref: TypeRefId, kind: TyLoweringDiagnosticKind) {
@@ -213,7 +252,7 @@
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
-pub enum ImplTraitLoweringMode {
+pub(crate) enum ImplTraitLoweringMode {
     /// `impl Trait` gets lowered into an opaque type that doesn't unify with
     /// anything except itself. This is used in places where values flow 'out',
     /// i.e. for arguments of the function we're currently checking, and return
@@ -224,30 +263,17 @@
     Disallowed,
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum ParamLoweringMode {
-    Placeholder,
-    Variable,
-}
-
-impl<'db> TyLoweringContext<'db> {
-    pub(crate) fn lower_ty(&mut self, type_ref: TypeRefId) -> Ty {
+impl<'db, 'a> TyLoweringContext<'db, 'a> {
+    pub fn lower_ty(&mut self, type_ref: TypeRefId) -> Ty<'db> {
         self.lower_ty_ext(type_ref).0
     }
 
-    pub(crate) fn lower_const(&mut self, const_ref: &ConstRef, const_type: Ty) -> Const {
+    pub(crate) fn lower_const(&mut self, const_ref: ConstRef, const_type: Ty<'db>) -> Const<'db> {
         let const_ref = &self.store[const_ref.expr];
         match const_ref {
-            hir_def::hir::Expr::Path(path) => path_to_const(
-                self.db,
-                self.resolver,
-                path,
-                self.type_param_mode,
-                || self.generics(),
-                self.in_binders,
-                const_type.clone(),
-            )
-            .unwrap_or_else(|| unknown_const(const_type)),
+            hir_def::hir::Expr::Path(path) => {
+                self.path_to_const(path).unwrap_or_else(|| unknown_const(const_type))
+            }
             hir_def::hir::Expr::Literal(literal) => intern_const_ref(
                 self.db,
                 &match *literal {
@@ -290,32 +316,88 @@
         }
     }
 
-    pub(crate) fn lower_path_as_const(&mut self, path: &Path, const_type: Ty) -> Const {
-        path_to_const(
-            self.db,
-            self.resolver,
-            path,
-            self.type_param_mode,
-            || self.generics(),
-            self.in_binders,
-            const_type.clone(),
-        )
-        .unwrap_or_else(|| unknown_const(const_type))
+    pub(crate) fn path_to_const(&mut self, path: &Path) -> Option<Const<'db>> {
+        match self.resolver.resolve_path_in_value_ns_fully(self.db, path, HygieneId::ROOT) {
+            Some(ValueNs::GenericParam(p)) => {
+                let args = self.generics();
+                match args.type_or_const_param_idx(p.into()) {
+                    Some(idx) => Some(self.const_param(p, idx as u32)),
+                    None => {
+                        never!(
+                            "Generic list doesn't contain this param: {:?}, {:?}, {:?}",
+                            args,
+                            path,
+                            p
+                        );
+                        None
+                    }
+                }
+            }
+            Some(ValueNs::ConstId(c)) => {
+                let args = GenericArgs::new_from_iter(self.interner, []);
+                Some(Const::new(
+                    self.interner,
+                    rustc_type_ir::ConstKind::Unevaluated(UnevaluatedConst::new(
+                        SolverDefId::ConstId(c),
+                        args,
+                    )),
+                ))
+            }
+            _ => None,
+        }
+    }
+
+    pub(crate) fn lower_path_as_const(&mut self, path: &Path, const_type: Ty<'db>) -> Const<'db> {
+        self.path_to_const(path).unwrap_or_else(|| unknown_const(const_type))
     }
 
     fn generics(&self) -> &Generics {
         self.generics.get_or_init(|| generics(self.db, self.def))
     }
 
-    pub(crate) fn lower_ty_ext(&mut self, type_ref_id: TypeRefId) -> (Ty, Option<TypeNs>) {
+    fn param_index_is_disallowed(&self, index: u32) -> bool {
+        self.lowering_param_default
+            .is_some_and(|disallow_params_after| index >= disallow_params_after)
+    }
+
+    fn type_param(&mut self, id: TypeParamId, index: u32) -> Ty<'db> {
+        if self.param_index_is_disallowed(index) {
+            // FIXME: Report an error.
+            Ty::new_error(self.interner, ErrorGuaranteed)
+        } else {
+            Ty::new_param(self.interner, id, index)
+        }
+    }
+
+    fn const_param(&mut self, id: ConstParamId, index: u32) -> Const<'db> {
+        if self.param_index_is_disallowed(index) {
+            // FIXME: Report an error.
+            Const::error(self.interner)
+        } else {
+            Const::new_param(self.interner, ParamConst { id, index })
+        }
+    }
+
+    fn region_param(&mut self, id: LifetimeParamId, index: u32) -> Region<'db> {
+        if self.param_index_is_disallowed(index) {
+            // FIXME: Report an error.
+            Region::error(self.interner)
+        } else {
+            Region::new_early_param(self.interner, EarlyParamRegion { id, index })
+        }
+    }
+
+    #[tracing::instrument(skip(self), ret)]
+    pub fn lower_ty_ext(&mut self, type_ref_id: TypeRefId) -> (Ty<'db>, Option<TypeNs>) {
+        let interner = self.interner;
         let mut res = None;
         let type_ref = &self.store[type_ref_id];
+        tracing::debug!(?type_ref);
         let ty = match type_ref {
-            TypeRef::Never => TyKind::Never.intern(Interner),
+            TypeRef::Never => Ty::new(interner, TyKind::Never),
             TypeRef::Tuple(inner) => {
                 let inner_tys = inner.iter().map(|&tr| self.lower_ty(tr));
-                TyKind::Tuple(inner_tys.len(), Substitution::from_iter(Interner, inner_tys))
-                    .intern(Interner)
+                Ty::new_tup_from_iter(interner, inner_tys)
             }
             TypeRef::Path(path) => {
                 let (ty, res_) =
@@ -325,81 +407,61 @@
             }
             &TypeRef::TypeParam(type_param_id) => {
                 res = Some(TypeNs::GenericParam(type_param_id));
-                match self.type_param_mode {
-                    ParamLoweringMode::Placeholder => {
-                        let generics = self.generics();
-                        let idx = generics.type_or_const_param_idx(type_param_id.into()).unwrap();
-                        TyKind::Placeholder(to_placeholder_idx(
-                            self.db,
-                            type_param_id.into(),
-                            idx as u32,
-                        ))
-                    }
-                    ParamLoweringMode::Variable => {
-                        let idx =
-                            self.generics().type_or_const_param_idx(type_param_id.into()).unwrap();
-                        TyKind::BoundVar(BoundVar::new(self.in_binders, idx))
-                    }
-                }
-                .intern(Interner)
+
+                let generics = self.generics();
+                let (idx, _data) =
+                    generics.type_or_const_param(type_param_id.into()).expect("matching generics");
+                self.type_param(type_param_id, idx as u32)
             }
             &TypeRef::RawPtr(inner, mutability) => {
                 let inner_ty = self.lower_ty(inner);
-                TyKind::Raw(lower_to_chalk_mutability(mutability), inner_ty).intern(Interner)
+                Ty::new(interner, TyKind::RawPtr(inner_ty, lower_mutability(mutability)))
             }
             TypeRef::Array(array) => {
                 let inner_ty = self.lower_ty(array.ty);
-                let const_len = self.lower_const(&array.len, TyBuilder::usize());
-                TyKind::Array(inner_ty, const_len).intern(Interner)
+                let const_len = self.lower_const(array.len, Ty::new_usize(interner));
+                Ty::new_array_with_const_len(interner, inner_ty, const_len)
             }
             &TypeRef::Slice(inner) => {
                 let inner_ty = self.lower_ty(inner);
-                TyKind::Slice(inner_ty).intern(Interner)
+                Ty::new_slice(interner, inner_ty)
             }
             TypeRef::Reference(ref_) => {
                 let inner_ty = self.lower_ty(ref_.ty);
-                // FIXME: It should infer the eldided lifetimes instead of stubbing with static
+                // FIXME: It should infer the eldided lifetimes instead of stubbing with error
                 let lifetime = ref_
                     .lifetime
-                    .as_ref()
-                    .map_or_else(error_lifetime, |&lr| self.lower_lifetime(lr));
-                TyKind::Ref(lower_to_chalk_mutability(ref_.mutability), lifetime, inner_ty)
-                    .intern(Interner)
+                    .map_or_else(|| Region::error(interner), |lr| self.lower_lifetime(lr));
+                Ty::new_ref(interner, lifetime, inner_ty, lower_mutability(ref_.mutability))
             }
-            TypeRef::Placeholder => TyKind::Error.intern(Interner),
+            TypeRef::Placeholder => Ty::new_error(interner, ErrorGuaranteed),
             TypeRef::Fn(fn_) => {
-                let substs = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
-                    let (params, ret) = fn_.split_params_and_ret();
-                    let mut subst = Vec::with_capacity(fn_.params.len());
-                    ctx.with_lifetime_elision(
-                        LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false },
-                        |ctx| {
-                            subst.extend(params.iter().map(|&(_, tr)| ctx.lower_ty(tr)));
-                        },
-                    );
-                    ctx.with_lifetime_elision(LifetimeElisionKind::for_fn_ret(), |ctx| {
-                        subst.push(ctx.lower_ty(ret));
-                    });
-                    Substitution::from_iter(Interner, subst)
-                });
-                TyKind::Function(FnPointer {
-                    num_binders: 0, // FIXME lower `for<'a> fn()` correctly
-                    sig: FnSig {
+                let substs = self.with_shifted_in(
+                    DebruijnIndex::from_u32(1),
+                    |ctx: &mut TyLoweringContext<'_, '_>| {
+                        Tys::new_from_iter(
+                            interner,
+                            fn_.params.iter().map(|&(_, tr)| ctx.lower_ty(tr)),
+                        )
+                    },
+                );
+                Ty::new_fn_ptr(
+                    interner,
+                    Binder::dummy(FnSig {
                         abi: fn_.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol),
                         safety: if fn_.is_unsafe { Safety::Unsafe } else { Safety::Safe },
-                        variadic: fn_.is_varargs,
-                    },
-                    substitution: FnSubst(substs),
-                })
-                .intern(Interner)
+                        c_variadic: fn_.is_varargs,
+                        inputs_and_output: substs,
+                    }),
+                )
             }
             TypeRef::DynTrait(bounds) => self.lower_dyn_trait(bounds),
             TypeRef::ImplTrait(bounds) => {
                 match self.impl_trait_mode.mode {
                     ImplTraitLoweringMode::Opaque => {
-                        let origin = match self.def {
-                            GenericDefId::FunctionId(it) => Either::Left(it),
-                            GenericDefId::TypeAliasId(it) => Either::Right(it),
+                        let origin = match self.resolver.generic_def() {
+                            Some(GenericDefId::FunctionId(it)) => Either::Left(it),
+                            Some(GenericDefId::TypeAliasId(it)) => Either::Right(it),
                             _ => panic!(
                                 "opaque impl trait lowering must be in function or type alias"
                             ),
@@ -408,9 +470,18 @@
                         // this dance is to make sure the data is in the right
                         // place even if we encounter more opaque types while
                         // lowering the bounds
-                        let idx = self.impl_trait_mode.opaque_type_data.alloc(ImplTrait {
-                            bounds: crate::make_single_type_binders(Vec::default()),
-                        });
+                        let idx = self
+                            .impl_trait_mode
+                            .opaque_type_data
+                            .alloc(ImplTrait { predicates: Vec::default() });
+
+                        let impl_trait_id = origin.either(
+                            |f| ImplTraitId::ReturnTypeImplTrait(f, idx),
+                            |a| ImplTraitId::TypeAliasImplTrait(a, idx),
+                        );
+                        let opaque_ty_id: SolverDefId =
+                            self.db.intern_impl_trait_id(impl_trait_id).into();
+
                         // We don't want to lower the bounds inside the binders
                         // we're currently in, because they don't end up inside
                         // those binders. E.g. when we have `impl Trait<impl
@@ -421,27 +492,25 @@
                         // parameter of the outer function, it's just one binder
                         // away instead of two.
                         let actual_opaque_type_data = self
-                            .with_debruijn(DebruijnIndex::INNERMOST, |ctx| {
-                                ctx.lower_impl_trait(bounds, self.resolver.krate())
+                            .with_debruijn(DebruijnIndex::ZERO, |ctx| {
+                                ctx.lower_impl_trait(opaque_ty_id, bounds, self.resolver.krate())
                             });
                         self.impl_trait_mode.opaque_type_data[idx] = actual_opaque_type_data;
 
-                        let impl_trait_id = origin.either(
-                            |f| ImplTraitId::ReturnTypeImplTrait(f, idx),
-                            |a| ImplTraitId::TypeAliasImplTrait(a, idx),
-                        );
-                        let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
-                        let generics = generics(self.db, origin.either(|f| f.into(), |a| a.into()));
-                        let parameters = generics.bound_vars_subst(self.db, self.in_binders);
-                        TyKind::OpaqueType(opaque_ty_id, parameters).intern(Interner)
+                        let args = GenericArgs::identity_for_item(self.interner, opaque_ty_id);
+                        Ty::new_alias(
+                            self.interner,
+                            AliasTyKind::Opaque,
+                            AliasTy::new_from_args(self.interner, opaque_ty_id, args),
+                        )
                     }
                     ImplTraitLoweringMode::Disallowed => {
                         // FIXME: report error
-                        TyKind::Error.intern(Interner)
+                        Ty::new_error(self.interner, ErrorGuaranteed)
                     }
                 }
             }
-            TypeRef::Error => TyKind::Error.intern(Interner),
+            TypeRef::Error => Ty::new_error(self.interner, ErrorGuaranteed),
         };
         (ty, res)
     }
@@ -449,8 +518,8 @@
     /// This is only for `generic_predicates_for_param`, where we can't just
     /// lower the self types of the predicates since that could lead to cycles.
     /// So we just check here if the `type_ref` resolves to a generic param, and which.
-    fn lower_ty_only_param(&mut self, type_ref_id: TypeRefId) -> Option<TypeOrConstParamId> {
-        let type_ref = &self.store[type_ref_id];
+    fn lower_ty_only_param(&self, type_ref: TypeRefId) -> Option<TypeOrConstParamId> {
+        let type_ref = &self.store[type_ref];
         let path = match type_ref {
             TypeRef::Path(path) => path,
             &TypeRef::TypeParam(idx) => return Some(idx.into()),
@@ -462,9 +531,8 @@
         if path.segments().len() > 1 {
             return None;
         }
-        let mut ctx = self.at_path(PathId::from_type_ref_unchecked(type_ref_id));
-        let resolution = match ctx.resolve_path_in_type_ns() {
-            Some((it, None)) => it,
+        let resolution = match self.resolver.resolve_path_in_type_ns(self.db, path) {
+            Some((it, None, _)) => it,
             _ => return None,
         };
         match resolution {
@@ -474,7 +542,7 @@
     }
 
     #[inline]
-    fn on_path_diagnostic_callback<'a>(type_ref: TypeRefId) -> PathDiagnosticCallback<'a, 'db> {
+    fn on_path_diagnostic_callback<'b>(type_ref: TypeRefId) -> PathDiagnosticCallback<'b, 'db> {
         PathDiagnosticCallback {
             data: Either::Left(PathDiagnosticCallbackData(type_ref)),
             callback: |data, this, diag| {
@@ -485,7 +553,7 @@
     }
 
     #[inline]
-    fn at_path(&mut self, path_id: PathId) -> PathLoweringContext<'_, 'db> {
+    fn at_path(&mut self, path_id: PathId) -> PathLoweringContext<'_, 'a, 'db> {
         PathLoweringContext::new(
             self,
             Self::on_path_diagnostic_callback(path_id.type_ref()),
@@ -493,7 +561,7 @@
         )
     }
 
-    pub(crate) fn lower_path(&mut self, path: &Path, path_id: PathId) -> (Ty, Option<TypeNs>) {
+    pub(crate) fn lower_path(&mut self, path: &Path, path_id: PathId) -> (Ty<'db>, Option<TypeNs>) {
         // Resolve the path (in type namespace)
         if let Some(type_ref) = path.type_anchor() {
             let (ty, res) = self.lower_ty_ext(type_ref);
@@ -504,7 +572,7 @@
         let mut ctx = self.at_path(path_id);
         let (resolution, remaining_index) = match ctx.resolve_path_in_type_ns() {
             Some(it) => it,
-            None => return (TyKind::Error.intern(Interner), None),
+            None => return (Ty::new_error(self.interner, ErrorGuaranteed), None),
         };
 
         if matches!(resolution, TypeNs::TraitId(_)) && remaining_index.is_none() {
@@ -520,8 +588,8 @@
     fn lower_trait_ref_from_path(
         &mut self,
         path_id: PathId,
-        explicit_self_ty: Ty,
-    ) -> Option<(TraitRef, PathLoweringContext<'_, 'db>)> {
+        explicit_self_ty: Ty<'db>,
+    ) -> Option<(TraitRef<'db>, PathLoweringContext<'_, 'a, 'db>)> {
         let mut ctx = self.at_path(path_id);
         let resolved = match ctx.resolve_path_in_type_ns_fully()? {
             // FIXME(trait_alias): We need to handle trait alias here.
@@ -531,26 +599,57 @@
         Some((ctx.lower_trait_ref_from_resolved_path(resolved, explicit_self_ty, false), ctx))
     }
 
-    /// When lowering predicates from parents (impl, traits) for children defs (fns, consts, types), `generics` should
-    /// contain the `Generics` for the **child**, while `predicate_owner` should contain the `GenericDefId` of the
-    /// **parent**. This is important so we generate the correct bound var/placeholder.
+    fn lower_trait_ref(
+        &mut self,
+        trait_ref: &HirTraitRef,
+        explicit_self_ty: Ty<'db>,
+    ) -> Option<TraitRef<'db>> {
+        self.lower_trait_ref_from_path(trait_ref.path, explicit_self_ty).map(|it| it.0)
+    }
+
     pub(crate) fn lower_where_predicate<'b>(
         &'b mut self,
         where_predicate: &'b WherePredicate,
         ignore_bindings: bool,
-    ) -> impl Iterator<Item = QuantifiedWhereClause> + use<'db, 'b> {
+        generics: &Generics,
+        predicate_filter: PredicateFilter,
+    ) -> impl Iterator<Item = Clause<'db>> + use<'a, 'b, 'db> {
         match where_predicate {
             WherePredicate::ForLifetime { target, bound, .. }
             | WherePredicate::TypeBound { target, bound } => {
+                if let PredicateFilter::SelfTrait = predicate_filter {
+                    let target_type = &self.store[*target];
+                    let self_type = 'is_self: {
+                        if let TypeRef::Path(path) = target_type
+                            && path.is_self_type()
+                        {
+                            break 'is_self true;
+                        }
+                        if let TypeRef::TypeParam(param) = target_type
+                            && generics[param.local_id()].is_trait_self()
+                        {
+                            break 'is_self true;
+                        }
+                        false
+                    };
+                    if !self_type {
+                        return Either::Left(Either::Left(iter::empty()));
+                    }
+                }
                 let self_ty = self.lower_ty(*target);
-                Either::Left(self.lower_type_bound(bound, self_ty, ignore_bindings))
+                Either::Left(Either::Right(self.lower_type_bound(bound, self_ty, ignore_bindings)))
             }
-            &WherePredicate::Lifetime { bound, target } => Either::Right(iter::once(
-                crate::wrap_empty_binders(WhereClause::LifetimeOutlives(LifetimeOutlives {
-                    a: self.lower_lifetime(bound),
-                    b: self.lower_lifetime(target),
-                })),
-            )),
+            &WherePredicate::Lifetime { bound, target } => {
+                Either::Right(iter::once(Clause(Predicate::new(
+                    self.interner,
+                    Binder::dummy(rustc_type_ir::PredicateKind::Clause(
+                        rustc_type_ir::ClauseKind::RegionOutlives(OutlivesPredicate(
+                            self.lower_lifetime(bound),
+                            self.lower_lifetime(target),
+                        )),
+                    )),
+                ))))
+            }
         }
         .into_iter()
     }
@@ -558,40 +657,40 @@
     pub(crate) fn lower_type_bound<'b>(
         &'b mut self,
         bound: &'b TypeBound,
-        self_ty: Ty,
+        self_ty: Ty<'db>,
         ignore_bindings: bool,
-    ) -> impl Iterator<Item = QuantifiedWhereClause> + use<'b, 'db> {
+    ) -> impl Iterator<Item = Clause<'db>> + use<'b, 'a, 'db> {
+        let interner = self.interner;
         let mut assoc_bounds = None;
         let mut clause = None;
         match bound {
             &TypeBound::Path(path, TraitBoundModifier::None) | &TypeBound::ForLifetime(_, path) => {
                 // FIXME Don't silently drop the hrtb lifetimes here
-                if let Some((trait_ref, mut ctx)) =
-                    self.lower_trait_ref_from_path(path, self_ty.clone())
-                {
+                if let Some((trait_ref, mut ctx)) = self.lower_trait_ref_from_path(path, self_ty) {
                     // FIXME(sized-hierarchy): Remove this bound modifications once we have implemented
                     // sized-hierarchy correctly.
                     let meta_sized = LangItem::MetaSized
                         .resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate());
                     let pointee_sized = LangItem::PointeeSized
                         .resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate());
-                    let destruct = LangItem::Destruct
-                        .resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate());
-                    let hir_trait_id = trait_ref.hir_trait_id();
-                    if meta_sized.is_some_and(|it| it == hir_trait_id)
-                        || destruct.is_some_and(|it| it == hir_trait_id)
-                    {
+                    if meta_sized.is_some_and(|it| it == trait_ref.def_id.0) {
                         // Ignore this bound
-                    } else if pointee_sized.is_some_and(|it| it == hir_trait_id) {
+                    } else if pointee_sized.is_some_and(|it| it == trait_ref.def_id.0) {
                         // Regard this as `?Sized` bound
                         ctx.ty_ctx().unsized_types.insert(self_ty);
                     } else {
                         if !ignore_bindings {
-                            assoc_bounds =
-                                ctx.assoc_type_bindings_from_type_bound(trait_ref.clone());
+                            assoc_bounds = ctx.assoc_type_bindings_from_type_bound(trait_ref);
                         }
-                        clause =
-                            Some(crate::wrap_empty_binders(WhereClause::Implemented(trait_ref)));
+                        clause = Some(Clause(Predicate::new(
+                            interner,
+                            Binder::dummy(rustc_type_ir::PredicateKind::Clause(
+                                rustc_type_ir::ClauseKind::Trait(TraitPredicate {
+                                    trait_ref,
+                                    polarity: rustc_type_ir::PredicatePolarity::Positive,
+                                }),
+                            )),
+                        )));
                     }
                 }
             }
@@ -601,95 +700,137 @@
                 // `?Sized` has no of them.
                 // If we got another trait here ignore the bound completely.
                 let trait_id = self
-                    .lower_trait_ref_from_path(path, self_ty.clone())
-                    .map(|(trait_ref, _)| trait_ref.hir_trait_id());
+                    .lower_trait_ref_from_path(path, self_ty)
+                    .map(|(trait_ref, _)| trait_ref.def_id.0);
                 if trait_id == sized_trait {
                     self.unsized_types.insert(self_ty);
                 }
             }
             &TypeBound::Lifetime(l) => {
                 let lifetime = self.lower_lifetime(l);
-                clause = Some(crate::wrap_empty_binders(WhereClause::TypeOutlives(TypeOutlives {
-                    ty: self_ty,
-                    lifetime,
-                })));
+                clause = Some(Clause(Predicate::new(
+                    self.interner,
+                    Binder::dummy(rustc_type_ir::PredicateKind::Clause(
+                        rustc_type_ir::ClauseKind::TypeOutlives(OutlivesPredicate(
+                            self_ty, lifetime,
+                        )),
+                    )),
+                )));
             }
             TypeBound::Use(_) | TypeBound::Error => {}
         }
         clause.into_iter().chain(assoc_bounds.into_iter().flatten())
     }
 
-    fn lower_dyn_trait(&mut self, bounds: &[TypeBound]) -> Ty {
-        let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
+    fn lower_dyn_trait(&mut self, bounds: &[TypeBound]) -> Ty<'db> {
+        let interner = self.interner;
+        // FIXME: we should never create non-existential predicates in the first place
+        // For now, use an error type so we don't run into dummy binder issues
+        let self_ty = Ty::new_error(interner, ErrorGuaranteed);
         // INVARIANT: The principal trait bound, if present, must come first. Others may be in any
         // order but should be in the same order for the same set but possibly different order of
         // bounds in the input.
         // INVARIANT: If this function returns `DynTy`, there should be at least one trait bound.
         // These invariants are utilized by `TyExt::dyn_trait()` and chalk.
         let mut lifetime = None;
-        let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
-            let mut lowered_bounds = Vec::new();
+        let bounds = self.with_shifted_in(DebruijnIndex::from_u32(1), |ctx| {
+            let mut lowered_bounds: Vec<
+                rustc_type_ir::Binder<DbInterner<'db>, ExistentialPredicate<DbInterner<'db>>>,
+            > = Vec::new();
             for b in bounds {
-                ctx.lower_type_bound(b, self_ty.clone(), false).for_each(|b| {
-                    let filter = match b.skip_binders() {
-                        WhereClause::Implemented(_) | WhereClause::AliasEq(_) => true,
-                        WhereClause::LifetimeOutlives(_) => false,
-                        WhereClause::TypeOutlives(t) => {
-                            lifetime = Some(t.lifetime.clone());
-                            false
-                        }
-                    };
-                    if filter {
-                        lowered_bounds.push(b);
+                let db = ctx.db;
+                ctx.lower_type_bound(b, self_ty, false).for_each(|b| {
+                    if let Some(bound) = b
+                        .kind()
+                        .map_bound(|c| match c {
+                            rustc_type_ir::ClauseKind::Trait(t) => {
+                                let id = t.def_id();
+                                let is_auto =
+                                    db.trait_signature(id.0).flags.contains(TraitFlags::AUTO);
+                                if is_auto {
+                                    Some(ExistentialPredicate::AutoTrait(t.def_id()))
+                                } else {
+                                    Some(ExistentialPredicate::Trait(
+                                        ExistentialTraitRef::new_from_args(
+                                            interner,
+                                            t.def_id(),
+                                            GenericArgs::new_from_iter(
+                                                interner,
+                                                t.trait_ref.args.iter().skip(1),
+                                            ),
+                                        ),
+                                    ))
+                                }
+                            }
+                            rustc_type_ir::ClauseKind::Projection(p) => {
+                                Some(ExistentialPredicate::Projection(
+                                    ExistentialProjection::new_from_args(
+                                        interner,
+                                        p.def_id(),
+                                        GenericArgs::new_from_iter(
+                                            interner,
+                                            p.projection_term.args.iter().skip(1),
+                                        ),
+                                        p.term,
+                                    ),
+                                ))
+                            }
+                            rustc_type_ir::ClauseKind::TypeOutlives(outlives_predicate) => {
+                                lifetime = Some(outlives_predicate.1);
+                                None
+                            }
+                            rustc_type_ir::ClauseKind::RegionOutlives(_)
+                            | rustc_type_ir::ClauseKind::ConstArgHasType(_, _)
+                            | rustc_type_ir::ClauseKind::WellFormed(_)
+                            | rustc_type_ir::ClauseKind::ConstEvaluatable(_)
+                            | rustc_type_ir::ClauseKind::HostEffect(_)
+                            | rustc_type_ir::ClauseKind::UnstableFeature(_) => unreachable!(),
+                        })
+                        .transpose()
+                    {
+                        lowered_bounds.push(bound);
                     }
-                });
+                })
             }
 
             let mut multiple_regular_traits = false;
             let mut multiple_same_projection = false;
             lowered_bounds.sort_unstable_by(|lhs, rhs| {
                 use std::cmp::Ordering;
-                match (lhs.skip_binders(), rhs.skip_binders()) {
-                    (WhereClause::Implemented(lhs), WhereClause::Implemented(rhs)) => {
-                        let lhs_id = lhs.trait_id;
-                        let lhs_is_auto = ctx
-                            .db
-                            .trait_signature(from_chalk_trait_id(lhs_id))
-                            .flags
-                            .contains(TraitFlags::AUTO);
-                        let rhs_id = rhs.trait_id;
-                        let rhs_is_auto = ctx
-                            .db
-                            .trait_signature(from_chalk_trait_id(rhs_id))
-                            .flags
-                            .contains(TraitFlags::AUTO);
-
-                        if !lhs_is_auto && !rhs_is_auto {
-                            multiple_regular_traits = true;
-                        }
-                        // Note that the ordering here is important; this ensures the invariant
-                        // mentioned above.
-                        (lhs_is_auto, lhs_id).cmp(&(rhs_is_auto, rhs_id))
+                match ((*lhs).skip_binder(), (*rhs).skip_binder()) {
+                    (ExistentialPredicate::Trait(_), ExistentialPredicate::Trait(_)) => {
+                        multiple_regular_traits = true;
+                        // Order doesn't matter - we error
+                        Ordering::Equal
                     }
-                    (WhereClause::Implemented(_), _) => Ordering::Less,
-                    (_, WhereClause::Implemented(_)) => Ordering::Greater,
-                    (WhereClause::AliasEq(lhs), WhereClause::AliasEq(rhs)) => {
-                        match (&lhs.alias, &rhs.alias) {
-                            (AliasTy::Projection(lhs_proj), AliasTy::Projection(rhs_proj)) => {
-                                // We only compare the `associated_ty_id`s. We shouldn't have
-                                // multiple bounds for an associated type in the correct Rust code,
-                                // and if we do, we error out.
-                                if lhs_proj.associated_ty_id == rhs_proj.associated_ty_id {
-                                    multiple_same_projection = true;
-                                }
-                                lhs_proj.associated_ty_id.cmp(&rhs_proj.associated_ty_id)
-                            }
-                            // We don't produce `AliasTy::Opaque`s yet.
+                    (
+                        ExistentialPredicate::AutoTrait(lhs_id),
+                        ExistentialPredicate::AutoTrait(rhs_id),
+                    ) => lhs_id.0.cmp(&rhs_id.0),
+                    (ExistentialPredicate::Trait(_), _) => Ordering::Less,
+                    (_, ExistentialPredicate::Trait(_)) => Ordering::Greater,
+                    (ExistentialPredicate::AutoTrait(_), _) => Ordering::Less,
+                    (_, ExistentialPredicate::AutoTrait(_)) => Ordering::Greater,
+                    (
+                        ExistentialPredicate::Projection(lhs),
+                        ExistentialPredicate::Projection(rhs),
+                    ) => {
+                        let lhs_id = match lhs.def_id {
+                            SolverDefId::TypeAliasId(id) => id,
                             _ => unreachable!(),
+                        };
+                        let rhs_id = match rhs.def_id {
+                            SolverDefId::TypeAliasId(id) => id,
+                            _ => unreachable!(),
+                        };
+                        // We only compare the `associated_ty_id`s. We shouldn't have
+                        // multiple bounds for an associated type in the correct Rust code,
+                        // and if we do, we error out.
+                        if lhs_id == rhs_id {
+                            multiple_same_projection = true;
                         }
+                        lhs_id.as_id().index().cmp(&rhs_id.as_id().index())
                     }
-                    // `WhereClause::{TypeOutlives, LifetimeOutlives}` have been filtered out
-                    _ => unreachable!(),
                 }
             });
 
@@ -697,568 +838,195 @@
                 return None;
             }
 
-            lowered_bounds.first().and_then(|b| b.trait_id())?;
+            if !lowered_bounds.first().map_or(false, |b| {
+                matches!(
+                    b.as_ref().skip_binder(),
+                    ExistentialPredicate::Trait(_) | ExistentialPredicate::AutoTrait(_)
+                )
+            }) {
+                return None;
+            }
 
             // As multiple occurrences of the same auto traits *are* permitted, we deduplicate the
             // bounds. We shouldn't have repeated elements besides auto traits at this point.
             lowered_bounds.dedup();
 
-            Some(QuantifiedWhereClauses::from_iter(Interner, lowered_bounds))
+            Some(BoundExistentialPredicates::new_from_iter(interner, lowered_bounds))
         });
 
         if let Some(bounds) = bounds {
-            let bounds = crate::make_single_type_binders(bounds);
-            TyKind::Dyn(DynTy {
-                bounds,
-                lifetime: match lifetime {
-                    Some(it) => match it.bound_var(Interner) {
-                        Some(bound_var) => bound_var
-                            .shifted_out_to(DebruijnIndex::new(2))
-                            .map(|bound_var| LifetimeData::BoundVar(bound_var).intern(Interner))
-                            .unwrap_or(it),
-                        None => it,
-                    },
-                    None => error_lifetime(),
+            let region = match lifetime {
+                Some(it) => match it.kind() {
+                    rustc_type_ir::RegionKind::ReBound(BoundVarIndexKind::Bound(db), var) => {
+                        Region::new_bound(
+                            self.interner,
+                            db.shifted_out_to_binder(DebruijnIndex::from_u32(2)),
+                            var,
+                        )
+                    }
+                    _ => it,
                 },
-            })
-            .intern(Interner)
+                None => Region::new_static(self.interner),
+            };
+            Ty::new_dynamic(self.interner, bounds, region)
         } else {
             // FIXME: report error
             // (additional non-auto traits, associated type rebound, or no resolved trait)
-            TyKind::Error.intern(Interner)
+            Ty::new_error(self.interner, ErrorGuaranteed)
         }
     }
 
-    fn lower_impl_trait(&mut self, bounds: &[TypeBound], krate: Crate) -> ImplTrait {
+    fn lower_impl_trait(
+        &mut self,
+        def_id: SolverDefId,
+        bounds: &[TypeBound],
+        krate: Crate,
+    ) -> ImplTrait<'db> {
+        let interner = self.interner;
         cov_mark::hit!(lower_rpit);
-        let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
-        let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
+        let args = GenericArgs::identity_for_item(interner, def_id);
+        let self_ty = Ty::new_alias(
+            self.interner,
+            rustc_type_ir::AliasTyKind::Opaque,
+            AliasTy::new_from_args(interner, def_id, args),
+        );
+        let predicates = self.with_shifted_in(DebruijnIndex::from_u32(1), |ctx| {
             let mut predicates = Vec::new();
             for b in bounds {
-                predicates.extend(ctx.lower_type_bound(b, self_ty.clone(), false));
+                predicates.extend(ctx.lower_type_bound(b, self_ty, false));
             }
 
             if !ctx.unsized_types.contains(&self_ty) {
-                let sized_trait =
-                    LangItem::Sized.resolve_trait(ctx.db, krate).map(to_chalk_trait_id);
+                let sized_trait = LangItem::Sized.resolve_trait(self.db, krate);
                 let sized_clause = sized_trait.map(|trait_id| {
-                    let clause = WhereClause::Implemented(TraitRef {
-                        trait_id,
-                        substitution: Substitution::from1(Interner, self_ty.clone()),
-                    });
-                    crate::wrap_empty_binders(clause)
+                    let trait_ref = TraitRef::new_from_args(
+                        interner,
+                        trait_id.into(),
+                        GenericArgs::new_from_iter(interner, [self_ty.into()]),
+                    );
+                    Clause(Predicate::new(
+                        interner,
+                        Binder::dummy(rustc_type_ir::PredicateKind::Clause(
+                            rustc_type_ir::ClauseKind::Trait(TraitPredicate {
+                                trait_ref,
+                                polarity: rustc_type_ir::PredicatePolarity::Positive,
+                            }),
+                        )),
+                    ))
                 });
                 predicates.extend(sized_clause);
             }
             predicates.shrink_to_fit();
             predicates
         });
-        ImplTrait { bounds: crate::make_single_type_binders(predicates) }
+        ImplTrait { predicates }
     }
 
-    pub(crate) fn lower_lifetime(&self, lifetime: LifetimeRefId) -> Lifetime {
+    pub(crate) fn lower_lifetime(&mut self, lifetime: LifetimeRefId) -> Region<'db> {
         match self.resolver.resolve_lifetime(&self.store[lifetime]) {
             Some(resolution) => match resolution {
-                LifetimeNs::Static => static_lifetime(),
-                LifetimeNs::LifetimeParam(id) => match self.type_param_mode {
-                    ParamLoweringMode::Placeholder => {
-                        let generics = self.generics();
-                        let idx = generics.lifetime_idx(id).unwrap();
-                        LifetimeData::Placeholder(lt_to_placeholder_idx(self.db, id, idx as u32))
-                    }
-                    ParamLoweringMode::Variable => {
-                        let idx = match self.generics().lifetime_idx(id) {
-                            None => return error_lifetime(),
-                            Some(idx) => idx,
-                        };
-
-                        LifetimeData::BoundVar(BoundVar::new(self.in_binders, idx))
-                    }
+                LifetimeNs::Static => Region::new_static(self.interner),
+                LifetimeNs::LifetimeParam(id) => {
+                    let idx = match self.generics().lifetime_idx(id) {
+                        None => return Region::error(self.interner),
+                        Some(idx) => idx,
+                    };
+                    self.region_param(id, idx as u32)
                 }
-                .intern(Interner),
             },
-            None => error_lifetime(),
+            None => Region::error(self.interner),
         }
     }
 }
 
-fn named_associated_type_shorthand_candidates<R>(
-    db: &dyn HirDatabase,
-    // If the type parameter is defined in an impl and we're in a method, there
-    // might be additional where clauses to consider
-    def: GenericDefId,
-    res: TypeNs,
-    assoc_name: Option<Name>,
-    // Do NOT let `cb` touch `TraitRef` outside of `TyLoweringContext`. Its substitution contains
-    // free `BoundVar`s that need to be shifted and only `TyLoweringContext` knows how to do that
-    // properly (see `TyLoweringContext::select_associated_type()`).
-    mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
-) -> Option<R> {
-    let mut search = |t| {
-        all_super_trait_refs(db, t, |t| {
-            let data = t.hir_trait_id().trait_items(db);
-
-            for (name, assoc_id) in &data.items {
-                if let AssocItemId::TypeAliasId(alias) = assoc_id
-                    && let Some(result) = cb(name, &t, *alias)
-                {
-                    return Some(result);
-                }
-            }
-            None
-        })
-    };
-
-    let interner = DbInterner::new_with(db, None, None);
-    match res {
-        TypeNs::SelfType(impl_id) => {
-            let trait_ref = db.impl_trait(impl_id)?;
-
-            let impl_id_as_generic_def: GenericDefId = impl_id.into();
-            if impl_id_as_generic_def != def {
-                let subst = TyBuilder::subst_for_def(db, impl_id, None)
-                    .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
-                    .build();
-                let args: crate::next_solver::GenericArgs<'_> = subst.to_nextsolver(interner);
-                let trait_ref = trait_ref.instantiate(interner, args).to_chalk(interner);
-                search(trait_ref)
-            } else {
-                search(trait_ref.skip_binder().to_chalk(interner))
-            }
-        }
-        TypeNs::GenericParam(param_id) => {
-            let predicates = db.generic_predicates_for_param(def, param_id.into(), assoc_name);
-            let res = predicates.iter().find_map(|pred| match pred.skip_binders().skip_binders() {
-                // FIXME: how to correctly handle higher-ranked bounds here?
-                WhereClause::Implemented(tr) => search(
-                    tr.clone()
-                        .shifted_out_to(Interner, DebruijnIndex::ONE)
-                        .expect("FIXME unexpected higher-ranked trait bound"),
-                ),
-                _ => None,
-            });
-            if res.is_some() {
-                return res;
-            }
-            // 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, trait_id.into());
-                if trait_generics[param_id.local_id()].is_trait_self() {
-                    let trait_ref = TyBuilder::trait_ref(db, trait_id)
-                        .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
-                        .build();
-                    return search(trait_ref);
-                }
-            }
-            None
-        }
-        _ => None,
+pub(crate) fn lower_mutability(m: hir_def::type_ref::Mutability) -> Mutability {
+    match m {
+        hir_def::type_ref::Mutability::Shared => Mutability::Not,
+        hir_def::type_ref::Mutability::Mut => Mutability::Mut,
     }
 }
 
+fn unknown_const(_ty: Ty<'_>) -> Const<'_> {
+    Const::new(DbInterner::conjure(), ConstKind::Error(ErrorGuaranteed))
+}
+
 pub(crate) type Diagnostics = Option<ThinArc<(), TyLoweringDiagnostic>>;
 
 pub(crate) fn create_diagnostics(diagnostics: Vec<TyLoweringDiagnostic>) -> Diagnostics {
     (!diagnostics.is_empty()).then(|| ThinArc::from_header_and_iter((), diagnostics.into_iter()))
 }
 
-pub(crate) fn field_types_query(
-    db: &dyn HirDatabase,
-    variant_id: VariantId,
-) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>> {
-    field_types_with_diagnostics_query(db, variant_id).0
-}
-
-/// Build the type of all specific fields of a struct or enum variant.
-pub(crate) fn field_types_with_diagnostics_query(
-    db: &dyn HirDatabase,
-    variant_id: VariantId,
-) -> (Arc<ArenaMap<LocalFieldId, Binders<Ty>>>, Diagnostics) {
-    let var_data = variant_id.fields(db);
-    let fields = var_data.fields();
-    if fields.is_empty() {
-        return (Arc::new(ArenaMap::default()), None);
-    }
-
-    let (resolver, def): (_, GenericDefId) = match variant_id {
-        VariantId::StructId(it) => (it.resolver(db), it.into()),
-        VariantId::UnionId(it) => (it.resolver(db), it.into()),
-        VariantId::EnumVariantId(it) => (it.resolver(db), it.lookup(db).parent.into()),
-    };
-    let generics = generics(db, def);
-    let mut res = ArenaMap::default();
-    let mut ctx = TyLoweringContext::new(
-        db,
-        &resolver,
-        &var_data.store,
-        def,
-        LifetimeElisionKind::AnonymousReportError,
-    )
-    .with_type_param_mode(ParamLoweringMode::Variable);
-    for (field_id, field_data) in fields.iter() {
-        res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(field_data.type_ref)));
-    }
-    (Arc::new(res), create_diagnostics(ctx.diagnostics))
-}
-
-/// This query exists only to be used when resolving short-hand associated types
-/// like `T::Item`.
-///
-/// See the analogous query in rustc and its comment:
-/// <https://github.com/rust-lang/rust/blob/9150f844e2624eb013ec78ca08c1d416e6644026/src/librustc_typeck/astconv.rs#L46>
-/// This is a query mostly to handle cycles somewhat gracefully; e.g. the
-/// following bounds are disallowed: `T: Foo<U::Item>, U: Foo<T::Item>`, but
-/// these are fine: `T: Foo<U::Item>, U: Foo<()>`.
-pub(crate) fn generic_predicates_for_param_query(
-    db: &dyn HirDatabase,
-    def: GenericDefId,
-    param_id: TypeOrConstParamId,
-    assoc_name: Option<Name>,
-) -> GenericPredicates {
-    let generics = generics(db, def);
-    if generics.has_no_predicates() && generics.is_empty() {
-        return GenericPredicates(None);
-    }
-
-    let resolver = def.resolver(db);
-    let mut ctx = TyLoweringContext::new(
-        db,
-        &resolver,
-        generics.store(),
-        def,
-        LifetimeElisionKind::AnonymousReportError,
-    )
-    .with_type_param_mode(ParamLoweringMode::Variable);
-
-    // we have to filter out all other predicates *first*, before attempting to lower them
-    let predicate = |pred: &_, ctx: &mut TyLoweringContext<'_>| match pred {
-        WherePredicate::ForLifetime { target, bound, .. }
-        | WherePredicate::TypeBound { target, bound, .. } => {
-            let invalid_target = { ctx.lower_ty_only_param(*target) != Some(param_id) };
-            if invalid_target {
-                // FIXME(sized-hierarchy): Revisit and adjust this properly once we have implemented
-                // sized-hierarchy correctly.
-                // If this is filtered out without lowering, `?Sized` or `PointeeSized` is not gathered into
-                // `ctx.unsized_types`
-                let lower = || -> bool {
-                    match bound {
-                        TypeBound::Path(_, TraitBoundModifier::Maybe) => true,
-                        TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
-                            let TypeRef::Path(path) = &ctx.store[path.type_ref()] else {
-                                return false;
-                            };
-                            let Some(pointee_sized) =
-                                LangItem::PointeeSized.resolve_trait(ctx.db, ctx.resolver.krate())
-                            else {
-                                return false;
-                            };
-                            // Lower the path directly with `Resolver` instead of PathLoweringContext`
-                            // to prevent diagnostics duplications.
-                            ctx.resolver.resolve_path_in_type_ns_fully(ctx.db, path).is_some_and(
-                                |it| matches!(it, TypeNs::TraitId(tr) if tr == pointee_sized),
-                            )
-                        }
-                        _ => false,
-                    }
-                }();
-                if lower {
-                    ctx.lower_where_predicate(pred, true).for_each(drop);
-                }
-                return false;
-            }
-
-            match bound {
-                &TypeBound::ForLifetime(_, path) | &TypeBound::Path(path, _) => {
-                    // Only lower the bound if the trait could possibly define the associated
-                    // type we're looking for.
-                    let path = &ctx.store[path];
-
-                    let Some(assoc_name) = &assoc_name else { return true };
-                    let Some(TypeNs::TraitId(tr)) =
-                        resolver.resolve_path_in_type_ns_fully(db, path)
-                    else {
-                        return false;
-                    };
-
-                    all_super_traits(db, tr).iter().any(|tr| {
-                        tr.trait_items(db).items.iter().any(|(name, item)| {
-                            matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name
-                        })
-                    })
-                }
-                TypeBound::Use(_) | TypeBound::Lifetime(_) | TypeBound::Error => false,
-            }
-        }
-        WherePredicate::Lifetime { .. } => false,
-    };
-    let mut predicates = Vec::new();
-    for maybe_parent_generics in
-        std::iter::successors(Some(&generics), |generics| generics.parent_generics())
-    {
-        ctx.store = maybe_parent_generics.store();
-        for pred in maybe_parent_generics.where_predicates() {
-            if predicate(pred, &mut ctx) {
-                predicates.extend(
-                    ctx.lower_where_predicate(pred, true).map(|p| make_binders(db, &generics, p)),
-                );
-            }
-        }
-    }
-
-    let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
-    if !subst.is_empty(Interner) {
-        let explicitly_unsized_tys = ctx.unsized_types;
-        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()))
-}
-
-pub(crate) fn generic_predicates_for_param_cycle_result(
-    _db: &dyn HirDatabase,
-    _def: GenericDefId,
-    _param_id: TypeOrConstParamId,
-    _assoc_name: Option<Name>,
-) -> GenericPredicates {
-    GenericPredicates(None)
-}
-
-#[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 {
-    generic_predicates_filtered_by(db, def, |_, _| true).0
-}
-
-/// Resolve the where clause(s) of an item with generics,
-/// with a given filter
-fn generic_predicates_filtered_by<F>(
-    db: &dyn HirDatabase,
-    def: GenericDefId,
-    filter: F,
-) -> (GenericPredicates, Diagnostics)
-where
-    F: Fn(&WherePredicate, GenericDefId) -> bool,
-{
-    let generics = generics(db, def);
-    if generics.has_no_predicates() && generics.is_empty() {
-        return (GenericPredicates(None), None);
-    }
-
-    let resolver = def.resolver(db);
-    let mut ctx = TyLoweringContext::new(
-        db,
-        &resolver,
-        generics.store(),
-        def,
-        LifetimeElisionKind::AnonymousReportError,
-    )
-    .with_type_param_mode(ParamLoweringMode::Variable);
-
-    let mut predicates = Vec::new();
-    for maybe_parent_generics in
-        std::iter::successors(Some(&generics), |generics| generics.parent_generics())
-    {
-        ctx.store = maybe_parent_generics.store();
-        for pred in maybe_parent_generics.where_predicates() {
-            if filter(pred, maybe_parent_generics.def()) {
-                // We deliberately use `generics` and not `maybe_parent_generics` here. This is not a mistake!
-                // If we use the parent generics
-                predicates.extend(
-                    ctx.lower_where_predicate(pred, false).map(|p| make_binders(db, &generics, p)),
-                );
-            }
-        }
-    }
-
-    if !generics.is_empty() {
-        let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
-        let explicitly_unsized_tys = ctx.unsized_types;
-        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())),
-        create_diagnostics(ctx.diagnostics),
-    )
-}
-
-/// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound.
-/// Exception is Self of a trait def.
-fn implicitly_sized_clauses<'db, 'a, 'subst: 'a>(
+pub(crate) fn impl_trait_query<'db>(
     db: &'db dyn HirDatabase,
-    def: GenericDefId,
-    explicitly_unsized_tys: &'a FxHashSet<Ty>,
-    substitution: &'subst Substitution,
-    resolver: &Resolver<'db>,
-) -> Option<impl Iterator<Item = WhereClause>> {
-    let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate()).map(to_chalk_trait_id)?;
-
-    let trait_self_idx = trait_self_param_idx(db, def);
-
-    Some(
-        substitution
-            .iter(Interner)
-            .enumerate()
-            .filter_map(
-                move |(idx, generic_arg)| {
-                    if Some(idx) == trait_self_idx { None } else { Some(generic_arg) }
-                },
-            )
-            .filter_map(|generic_arg| generic_arg.ty(Interner))
-            .filter(move |&self_ty| !explicitly_unsized_tys.contains(self_ty))
-            .map(move |self_ty| {
-                WhereClause::Implemented(TraitRef {
-                    trait_id: sized_trait,
-                    substitution: Substitution::from1(Interner, self_ty.clone()),
-                })
-            }),
-    )
+    impl_id: ImplId,
+) -> Option<EarlyBinder<'db, TraitRef<'db>>> {
+    db.impl_trait_with_diagnostics(impl_id).map(|it| it.0)
 }
 
-#[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(&[])
-    }
-}
-
-pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) -> GenericDefaults {
-    db.generic_defaults_with_diagnostics(def).0
-}
-
-/// Resolve the default type params from generics.
-///
-/// Diagnostics are only returned for this `GenericDefId` (returned defaults include parents).
-pub(crate) fn generic_defaults_with_diagnostics_query(
-    db: &dyn HirDatabase,
-    def: GenericDefId,
-) -> (GenericDefaults, Diagnostics) {
-    let generic_params = generics(db, def);
-    if generic_params.is_empty() {
-        return (GenericDefaults(None), None);
-    }
-    let resolver = def.resolver(db);
-
+pub(crate) fn impl_trait_with_diagnostics_query<'db>(
+    db: &'db dyn HirDatabase,
+    impl_id: ImplId,
+) -> Option<(EarlyBinder<'db, TraitRef<'db>>, Diagnostics)> {
+    let impl_data = db.impl_signature(impl_id);
+    let resolver = impl_id.resolver(db);
     let mut ctx = TyLoweringContext::new(
         db,
         &resolver,
-        generic_params.store(),
-        def,
-        LifetimeElisionKind::AnonymousReportError,
-    )
-    .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed)
-    .with_type_param_mode(ParamLoweringMode::Variable);
-    let mut idx = 0;
-    let mut has_any_default = false;
-    let mut defaults = generic_params
-        .iter_parents_with_store()
-        .map(|((id, p), store)| {
-            ctx.store = store;
-            let (result, has_default) = handle_generic_param(&mut ctx, idx, id, p, &generic_params);
-            has_any_default |= has_default;
-            idx += 1;
-            result
-        })
-        .collect::<Vec<_>>();
-    ctx.diagnostics.clear(); // Don't include diagnostics from the parent.
-    defaults.extend(generic_params.iter_self().map(|(id, p)| {
-        let (result, has_default) = handle_generic_param(&mut ctx, idx, id, p, &generic_params);
-        has_any_default |= has_default;
-        idx += 1;
-        result
-    }));
-    let diagnostics = create_diagnostics(mem::take(&mut ctx.diagnostics));
-    let defaults = if has_any_default {
-        GenericDefaults(Some(Arc::from_iter(defaults)))
+        &impl_data.store,
+        impl_id.into(),
+        LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true },
+    );
+    let self_ty = db.impl_self_ty(impl_id).skip_binder();
+    let target_trait = impl_data.target_trait.as_ref()?;
+    let trait_ref = EarlyBinder::bind(ctx.lower_trait_ref(target_trait, self_ty)?);
+    Some((trait_ref, create_diagnostics(ctx.diagnostics)))
+}
+
+pub(crate) fn return_type_impl_traits<'db>(
+    db: &'db dyn HirDatabase,
+    def: hir_def::FunctionId,
+) -> Option<Arc<EarlyBinder<'db, ImplTraits<'db>>>> {
+    // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe
+    let data = db.function_signature(def);
+    let resolver = def.resolver(db);
+    let mut ctx_ret =
+        TyLoweringContext::new(db, &resolver, &data.store, def.into(), LifetimeElisionKind::Infer)
+            .with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
+    if let Some(ret_type) = data.ret_type {
+        let _ret = ctx_ret.lower_ty(ret_type);
+    }
+    let return_type_impl_traits =
+        ImplTraits { impl_traits: ctx_ret.impl_trait_mode.opaque_type_data };
+    if return_type_impl_traits.impl_traits.is_empty() {
+        None
     } else {
-        GenericDefaults(None)
-    };
-    return (defaults, diagnostics);
-
-    fn handle_generic_param(
-        ctx: &mut TyLoweringContext<'_>,
-        idx: usize,
-        id: GenericParamId,
-        p: GenericParamDataRef<'_>,
-        generic_params: &Generics,
-    ) -> (Binders<crate::GenericArg>, bool) {
-        let binders = variable_kinds_from_iter(ctx.db, generic_params.iter_id().take(idx));
-        match p {
-            GenericParamDataRef::TypeParamData(p) => {
-                let ty = p.default.as_ref().map_or_else(
-                    || 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)
-                    },
-                );
-                (Binders::new(binders, ty.cast(Interner)), p.default.is_some())
-            }
-            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(ctx.db.const_param_ty(id)),
-                    |c| {
-                        let param_ty = ctx.lower_ty(p.ty);
-                        let c = ctx.lower_const(c, param_ty);
-                        c.cast(Interner)
-                    },
-                );
-                // Each default can only refer to previous parameters, see above.
-                val = fallback_bound_vars(val, idx);
-                (Binders::new(binders, val), p.default.is_some())
-            }
-            GenericParamDataRef::LifetimeParamData(_) => {
-                (Binders::new(binders, error_lifetime().cast(Interner)), false)
-            }
-        }
+        Some(Arc::new(EarlyBinder::bind(return_type_impl_traits)))
     }
 }
 
-pub(crate) fn generic_defaults_with_diagnostics_cycle_result(
-    _db: &dyn HirDatabase,
-    _def: GenericDefId,
-) -> (GenericDefaults, Diagnostics) {
-    (GenericDefaults(None), None)
+pub(crate) fn type_alias_impl_traits<'db>(
+    db: &'db dyn HirDatabase,
+    def: hir_def::TypeAliasId,
+) -> Option<Arc<EarlyBinder<'db, ImplTraits<'db>>>> {
+    let data = db.type_alias_signature(def);
+    let resolver = def.resolver(db);
+    let mut ctx = TyLoweringContext::new(
+        db,
+        &resolver,
+        &data.store,
+        def.into(),
+        LifetimeElisionKind::AnonymousReportError,
+    )
+    .with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
+    if let Some(type_ref) = data.ty {
+        let _ty = ctx.lower_ty(type_ref);
+    }
+    let type_alias_impl_traits = ImplTraits { impl_traits: ctx.impl_trait_mode.opaque_type_data };
+    if type_alias_impl_traits.impl_traits.is_empty() {
+        None
+    } else {
+        Some(Arc::new(EarlyBinder::bind(type_alias_impl_traits)))
+    }
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -1293,18 +1061,203 @@
     }
 }
 
-pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty {
-    const_param_ty_with_diagnostics_query(db, def).0
+/// Build the declared type of an item. This depends on the namespace; e.g. for
+/// `struct Foo(usize)`, we have two types: The type of the struct itself, and
+/// the constructor function `(usize) -> Foo` which lives in the values
+/// namespace.
+pub(crate) fn ty_query<'db>(db: &'db dyn HirDatabase, def: TyDefId) -> EarlyBinder<'db, Ty<'db>> {
+    let interner = DbInterner::new_with(db, None, None);
+    match def {
+        TyDefId::BuiltinType(it) => EarlyBinder::bind(Ty::from_builtin_type(interner, it)),
+        TyDefId::AdtId(it) => EarlyBinder::bind(Ty::new_adt(
+            interner,
+            it,
+            GenericArgs::identity_for_item(interner, it.into()),
+        )),
+        TyDefId::TypeAliasId(it) => db.type_for_type_alias_with_diagnostics(it).0,
+    }
+}
+
+/// Build the declared type of a function. This should not need to look at the
+/// function body.
+fn type_for_fn<'db>(db: &'db dyn HirDatabase, def: FunctionId) -> EarlyBinder<'db, Ty<'db>> {
+    let interner = DbInterner::new_with(db, None, None);
+    EarlyBinder::bind(Ty::new_fn_def(
+        interner,
+        CallableDefId::FunctionId(def).into(),
+        GenericArgs::identity_for_item(interner, def.into()),
+    ))
+}
+
+/// Build the declared type of a const.
+fn type_for_const<'db>(db: &'db dyn HirDatabase, def: ConstId) -> EarlyBinder<'db, Ty<'db>> {
+    let resolver = def.resolver(db);
+    let data = db.const_signature(def);
+    let parent = def.loc(db).container;
+    let mut ctx = TyLoweringContext::new(
+        db,
+        &resolver,
+        &data.store,
+        def.into(),
+        LifetimeElisionKind::AnonymousReportError,
+    );
+    ctx.set_lifetime_elision(LifetimeElisionKind::for_const(ctx.interner, parent));
+    EarlyBinder::bind(ctx.lower_ty(data.type_ref))
+}
+
+/// Build the declared type of a static.
+fn type_for_static<'db>(db: &'db dyn HirDatabase, def: StaticId) -> EarlyBinder<'db, Ty<'db>> {
+    let resolver = def.resolver(db);
+    let data = db.static_signature(def);
+    let mut ctx = TyLoweringContext::new(
+        db,
+        &resolver,
+        &data.store,
+        def.into(),
+        LifetimeElisionKind::AnonymousReportError,
+    );
+    ctx.set_lifetime_elision(LifetimeElisionKind::Elided(Region::new_static(ctx.interner)));
+    EarlyBinder::bind(ctx.lower_ty(data.type_ref))
+}
+
+/// Build the type of a tuple struct constructor.
+fn type_for_struct_constructor<'db>(
+    db: &'db dyn HirDatabase,
+    def: StructId,
+) -> Option<EarlyBinder<'db, Ty<'db>>> {
+    let struct_data = def.fields(db);
+    match struct_data.shape {
+        FieldsShape::Record => None,
+        FieldsShape::Unit => Some(type_for_adt(db, def.into())),
+        FieldsShape::Tuple => {
+            let interner = DbInterner::new_with(db, None, None);
+            Some(EarlyBinder::bind(Ty::new_fn_def(
+                interner,
+                CallableDefId::StructId(def).into(),
+                GenericArgs::identity_for_item(interner, def.into()),
+            )))
+        }
+    }
+}
+
+/// Build the type of a tuple enum variant constructor.
+fn type_for_enum_variant_constructor<'db>(
+    db: &'db dyn HirDatabase,
+    def: EnumVariantId,
+) -> Option<EarlyBinder<'db, Ty<'db>>> {
+    let struct_data = def.fields(db);
+    match struct_data.shape {
+        FieldsShape::Record => None,
+        FieldsShape::Unit => Some(type_for_adt(db, def.loc(db).parent.into())),
+        FieldsShape::Tuple => {
+            let interner = DbInterner::new_with(db, None, None);
+            Some(EarlyBinder::bind(Ty::new_fn_def(
+                interner,
+                CallableDefId::EnumVariantId(def).into(),
+                GenericArgs::identity_for_item(interner, def.loc(db).parent.into()),
+            )))
+        }
+    }
+}
+
+pub(crate) fn value_ty_query<'db>(
+    db: &'db dyn HirDatabase,
+    def: ValueTyDefId,
+) -> Option<EarlyBinder<'db, Ty<'db>>> {
+    match def {
+        ValueTyDefId::FunctionId(it) => Some(type_for_fn(db, it)),
+        ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it),
+        ValueTyDefId::UnionId(it) => Some(type_for_adt(db, it.into())),
+        ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it),
+        ValueTyDefId::ConstId(it) => Some(type_for_const(db, it)),
+        ValueTyDefId::StaticId(it) => Some(type_for_static(db, it)),
+    }
+}
+
+pub(crate) fn type_for_type_alias_with_diagnostics_query<'db>(
+    db: &'db dyn HirDatabase,
+    t: TypeAliasId,
+) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) {
+    let type_alias_data = db.type_alias_signature(t);
+    let mut diags = None;
+    let resolver = t.resolver(db);
+    let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
+    let inner = if type_alias_data.flags.contains(TypeAliasFlags::IS_EXTERN) {
+        EarlyBinder::bind(Ty::new_foreign(interner, t.into()))
+    } else {
+        let mut ctx = TyLoweringContext::new(
+            db,
+            &resolver,
+            &type_alias_data.store,
+            t.into(),
+            LifetimeElisionKind::AnonymousReportError,
+        )
+        .with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
+        let res = EarlyBinder::bind(
+            type_alias_data
+                .ty
+                .map(|type_ref| ctx.lower_ty(type_ref))
+                .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed)),
+        );
+        diags = create_diagnostics(ctx.diagnostics);
+        res
+    };
+    (inner, diags)
+}
+
+pub(crate) fn type_for_type_alias_with_diagnostics_cycle_result<'db>(
+    db: &'db dyn HirDatabase,
+    _adt: TypeAliasId,
+) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) {
+    (EarlyBinder::bind(Ty::new_error(DbInterner::new_with(db, None, None), ErrorGuaranteed)), None)
+}
+
+pub(crate) fn impl_self_ty_query<'db>(
+    db: &'db dyn HirDatabase,
+    impl_id: ImplId,
+) -> EarlyBinder<'db, Ty<'db>> {
+    db.impl_self_ty_with_diagnostics(impl_id).0
+}
+
+pub(crate) fn impl_self_ty_with_diagnostics_query<'db>(
+    db: &'db dyn HirDatabase,
+    impl_id: ImplId,
+) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) {
+    let resolver = impl_id.resolver(db);
+
+    let impl_data = db.impl_signature(impl_id);
+    let mut ctx = TyLoweringContext::new(
+        db,
+        &resolver,
+        &impl_data.store,
+        impl_id.into(),
+        LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true },
+    );
+    let ty = ctx.lower_ty(impl_data.self_ty);
+    assert!(!ty.has_escaping_bound_vars());
+    (EarlyBinder::bind(ty), create_diagnostics(ctx.diagnostics))
+}
+
+pub(crate) fn impl_self_ty_with_diagnostics_cycle_result(
+    db: &dyn HirDatabase,
+    _impl_id: ImplId,
+) -> (EarlyBinder<'_, Ty<'_>>, Diagnostics) {
+    (EarlyBinder::bind(Ty::new_error(DbInterner::new_with(db, None, None), ErrorGuaranteed)), None)
+}
+
+pub(crate) fn const_param_ty_query<'db>(db: &'db dyn HirDatabase, def: ConstParamId) -> Ty<'db> {
+    db.const_param_ty_with_diagnostics(def).0
 }
 
 // returns None if def is a type arg
-pub(crate) fn const_param_ty_with_diagnostics_query(
-    db: &dyn HirDatabase,
+pub(crate) fn const_param_ty_with_diagnostics_query<'db>(
+    db: &'db dyn HirDatabase,
     def: ConstParamId,
-) -> (Ty, Diagnostics) {
+) -> (Ty<'db>, Diagnostics) {
     let (parent_data, store) = db.generic_params_and_store(def.parent());
     let data = &parent_data[def.local_id()];
     let resolver = def.parent().resolver(db);
+    let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
     let mut ctx = TyLoweringContext::new(
         db,
         &resolver,
@@ -1315,103 +1268,912 @@
     let ty = match data {
         TypeOrConstParamData::TypeParamData(_) => {
             never!();
-            Ty::new(Interner, TyKind::Error)
+            Ty::new_error(interner, ErrorGuaranteed)
         }
         TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(d.ty),
     };
     (ty, create_diagnostics(ctx.diagnostics))
 }
 
-pub(crate) fn const_param_ty_cycle_result(
-    _: &dyn HirDatabase,
+pub(crate) fn const_param_ty_with_diagnostics_cycle_result<'db>(
+    db: &'db dyn HirDatabase,
     _: crate::db::HirDatabaseData,
-    _: ConstParamId,
-) -> Ty {
-    TyKind::Error.intern(Interner)
+    def: ConstParamId,
+) -> (Ty<'db>, Diagnostics) {
+    let resolver = def.parent().resolver(db);
+    let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
+    (Ty::new_error(interner, ErrorGuaranteed), None)
 }
 
-pub(crate) fn return_type_impl_traits(
-    db: &dyn HirDatabase,
-    def: hir_def::FunctionId,
-) -> Option<Arc<Binders<ImplTraits>>> {
-    // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe
-    let data = db.function_signature(def);
-    let resolver = def.resolver(db);
-    let mut ctx_ret =
-        TyLoweringContext::new(db, &resolver, &data.store, def.into(), LifetimeElisionKind::Infer)
-            .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
-            .with_type_param_mode(ParamLoweringMode::Variable);
-    if let Some(ret_type) = data.ret_type {
-        let _ret = ctx_ret.lower_ty(ret_type);
-    }
-    let generics = generics(db, def.into());
-    let return_type_impl_traits =
-        ImplTraits { impl_traits: ctx_ret.impl_trait_mode.opaque_type_data };
-    if return_type_impl_traits.impl_traits.is_empty() {
-        None
-    } else {
-        Some(Arc::new(make_binders(db, &generics, return_type_impl_traits)))
-    }
+pub(crate) fn field_types_query<'db>(
+    db: &'db dyn HirDatabase,
+    variant_id: VariantId,
+) -> Arc<ArenaMap<LocalFieldId, EarlyBinder<'db, Ty<'db>>>> {
+    db.field_types_with_diagnostics(variant_id).0
 }
 
-pub(crate) fn type_alias_impl_traits(
-    db: &dyn HirDatabase,
-    def: hir_def::TypeAliasId,
-) -> Option<Arc<Binders<ImplTraits>>> {
-    let data = db.type_alias_signature(def);
+/// Build the type of all specific fields of a struct or enum variant.
+pub(crate) fn field_types_with_diagnostics_query<'db>(
+    db: &'db dyn HirDatabase,
+    variant_id: VariantId,
+) -> (Arc<ArenaMap<LocalFieldId, EarlyBinder<'db, Ty<'db>>>>, Diagnostics) {
+    let var_data = variant_id.fields(db);
+    let fields = var_data.fields();
+    if fields.is_empty() {
+        return (Arc::new(ArenaMap::default()), None);
+    }
+
+    let (resolver, def): (_, GenericDefId) = match variant_id {
+        VariantId::StructId(it) => (it.resolver(db), it.into()),
+        VariantId::UnionId(it) => (it.resolver(db), it.into()),
+        VariantId::EnumVariantId(it) => (it.resolver(db), it.lookup(db).parent.into()),
+    };
+    let mut res = ArenaMap::default();
+    let mut ctx = TyLoweringContext::new(
+        db,
+        &resolver,
+        &var_data.store,
+        def,
+        LifetimeElisionKind::AnonymousReportError,
+    );
+    for (field_id, field_data) in var_data.fields().iter() {
+        res.insert(field_id, EarlyBinder::bind(ctx.lower_ty(field_data.type_ref)));
+    }
+    (Arc::new(res), create_diagnostics(ctx.diagnostics))
+}
+
+/// This query exists only to be used when resolving short-hand associated types
+/// like `T::Item`.
+///
+/// See the analogous query in rustc and its comment:
+/// <https://github.com/rust-lang/rust/blob/9150f844e2624eb013ec78ca08c1d416e6644026/src/librustc_typeck/astconv.rs#L46>
+/// This is a query mostly to handle cycles somewhat gracefully; e.g. the
+/// following bounds are disallowed: `T: Foo<U::Item>, U: Foo<T::Item>`, but
+/// these are fine: `T: Foo<U::Item>, U: Foo<()>`.
+#[tracing::instrument(skip(db), ret)]
+pub(crate) fn generic_predicates_for_param_query<'db>(
+    db: &'db dyn HirDatabase,
+    def: GenericDefId,
+    param_id: TypeOrConstParamId,
+    assoc_name: Option<Name>,
+) -> GenericPredicates<'db> {
+    let generics = generics(db, def);
+    let interner = DbInterner::new_with(db, None, None);
     let resolver = def.resolver(db);
     let mut ctx = TyLoweringContext::new(
         db,
         &resolver,
-        &data.store,
-        def.into(),
+        generics.store(),
+        def,
+        LifetimeElisionKind::AnonymousReportError,
+    );
+
+    // we have to filter out all other predicates *first*, before attempting to lower them
+    let predicate = |pred: &_, ctx: &mut TyLoweringContext<'_, '_>| match pred {
+        WherePredicate::ForLifetime { target, bound, .. }
+        | WherePredicate::TypeBound { target, bound, .. } => {
+            let invalid_target = { ctx.lower_ty_only_param(*target) != Some(param_id) };
+            if invalid_target {
+                // FIXME(sized-hierarchy): Revisit and adjust this properly once we have implemented
+                // sized-hierarchy correctly.
+                // If this is filtered out without lowering, `?Sized` or `PointeeSized` is not gathered into
+                // `ctx.unsized_types`
+                let lower = || -> bool {
+                    match bound {
+                        TypeBound::Path(_, TraitBoundModifier::Maybe) => true,
+                        TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
+                            let TypeRef::Path(path) = &ctx.store[path.type_ref()] else {
+                                return false;
+                            };
+                            let Some(pointee_sized) =
+                                LangItem::PointeeSized.resolve_trait(ctx.db, ctx.resolver.krate())
+                            else {
+                                return false;
+                            };
+                            // Lower the path directly with `Resolver` instead of PathLoweringContext`
+                            // to prevent diagnostics duplications.
+                            ctx.resolver.resolve_path_in_type_ns_fully(ctx.db, path).is_some_and(
+                                |it| matches!(it, TypeNs::TraitId(tr) if tr == pointee_sized),
+                            )
+                        }
+                        _ => false,
+                    }
+                }();
+                if lower {
+                    ctx.lower_where_predicate(pred, true, &generics, PredicateFilter::All)
+                        .for_each(drop);
+                }
+                return false;
+            }
+
+            match bound {
+                &TypeBound::ForLifetime(_, path) | &TypeBound::Path(path, _) => {
+                    // Only lower the bound if the trait could possibly define the associated
+                    // type we're looking for.
+                    let path = &ctx.store[path];
+
+                    let Some(assoc_name) = &assoc_name else { return true };
+                    let Some(TypeNs::TraitId(tr)) =
+                        resolver.resolve_path_in_type_ns_fully(db, path)
+                    else {
+                        return false;
+                    };
+
+                    rustc_type_ir::elaborate::supertrait_def_ids(interner, tr.into()).any(|tr| {
+                        tr.0.trait_items(db).items.iter().any(|(name, item)| {
+                            matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name
+                        })
+                    })
+                }
+                TypeBound::Use(_) | TypeBound::Lifetime(_) | TypeBound::Error => false,
+            }
+        }
+        WherePredicate::Lifetime { .. } => false,
+    };
+    let mut predicates = Vec::new();
+    for maybe_parent_generics in
+        std::iter::successors(Some(&generics), |generics| generics.parent_generics())
+    {
+        ctx.store = maybe_parent_generics.store();
+        for pred in maybe_parent_generics.where_predicates() {
+            if predicate(pred, &mut ctx) {
+                predicates.extend(ctx.lower_where_predicate(
+                    pred,
+                    true,
+                    maybe_parent_generics,
+                    PredicateFilter::All,
+                ));
+            }
+        }
+    }
+
+    let args = GenericArgs::identity_for_item(interner, def.into());
+    if !args.is_empty() {
+        let explicitly_unsized_tys = ctx.unsized_types;
+        if let Some(implicitly_sized_predicates) =
+            implicitly_sized_clauses(db, param_id.parent, &explicitly_unsized_tys, &args, &resolver)
+        {
+            predicates.extend(implicitly_sized_predicates);
+        };
+    }
+    GenericPredicates(predicates.is_empty().not().then(|| predicates.into()))
+}
+
+pub(crate) fn generic_predicates_for_param_cycle_result(
+    _db: &dyn HirDatabase,
+    _def: GenericDefId,
+    _param_id: TypeOrConstParamId,
+    _assoc_name: Option<Name>,
+) -> GenericPredicates<'_> {
+    GenericPredicates(None)
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct GenericPredicates<'db>(Option<Arc<[Clause<'db>]>>);
+
+impl<'db> GenericPredicates<'db> {
+    #[inline]
+    pub fn instantiate(
+        &self,
+        interner: DbInterner<'db>,
+        args: GenericArgs<'db>,
+    ) -> Option<impl Iterator<Item = Clause<'db>>> {
+        self.0
+            .as_ref()
+            .map(|it| EarlyBinder::bind(it.iter().copied()).iter_instantiated(interner, args))
+    }
+
+    #[inline]
+    pub fn instantiate_identity(&self) -> Option<impl Iterator<Item = Clause<'db>>> {
+        self.0.as_ref().map(|it| it.iter().copied())
+    }
+}
+
+impl<'db> ops::Deref for GenericPredicates<'db> {
+    type Target = [Clause<'db>];
+
+    fn deref(&self) -> &Self::Target {
+        self.0.as_deref().unwrap_or(&[])
+    }
+}
+
+pub(crate) fn trait_environment_for_body_query(
+    db: &dyn HirDatabase,
+    def: DefWithBodyId,
+) -> Arc<TraitEnvironment<'_>> {
+    let Some(def) = def.as_generic_def_id(db) else {
+        let krate = def.module(db).krate();
+        return TraitEnvironment::empty(krate);
+    };
+    db.trait_environment(def)
+}
+
+pub(crate) fn trait_environment_query<'db>(
+    db: &'db dyn HirDatabase,
+    def: GenericDefId,
+) -> Arc<TraitEnvironment<'db>> {
+    let generics = generics(db, def);
+    if generics.has_no_predicates() && generics.is_empty() {
+        return TraitEnvironment::empty(def.krate(db));
+    }
+
+    let resolver = def.resolver(db);
+    let mut ctx = TyLoweringContext::new(
+        db,
+        &resolver,
+        generics.store(),
+        def,
+        LifetimeElisionKind::AnonymousReportError,
+    );
+    let mut traits_in_scope = Vec::new();
+    let mut clauses = Vec::new();
+    for maybe_parent_generics in
+        std::iter::successors(Some(&generics), |generics| generics.parent_generics())
+    {
+        ctx.store = maybe_parent_generics.store();
+        for pred in maybe_parent_generics.where_predicates() {
+            for pred in ctx.lower_where_predicate(pred, false, &generics, PredicateFilter::All) {
+                if let rustc_type_ir::ClauseKind::Trait(tr) = pred.kind().skip_binder() {
+                    traits_in_scope.push((tr.self_ty(), tr.def_id().0));
+                }
+                clauses.push(pred);
+            }
+        }
+    }
+
+    if let Some(trait_id) = def.assoc_trait_container(db) {
+        // add `Self: Trait<T1, T2, ...>` to the environment in trait
+        // function default implementations (and speculative code
+        // inside consts or type aliases)
+        cov_mark::hit!(trait_self_implements_self);
+        let trait_ref = TraitRef::identity(ctx.interner, trait_id.into());
+        let clause = Clause(Predicate::new(
+            ctx.interner,
+            Binder::dummy(rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Trait(
+                TraitPredicate { trait_ref, polarity: rustc_type_ir::PredicatePolarity::Positive },
+            ))),
+        ));
+        clauses.push(clause);
+    }
+
+    let explicitly_unsized_tys = ctx.unsized_types;
+
+    let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate());
+    if let Some(sized_trait) = sized_trait {
+        let (mut generics, mut def_id) =
+            (crate::next_solver::generics::generics(db, def.into()), def);
+        loop {
+            let self_idx = trait_self_param_idx(db, def_id);
+            for (idx, p) in generics.own_params.iter().enumerate() {
+                if let Some(self_idx) = self_idx
+                    && p.index() as usize == self_idx
+                {
+                    continue;
+                }
+                let GenericParamId::TypeParamId(param_id) = p.id else {
+                    continue;
+                };
+                let idx = idx as u32 + generics.parent_count as u32;
+                let param_ty = Ty::new_param(ctx.interner, param_id, idx);
+                if explicitly_unsized_tys.contains(&param_ty) {
+                    continue;
+                }
+                let trait_ref = TraitRef::new_from_args(
+                    ctx.interner,
+                    sized_trait.into(),
+                    GenericArgs::new_from_iter(ctx.interner, [param_ty.into()]),
+                );
+                let clause = Clause(Predicate::new(
+                    ctx.interner,
+                    Binder::dummy(rustc_type_ir::PredicateKind::Clause(
+                        rustc_type_ir::ClauseKind::Trait(TraitPredicate {
+                            trait_ref,
+                            polarity: rustc_type_ir::PredicatePolarity::Positive,
+                        }),
+                    )),
+                ));
+                clauses.push(clause);
+            }
+
+            if let Some(g) = generics.parent {
+                generics = crate::next_solver::generics::generics(db, g.into());
+                def_id = g;
+            } else {
+                break;
+            }
+        }
+    }
+
+    let clauses = rustc_type_ir::elaborate::elaborate(ctx.interner, clauses);
+    let clauses = Clauses::new_from_iter(ctx.interner, clauses);
+    let env = ParamEnv { clauses };
+
+    TraitEnvironment::new(resolver.krate(), None, traits_in_scope.into_boxed_slice(), env)
+}
+
+#[derive(Copy, Clone, Debug)]
+pub(crate) enum PredicateFilter {
+    SelfTrait,
+    All,
+}
+
+/// Resolve the where clause(s) of an item with generics.
+#[tracing::instrument(skip(db))]
+pub(crate) fn generic_predicates_query<'db>(
+    db: &'db dyn HirDatabase,
+    def: GenericDefId,
+) -> GenericPredicates<'db> {
+    generic_predicates_filtered_by(db, def, PredicateFilter::All, |_| true).0
+}
+
+pub(crate) fn generic_predicates_without_parent_query<'db>(
+    db: &'db dyn HirDatabase,
+    def: GenericDefId,
+) -> GenericPredicates<'db> {
+    generic_predicates_filtered_by(db, def, PredicateFilter::All, |d| d == def).0
+}
+
+/// Resolve the where clause(s) of an item with generics,
+/// except the ones inherited from the parent
+pub(crate) fn generic_predicates_without_parent_with_diagnostics_query<'db>(
+    db: &'db dyn HirDatabase,
+    def: GenericDefId,
+) -> (GenericPredicates<'db>, Diagnostics) {
+    generic_predicates_filtered_by(db, def, PredicateFilter::All, |d| d == def)
+}
+
+/// Resolve the where clause(s) of an item with generics,
+/// with a given filter
+#[tracing::instrument(skip(db, filter), ret)]
+pub(crate) fn generic_predicates_filtered_by<'db, F>(
+    db: &'db dyn HirDatabase,
+    def: GenericDefId,
+    predicate_filter: PredicateFilter,
+    filter: F,
+) -> (GenericPredicates<'db>, Diagnostics)
+where
+    F: Fn(GenericDefId) -> bool,
+{
+    let generics = generics(db, def);
+    let resolver = def.resolver(db);
+    let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
+    let mut ctx = TyLoweringContext::new(
+        db,
+        &resolver,
+        generics.store(),
+        def,
+        LifetimeElisionKind::AnonymousReportError,
+    );
+
+    let mut predicates = Vec::new();
+    for maybe_parent_generics in
+        std::iter::successors(Some(&generics), |generics| generics.parent_generics())
+    {
+        ctx.store = maybe_parent_generics.store();
+        for pred in maybe_parent_generics.where_predicates() {
+            tracing::debug!(?pred);
+            if filter(maybe_parent_generics.def()) {
+                predicates.extend(ctx.lower_where_predicate(
+                    pred,
+                    false,
+                    maybe_parent_generics,
+                    predicate_filter,
+                ));
+            }
+        }
+    }
+
+    let explicitly_unsized_tys = ctx.unsized_types;
+
+    let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate());
+    if let Some(sized_trait) = sized_trait {
+        let mut add_sized_clause = |param_idx, param_id, param_data| {
+            let (
+                GenericParamId::TypeParamId(param_id),
+                GenericParamDataRef::TypeParamData(param_data),
+            ) = (param_id, param_data)
+            else {
+                return;
+            };
+
+            if param_data.provenance == TypeParamProvenance::TraitSelf {
+                return;
+            }
+
+            let param_ty = Ty::new_param(interner, param_id, param_idx);
+            if explicitly_unsized_tys.contains(&param_ty) {
+                return;
+            }
+            let trait_ref = TraitRef::new_from_args(
+                interner,
+                sized_trait.into(),
+                GenericArgs::new_from_iter(interner, [param_ty.into()]),
+            );
+            let clause = Clause(Predicate::new(
+                interner,
+                Binder::dummy(rustc_type_ir::PredicateKind::Clause(
+                    rustc_type_ir::ClauseKind::Trait(TraitPredicate {
+                        trait_ref,
+                        polarity: rustc_type_ir::PredicatePolarity::Positive,
+                    }),
+                )),
+            ));
+            predicates.push(clause);
+        };
+        if generics.parent_generics().is_some_and(|parent| filter(parent.def())) {
+            generics.iter_parent().enumerate().for_each(|(param_idx, (param_id, param_data))| {
+                add_sized_clause(param_idx as u32, param_id, param_data);
+            });
+        }
+        if filter(def) {
+            let parent_params_len = generics.len_parent();
+            generics.iter_self().enumerate().for_each(|(param_idx, (param_id, param_data))| {
+                add_sized_clause((param_idx + parent_params_len) as u32, param_id, param_data);
+            });
+        }
+    }
+
+    // FIXME: rustc gathers more predicates by recursing through resulting trait predicates.
+    // See https://github.com/rust-lang/rust/blob/76c5ed2847cdb26ef2822a3a165d710f6b772217/compiler/rustc_hir_analysis/src/collect/predicates_of.rs#L689-L715
+
+    (
+        GenericPredicates(predicates.is_empty().not().then(|| predicates.into())),
+        create_diagnostics(ctx.diagnostics),
+    )
+}
+
+/// 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, 'db>(
+    db: &'db dyn HirDatabase,
+    def: GenericDefId,
+    explicitly_unsized_tys: &'a FxHashSet<Ty<'db>>,
+    args: &'subst GenericArgs<'db>,
+    resolver: &Resolver<'db>,
+) -> Option<impl Iterator<Item = Clause<'db>> + Captures<'a> + Captures<'subst>> {
+    let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
+    let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate())?;
+
+    let trait_self_idx = trait_self_param_idx(db, def);
+
+    Some(
+        args.iter()
+            .enumerate()
+            .filter_map(
+                move |(idx, generic_arg)| {
+                    if Some(idx) == trait_self_idx { None } else { Some(generic_arg) }
+                },
+            )
+            .filter_map(|generic_arg| generic_arg.as_type())
+            .filter(move |self_ty| !explicitly_unsized_tys.contains(self_ty))
+            .map(move |self_ty| {
+                let trait_ref = TraitRef::new_from_args(
+                    interner,
+                    sized_trait.into(),
+                    GenericArgs::new_from_iter(interner, [self_ty.into()]),
+                );
+                Clause(Predicate::new(
+                    interner,
+                    Binder::dummy(rustc_type_ir::PredicateKind::Clause(
+                        rustc_type_ir::ClauseKind::Trait(TraitPredicate {
+                            trait_ref,
+                            polarity: rustc_type_ir::PredicatePolarity::Positive,
+                        }),
+                    )),
+                ))
+            }),
+    )
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct GenericDefaults<'db>(Option<Arc<[Option<EarlyBinder<'db, GenericArg<'db>>>]>>);
+
+impl<'db> GenericDefaults<'db> {
+    #[inline]
+    pub fn get(&self, idx: usize) -> Option<EarlyBinder<'db, GenericArg<'db>>> {
+        self.0.as_ref()?[idx]
+    }
+}
+
+pub(crate) fn generic_defaults_query(
+    db: &dyn HirDatabase,
+    def: GenericDefId,
+) -> GenericDefaults<'_> {
+    db.generic_defaults_with_diagnostics(def).0
+}
+
+/// Resolve the default type params from generics.
+///
+/// Diagnostics are only returned for this `GenericDefId` (returned defaults include parents).
+pub(crate) fn generic_defaults_with_diagnostics_query(
+    db: &dyn HirDatabase,
+    def: GenericDefId,
+) -> (GenericDefaults<'_>, Diagnostics) {
+    let generic_params = generics(db, def);
+    if generic_params.is_empty() {
+        return (GenericDefaults(None), None);
+    }
+    let resolver = def.resolver(db);
+
+    let mut ctx = TyLoweringContext::new(
+        db,
+        &resolver,
+        generic_params.store(),
+        def,
         LifetimeElisionKind::AnonymousReportError,
     )
-    .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
-    .with_type_param_mode(ParamLoweringMode::Variable);
-    if let Some(type_ref) = data.ty {
-        let _ty = ctx.lower_ty(type_ref);
-    }
-    let type_alias_impl_traits = ImplTraits { impl_traits: ctx.impl_trait_mode.opaque_type_data };
-    if type_alias_impl_traits.impl_traits.is_empty() {
-        None
+    .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed);
+    let mut idx = 0;
+    let mut has_any_default = false;
+    let mut defaults = generic_params
+        .iter_parents_with_store()
+        .map(|((_id, p), store)| {
+            ctx.store = store;
+            let (result, has_default) = handle_generic_param(&mut ctx, idx, p);
+            has_any_default |= has_default;
+            idx += 1;
+            result
+        })
+        .collect::<Vec<_>>();
+    ctx.diagnostics.clear(); // Don't include diagnostics from the parent.
+    defaults.extend(generic_params.iter_self().map(|(_id, p)| {
+        let (result, has_default) = handle_generic_param(&mut ctx, idx, p);
+        has_any_default |= has_default;
+        idx += 1;
+        result
+    }));
+    let diagnostics = create_diagnostics(mem::take(&mut ctx.diagnostics));
+    let defaults = if has_any_default {
+        GenericDefaults(Some(Arc::from_iter(defaults)))
     } else {
-        let generics = generics(db, def.into());
-        Some(Arc::new(make_binders(db, &generics, type_alias_impl_traits)))
+        GenericDefaults(None)
+    };
+    return (defaults, diagnostics);
+
+    fn handle_generic_param<'db>(
+        ctx: &mut TyLoweringContext<'db, '_>,
+        idx: usize,
+        p: GenericParamDataRef<'_>,
+    ) -> (Option<EarlyBinder<'db, GenericArg<'db>>>, bool) {
+        ctx.lowering_param_default(idx as u32);
+        match p {
+            GenericParamDataRef::TypeParamData(p) => {
+                let ty = p.default.map(|ty| ctx.lower_ty(ty));
+                (ty.map(|ty| EarlyBinder::bind(ty.into())), p.default.is_some())
+            }
+            GenericParamDataRef::ConstParamData(p) => {
+                let val = p.default.map(|c| {
+                    let param_ty = ctx.lower_ty(p.ty);
+                    let c = ctx.lower_const(c, param_ty);
+                    c.into()
+                });
+                (val.map(EarlyBinder::bind), p.default.is_some())
+            }
+            GenericParamDataRef::LifetimeParamData(_) => (None, false),
+        }
     }
 }
 
-pub(crate) fn lower_to_chalk_mutability(m: hir_def::type_ref::Mutability) -> Mutability {
-    match m {
-        hir_def::type_ref::Mutability::Shared => Mutability::Not,
-        hir_def::type_ref::Mutability::Mut => Mutability::Mut,
+pub(crate) fn generic_defaults_with_diagnostics_cycle_result(
+    _db: &dyn HirDatabase,
+    _def: GenericDefId,
+) -> (GenericDefaults<'_>, Diagnostics) {
+    (GenericDefaults(None), None)
+}
+
+/// Build the signature of a callable item (function, struct or enum variant).
+pub(crate) fn callable_item_signature_query<'db>(
+    db: &'db dyn HirDatabase,
+    def: CallableDefId,
+) -> EarlyBinder<'db, PolyFnSig<'db>> {
+    match def {
+        CallableDefId::FunctionId(f) => fn_sig_for_fn(db, f),
+        CallableDefId::StructId(s) => fn_sig_for_struct_constructor(db, s),
+        CallableDefId::EnumVariantId(e) => fn_sig_for_enum_variant_constructor(db, e),
     }
 }
 
-/// Replaces any 'free' `BoundVar`s in `s` by `TyKind::Error` from the perspective of generic
-/// parameter whose index is `param_index`. A `BoundVar` is free when it appears after the
-/// generic parameter of `param_index`.
-fn fallback_bound_vars<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>(
-    s: T,
-    param_index: usize,
-) -> T {
-    let is_allowed = |index| (0..param_index).contains(&index);
+fn fn_sig_for_fn<'db>(
+    db: &'db dyn HirDatabase,
+    def: FunctionId,
+) -> EarlyBinder<'db, PolyFnSig<'db>> {
+    let data = db.function_signature(def);
+    let resolver = def.resolver(db);
+    let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
+    let mut ctx_params = TyLoweringContext::new(
+        db,
+        &resolver,
+        &data.store,
+        def.into(),
+        LifetimeElisionKind::for_fn_params(&data),
+    );
+    let params = data.params.iter().map(|&tr| ctx_params.lower_ty(tr));
 
-    crate::fold_free_vars(
-        s,
-        |bound, binders| {
-            if bound.index_if_innermost().is_none_or(is_allowed) {
-                bound.shifted_in_from(binders).to_ty(Interner)
-            } else {
-                TyKind::Error.intern(Interner)
+    let ret = match data.ret_type {
+        Some(ret_type) => {
+            let mut ctx_ret = TyLoweringContext::new(
+                db,
+                &resolver,
+                &data.store,
+                def.into(),
+                LifetimeElisionKind::for_fn_ret(interner),
+            )
+            .with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
+            ctx_ret.lower_ty(ret_type)
+        }
+        None => Ty::new_tup(interner, &[]),
+    };
+
+    let inputs_and_output = Tys::new_from_iter(interner, params.chain(Some(ret)));
+    // If/when we track late bound vars, we need to switch this to not be `dummy`
+    EarlyBinder::bind(rustc_type_ir::Binder::dummy(FnSig {
+        abi: data.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol),
+        c_variadic: data.is_varargs(),
+        safety: if data.is_unsafe() { Safety::Unsafe } else { Safety::Safe },
+        inputs_and_output,
+    }))
+}
+
+fn type_for_adt<'db>(db: &'db dyn HirDatabase, adt: AdtId) -> EarlyBinder<'db, Ty<'db>> {
+    let interner = DbInterner::new_with(db, None, None);
+    let args = GenericArgs::identity_for_item(interner, adt.into());
+    let ty = Ty::new_adt(interner, adt, args);
+    EarlyBinder::bind(ty)
+}
+
+fn fn_sig_for_struct_constructor<'db>(
+    db: &'db dyn HirDatabase,
+    def: StructId,
+) -> EarlyBinder<'db, PolyFnSig<'db>> {
+    let field_tys = db.field_types(def.into());
+    let params = field_tys.iter().map(|(_, ty)| ty.skip_binder());
+    let ret = type_for_adt(db, def.into()).skip_binder();
+
+    let inputs_and_output =
+        Tys::new_from_iter(DbInterner::new_with(db, None, None), params.chain(Some(ret)));
+    EarlyBinder::bind(Binder::dummy(FnSig {
+        abi: FnAbi::RustCall,
+        c_variadic: false,
+        safety: Safety::Safe,
+        inputs_and_output,
+    }))
+}
+
+fn fn_sig_for_enum_variant_constructor<'db>(
+    db: &'db dyn HirDatabase,
+    def: EnumVariantId,
+) -> EarlyBinder<'db, PolyFnSig<'db>> {
+    let field_tys = db.field_types(def.into());
+    let params = field_tys.iter().map(|(_, ty)| ty.skip_binder());
+    let parent = def.lookup(db).parent;
+    let ret = type_for_adt(db, parent.into()).skip_binder();
+
+    let inputs_and_output =
+        Tys::new_from_iter(DbInterner::new_with(db, None, None), params.chain(Some(ret)));
+    EarlyBinder::bind(Binder::dummy(FnSig {
+        abi: FnAbi::RustCall,
+        c_variadic: false,
+        safety: Safety::Safe,
+        inputs_and_output,
+    }))
+}
+
+// FIXME(next-solver): should merge this with `explicit_item_bounds` in some way
+pub(crate) fn associated_ty_item_bounds<'db>(
+    db: &'db dyn HirDatabase,
+    type_alias: TypeAliasId,
+) -> EarlyBinder<'db, BoundExistentialPredicates<'db>> {
+    let type_alias_data = db.type_alias_signature(type_alias);
+    let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db);
+    let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
+    let mut ctx = TyLoweringContext::new(
+        db,
+        &resolver,
+        &type_alias_data.store,
+        type_alias.into(),
+        LifetimeElisionKind::AnonymousReportError,
+    );
+    // FIXME: we should never create non-existential predicates in the first place
+    // For now, use an error type so we don't run into dummy binder issues
+    let self_ty = Ty::new_error(interner, ErrorGuaranteed);
+
+    let mut bounds = Vec::new();
+    for bound in &type_alias_data.bounds {
+        ctx.lower_type_bound(bound, self_ty, false).for_each(|pred| {
+            if let Some(bound) = pred
+                .kind()
+                .map_bound(|c| match c {
+                    rustc_type_ir::ClauseKind::Trait(t) => {
+                        let id = t.def_id();
+                        let is_auto = db.trait_signature(id.0).flags.contains(TraitFlags::AUTO);
+                        if is_auto {
+                            Some(ExistentialPredicate::AutoTrait(t.def_id()))
+                        } else {
+                            Some(ExistentialPredicate::Trait(ExistentialTraitRef::new_from_args(
+                                interner,
+                                t.def_id(),
+                                GenericArgs::new_from_iter(
+                                    interner,
+                                    t.trait_ref.args.iter().skip(1),
+                                ),
+                            )))
+                        }
+                    }
+                    rustc_type_ir::ClauseKind::Projection(p) => Some(
+                        ExistentialPredicate::Projection(ExistentialProjection::new_from_args(
+                            interner,
+                            p.def_id(),
+                            GenericArgs::new_from_iter(
+                                interner,
+                                p.projection_term.args.iter().skip(1),
+                            ),
+                            p.term,
+                        )),
+                    ),
+                    rustc_type_ir::ClauseKind::TypeOutlives(_) => None,
+                    rustc_type_ir::ClauseKind::RegionOutlives(_)
+                    | rustc_type_ir::ClauseKind::ConstArgHasType(_, _)
+                    | rustc_type_ir::ClauseKind::WellFormed(_)
+                    | rustc_type_ir::ClauseKind::ConstEvaluatable(_)
+                    | rustc_type_ir::ClauseKind::HostEffect(_)
+                    | rustc_type_ir::ClauseKind::UnstableFeature(_) => unreachable!(),
+                })
+                .transpose()
+            {
+                bounds.push(bound);
             }
-        },
-        |ty, bound, binders| {
-            if bound.index_if_innermost().is_none_or(is_allowed) {
-                bound.shifted_in_from(binders).to_const(Interner, ty)
-            } else {
-                unknown_const(ty)
+        });
+    }
+
+    if !ctx.unsized_types.contains(&self_ty)
+        && let Some(sized_trait) = LangItem::Sized.resolve_trait(db, resolver.krate())
+    {
+        let sized_clause = Binder::dummy(ExistentialPredicate::Trait(ExistentialTraitRef::new(
+            interner,
+            sized_trait.into(),
+            [] as [GenericArg<'_>; 0],
+        )));
+        bounds.push(sized_clause);
+    }
+
+    EarlyBinder::bind(BoundExistentialPredicates::new_from_iter(interner, bounds))
+}
+
+pub(crate) fn associated_type_by_name_including_super_traits<'db>(
+    db: &'db dyn HirDatabase,
+    trait_ref: TraitRef<'db>,
+    name: &Name,
+) -> Option<(TraitRef<'db>, TypeAliasId)> {
+    let interner = DbInterner::new_with(db, None, None);
+    rustc_type_ir::elaborate::supertraits(interner, Binder::dummy(trait_ref)).find_map(|t| {
+        let trait_id = t.as_ref().skip_binder().def_id.0;
+        let assoc_type = trait_id.trait_items(db).associated_type_by_name(name)?;
+        Some((t.skip_binder(), assoc_type))
+    })
+}
+
+pub fn associated_type_shorthand_candidates(
+    db: &dyn HirDatabase,
+    def: GenericDefId,
+    res: TypeNs,
+    mut cb: impl FnMut(&Name, TypeAliasId) -> bool,
+) -> Option<TypeAliasId> {
+    let interner = DbInterner::new_with(db, None, None);
+    named_associated_type_shorthand_candidates(interner, def, res, None, |name, _, id| {
+        cb(name, id).then_some(id)
+    })
+}
+
+#[tracing::instrument(skip(interner, check_alias))]
+fn named_associated_type_shorthand_candidates<'db, R>(
+    interner: DbInterner<'db>,
+    // If the type parameter is defined in an impl and we're in a method, there
+    // might be additional where clauses to consider
+    def: GenericDefId,
+    res: TypeNs,
+    assoc_name: Option<Name>,
+    mut check_alias: impl FnMut(&Name, TraitRef<'db>, TypeAliasId) -> Option<R>,
+) -> Option<R> {
+    let db = interner.db;
+    let mut search = |t: TraitRef<'db>| -> Option<R> {
+        let mut checked_traits = FxHashSet::default();
+        let mut check_trait = |trait_ref: TraitRef<'db>| {
+            let trait_id = trait_ref.def_id.0;
+            let name = &db.trait_signature(trait_id).name;
+            tracing::debug!(?trait_id, ?name);
+            if !checked_traits.insert(trait_id) {
+                return None;
             }
-        },
-    )
+            let data = trait_id.trait_items(db);
+
+            tracing::debug!(?data.items);
+            for (name, assoc_id) in &data.items {
+                if let &AssocItemId::TypeAliasId(alias) = assoc_id
+                    && let Some(ty) = check_alias(name, trait_ref, alias)
+                {
+                    return Some(ty);
+                }
+            }
+            None
+        };
+        let mut stack: SmallVec<[_; 4]> = smallvec![t];
+        while let Some(trait_ref) = stack.pop() {
+            if let Some(alias) = check_trait(trait_ref) {
+                return Some(alias);
+            }
+            for pred in generic_predicates_filtered_by(
+                db,
+                GenericDefId::TraitId(trait_ref.def_id.0),
+                PredicateFilter::SelfTrait,
+                // We are likely in the midst of lowering generic predicates of `def`.
+                // So, if we allow `pred == def` we might fall into an infinite recursion.
+                // Actually, we have already checked for the case `pred == def` above as we started
+                // with a stack including `trait_id`
+                |pred| pred != def && pred == GenericDefId::TraitId(trait_ref.def_id.0),
+            )
+            .0
+            .deref()
+            {
+                tracing::debug!(?pred);
+                let sup_trait_ref = match pred.kind().skip_binder() {
+                    rustc_type_ir::ClauseKind::Trait(pred) => pred.trait_ref,
+                    _ => continue,
+                };
+                let sup_trait_ref =
+                    EarlyBinder::bind(sup_trait_ref).instantiate(interner, trait_ref.args);
+                stack.push(sup_trait_ref);
+            }
+            tracing::debug!(?stack);
+        }
+
+        None
+    };
+
+    match res {
+        TypeNs::SelfType(impl_id) => {
+            let trait_ref = db.impl_trait(impl_id)?;
+
+            // FIXME(next-solver): same method in `lower` checks for impl or not
+            // Is that needed here?
+
+            // we're _in_ the impl -- the binders get added back later. Correct,
+            // but it would be nice to make this more explicit
+            search(trait_ref.skip_binder())
+        }
+        TypeNs::GenericParam(param_id) => {
+            // Handle `Self::Type` referring to own associated type in trait definitions
+            // This *must* be done first to avoid cycles with
+            // `generic_predicates_for_param`, but not sure that it's sufficient,
+            if let GenericDefId::TraitId(trait_id) = param_id.parent() {
+                let trait_name = &db.trait_signature(trait_id).name;
+                tracing::debug!(?trait_name);
+                let trait_generics = generics(db, trait_id.into());
+                tracing::debug!(?trait_generics);
+                if trait_generics[param_id.local_id()].is_trait_self() {
+                    let args = GenericArgs::identity_for_item(interner, trait_id.into());
+                    let trait_ref = TraitRef::new_from_args(interner, trait_id.into(), args);
+                    tracing::debug!(?args, ?trait_ref);
+                    return search(trait_ref);
+                }
+            }
+
+            let predicates =
+                db.generic_predicates_for_param(def, param_id.into(), assoc_name.clone());
+            predicates
+                .iter()
+                .find_map(|pred| match (*pred).kind().skip_binder() {
+                    rustc_type_ir::ClauseKind::Trait(trait_predicate) => Some(trait_predicate),
+                    _ => None,
+                })
+                .and_then(|trait_predicate| {
+                    let trait_ref = trait_predicate.trait_ref;
+                    assert!(
+                        !trait_ref.has_escaping_bound_vars(),
+                        "FIXME unexpected higher-ranked trait bound"
+                    );
+                    search(trait_ref)
+                })
+        }
+        _ => None,
+    }
 }
diff --git a/crates/hir-ty/src/lower/path.rs b/crates/hir-ty/src/lower/path.rs
index 09a256a..9ba0da6 100644
--- a/crates/hir-ty/src/lower/path.rs
+++ b/crates/hir-ty/src/lower/path.rs
@@ -1,42 +1,52 @@
 //! A wrapper around [`TyLoweringContext`] specifically for lowering paths.
 
-use chalk_ir::{BoundVar, cast::Cast, fold::Shift};
 use either::Either;
 use hir_def::{
-    GenericDefId, GenericParamId, TraitId,
+    GenericDefId, GenericParamId, Lookup, TraitId, TypeAliasId,
     expr_store::{
-        ExpressionStore,
-        path::{GenericArg, GenericArgs, GenericArgsParentheses, Path, PathSegment, PathSegments},
+        ExpressionStore, HygieneId,
+        path::{
+            GenericArg as HirGenericArg, GenericArgs as HirGenericArgs, GenericArgsParentheses,
+            Path, PathSegment, PathSegments,
+        },
     },
     hir::generics::{
         GenericParamDataRef, TypeOrConstParamData, TypeParamData, TypeParamProvenance,
     },
-    resolver::TypeNs,
+    resolver::{ResolveValueResult, TypeNs, ValueNs},
     signatures::TraitFlags,
     type_ref::{TypeRef, TypeRefId},
 };
+use hir_expand::name::Name;
+use rustc_type_ir::{
+    AliasTerm, AliasTy, AliasTyKind,
+    inherent::{GenericArgs as _, Region as _, SliceLike, Ty as _},
+};
 use smallvec::SmallVec;
 use stdx::never;
 
 use crate::{
-    AliasEq, AliasTy, GenericArgsProhibitedReason, ImplTraitLoweringMode, IncorrectGenericsLenKind,
-    Interner, ParamLoweringMode, PathGenericsSource, PathLoweringDiagnostic, ProjectionTy,
-    QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyDefId, TyKind, WhereClause,
-    consteval_chalk::{unknown_const, unknown_const_as_generic},
+    GenericArgsProhibitedReason, IncorrectGenericsLenKind, PathGenericsSource,
+    PathLoweringDiagnostic, TyDefId, ValueTyDefId,
+    consteval::{unknown_const, unknown_const_as_generic},
     db::HirDatabase,
-    error_lifetime,
     generics::{Generics, generics},
-    lower::{LifetimeElisionKind, TyLoweringContext, named_associated_type_shorthand_candidates},
-    next_solver::{
-        DbInterner,
-        mapping::{ChalkToNextSolver, NextSolverToChalk},
+    lower::{
+        LifetimeElisionKind, PathDiagnosticCallbackData, named_associated_type_shorthand_candidates,
     },
-    to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
-    utils::associated_type_by_name_including_super_traits,
+    next_solver::{
+        Binder, Clause, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, Predicate,
+        ProjectionPredicate, Region, TraitRef, Ty,
+    },
+};
+
+use super::{
+    ImplTraitLoweringMode, TyLoweringContext, associated_type_by_name_including_super_traits,
+    const_param_ty_query, ty_query,
 };
 
 type CallbackData<'a, 'db> = Either<
-    super::PathDiagnosticCallbackData,
+    PathDiagnosticCallbackData,
     crate::infer::diagnostics::PathDiagnosticCallbackData<'a, 'db>,
 >;
 
@@ -45,12 +55,12 @@
 pub(crate) struct PathDiagnosticCallback<'a, 'db> {
     pub(crate) data: CallbackData<'a, 'db>,
     pub(crate) callback:
-        fn(&CallbackData<'_, 'db>, &mut TyLoweringContext<'_>, PathLoweringDiagnostic),
+        fn(&CallbackData<'_, 'db>, &mut TyLoweringContext<'db, '_>, PathLoweringDiagnostic),
 }
 
-pub(crate) struct PathLoweringContext<'a, 'b> {
-    ctx: &'a mut TyLoweringContext<'b>,
-    on_diagnostic: PathDiagnosticCallback<'a, 'b>,
+pub(crate) struct PathLoweringContext<'a, 'b, 'db> {
+    ctx: &'a mut TyLoweringContext<'db, 'b>,
+    on_diagnostic: PathDiagnosticCallback<'a, 'db>,
     path: &'a Path,
     segments: PathSegments<'a>,
     current_segment_idx: usize,
@@ -58,11 +68,11 @@
     current_or_prev_segment: PathSegment<'a>,
 }
 
-impl<'a, 'b> PathLoweringContext<'a, 'b> {
+impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
     #[inline]
     pub(crate) fn new(
-        ctx: &'a mut TyLoweringContext<'b>,
-        on_diagnostic: PathDiagnosticCallback<'a, 'b>,
+        ctx: &'a mut TyLoweringContext<'db, 'b>,
+        on_diagnostic: PathDiagnosticCallback<'a, 'db>,
         path: &'a Path,
     ) -> Self {
         let segments = path.segments();
@@ -84,7 +94,7 @@
     }
 
     #[inline]
-    pub(crate) fn ty_ctx(&mut self) -> &mut TyLoweringContext<'b> {
+    pub(crate) fn ty_ctx(&mut self) -> &mut TyLoweringContext<'db, 'b> {
         self.ctx
     }
 
@@ -110,10 +120,24 @@
     }
 
     #[inline]
+    pub(crate) fn ignore_last_segment(&mut self) {
+        self.segments = self.segments.strip_last();
+    }
+
+    #[inline]
+    pub(crate) fn set_current_segment(&mut self, segment: usize) {
+        self.current_segment_idx = segment;
+        self.current_or_prev_segment = self
+            .segments
+            .get(segment)
+            .expect("invalid segment passed to PathLoweringContext::set_current_segment()");
+    }
+
+    #[inline]
     fn with_lifetime_elision<T>(
         &mut self,
-        lifetime_elision: LifetimeElisionKind,
-        f: impl FnOnce(&mut PathLoweringContext<'_, '_>) -> T,
+        lifetime_elision: LifetimeElisionKind<'db>,
+        f: impl FnOnce(&mut PathLoweringContext<'_, '_, 'db>) -> T,
     ) -> T {
         let old_lifetime_elision =
             std::mem::replace(&mut self.ctx.lifetime_elision, lifetime_elision);
@@ -124,12 +148,13 @@
 
     pub(crate) fn lower_ty_relative_path(
         &mut self,
-        ty: Ty,
+        ty: Ty<'db>,
         // We need the original resolution to lower `Self::AssocTy` correctly
         res: Option<TypeNs>,
         infer_args: bool,
-    ) -> (Ty, Option<TypeNs>) {
-        match self.segments.len() - self.current_segment_idx {
+    ) -> (Ty<'db>, Option<TypeNs>) {
+        let remaining_segments = self.segments.len() - self.current_segment_idx;
+        match remaining_segments {
             0 => (ty, res),
             1 => {
                 // resolve unselected assoc types
@@ -137,7 +162,7 @@
             }
             _ => {
                 // FIXME report error (ambiguous associated type)
-                (TyKind::Error.intern(Interner), None)
+                (Ty::new_error(self.ctx.interner, ErrorGuaranteed), None)
             }
         }
     }
@@ -147,8 +172,11 @@
         &mut self,
         resolution: TypeNs,
         infer_args: bool,
-    ) -> (Ty, Option<TypeNs>) {
+    ) -> (Ty<'db>, Option<TypeNs>) {
         let remaining_segments = self.segments.skip(self.current_segment_idx + 1);
+        tracing::debug!(?remaining_segments);
+        let rem_seg_len = remaining_segments.len();
+        tracing::debug!(?rem_seg_len);
 
         let ty = match resolution {
             TypeNs::TraitId(trait_) => {
@@ -156,15 +184,17 @@
                     1 => {
                         let trait_ref = self.lower_trait_ref_from_resolved_path(
                             trait_,
-                            TyKind::Error.intern(Interner),
-                            infer_args,
+                            Ty::new_error(self.ctx.interner, ErrorGuaranteed),
+                            false,
                         );
-
+                        tracing::debug!(?trait_ref);
                         self.skip_resolved_segment();
                         let segment = self.current_or_prev_segment;
+                        let trait_id = trait_ref.def_id.0;
                         let found =
-                            trait_.trait_items(self.ctx.db).associated_type_by_name(segment.name);
+                            trait_id.trait_items(self.ctx.db).associated_type_by_name(segment.name);
 
+                        tracing::debug!(?found);
                         match found {
                             Some(associated_ty) => {
                                 // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
@@ -173,27 +203,30 @@
                                 // this point (`trait_ref.substitution`).
                                 let substitution = self.substs_from_path_segment(
                                     associated_ty.into(),
-                                    infer_args,
+                                    false,
                                     None,
                                     true,
                                 );
-                                let substitution = Substitution::from_iter(
-                                    Interner,
-                                    trait_ref.substitution.iter(Interner).chain(
-                                        substitution
-                                            .iter(Interner)
-                                            .skip(trait_ref.substitution.len(Interner)),
-                                    ),
+                                let args = GenericArgs::new_from_iter(
+                                    self.ctx.interner,
+                                    trait_ref
+                                        .args
+                                        .iter()
+                                        .chain(substitution.iter().skip(trait_ref.args.len())),
                                 );
-                                TyKind::Alias(AliasTy::Projection(ProjectionTy {
-                                    associated_ty_id: to_assoc_type_id(associated_ty),
-                                    substitution,
-                                }))
-                                .intern(Interner)
+                                Ty::new_alias(
+                                    self.ctx.interner,
+                                    AliasTyKind::Projection,
+                                    AliasTy::new_from_args(
+                                        self.ctx.interner,
+                                        associated_ty.into(),
+                                        args,
+                                    ),
+                                )
                             }
                             None => {
                                 // FIXME: report error (associated type not found)
-                                TyKind::Error.intern(Interner)
+                                Ty::new_error(self.ctx.interner, ErrorGuaranteed)
                             }
                         }
                     }
@@ -201,73 +234,34 @@
                         // Trait object type without dyn; this should be handled in upstream. See
                         // `lower_path()`.
                         stdx::never!("unexpected fully resolved trait path");
-                        TyKind::Error.intern(Interner)
+                        Ty::new_error(self.ctx.interner, ErrorGuaranteed)
                     }
                     _ => {
                         // FIXME report error (ambiguous associated type)
-                        TyKind::Error.intern(Interner)
+                        Ty::new_error(self.ctx.interner, ErrorGuaranteed)
                     }
                 };
                 return (ty, None);
             }
-            TypeNs::GenericParam(param_id) => match self.ctx.type_param_mode {
-                ParamLoweringMode::Placeholder => {
-                    let generics = self.ctx.generics();
-                    let idx = generics.type_or_const_param_idx(param_id.into()).unwrap();
-                    TyKind::Placeholder(to_placeholder_idx(
-                        self.ctx.db,
-                        param_id.into(),
-                        idx as u32,
-                    ))
-                }
-                ParamLoweringMode::Variable => {
-                    let idx = match self.ctx.generics().type_or_const_param_idx(param_id.into()) {
-                        None => {
-                            never!("no matching generics");
-                            return (TyKind::Error.intern(Interner), None);
-                        }
-                        Some(idx) => idx,
-                    };
-
-                    TyKind::BoundVar(BoundVar::new(self.ctx.in_binders, idx))
-                }
-            }
-            .intern(Interner),
-            TypeNs::SelfType(impl_id) => {
+            TypeNs::GenericParam(param_id) => {
                 let generics = self.ctx.generics();
-
-                match self.ctx.type_param_mode {
-                    ParamLoweringMode::Placeholder => {
-                        // `def` can be either impl itself or item within, and we need impl itself
-                        // now.
-                        let generics = generics.parent_or_self();
-                        let interner = DbInterner::new_with(self.ctx.db, None, None);
-                        let subst = generics.placeholder_subst(self.ctx.db);
-                        let args: crate::next_solver::GenericArgs<'_> =
-                            subst.to_nextsolver(interner);
-                        self.ctx
-                            .db
-                            .impl_self_ty(impl_id)
-                            .instantiate(interner, args)
-                            .to_chalk(interner)
+                let idx = generics.type_or_const_param_idx(param_id.into());
+                match idx {
+                    None => {
+                        never!("no matching generics");
+                        Ty::new_error(self.ctx.interner, ErrorGuaranteed)
                     }
-                    ParamLoweringMode::Variable => TyBuilder::impl_self_ty(self.ctx.db, impl_id)
-                        .fill_with_bound_vars(self.ctx.in_binders, 0)
-                        .build(DbInterner::conjure())
-                        .to_chalk(DbInterner::conjure()),
+                    Some(idx) => {
+                        let (pidx, _param) = generics.iter().nth(idx).unwrap();
+                        assert_eq!(pidx, param_id.into());
+                        self.ctx.type_param(param_id, idx as u32)
+                    }
                 }
             }
+            TypeNs::SelfType(impl_id) => self.ctx.db.impl_self_ty(impl_id).skip_binder(),
             TypeNs::AdtSelfType(adt) => {
-                let generics = generics(self.ctx.db, adt.into());
-                let substs = match self.ctx.type_param_mode {
-                    ParamLoweringMode::Placeholder => generics.placeholder_subst(self.ctx.db),
-                    ParamLoweringMode::Variable => {
-                        generics.bound_vars_subst(self.ctx.db, self.ctx.in_binders)
-                    }
-                };
-                let interner = DbInterner::conjure();
-                let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
-                self.ctx.db.ty(adt.into()).instantiate(interner, args).to_chalk(interner)
+                let args = GenericArgs::identity_for_item(self.ctx.interner, adt.into());
+                Ty::new_adt(self.ctx.interner, adt, args)
             }
 
             TypeNs::AdtId(it) => self.lower_path_inner(it.into(), infer_args),
@@ -275,15 +269,19 @@
             TypeNs::TypeAliasId(it) => self.lower_path_inner(it.into(), infer_args),
             // FIXME: report error
             TypeNs::EnumVariantId(_) | TypeNs::ModuleId(_) => {
-                return (TyKind::Error.intern(Interner), None);
+                return (Ty::new_error(self.ctx.interner, ErrorGuaranteed), None);
             }
         };
 
+        tracing::debug!(?ty);
+
         self.skip_resolved_segment();
         self.lower_ty_relative_path(ty, Some(resolution), infer_args)
     }
 
-    fn handle_type_ns_resolution(&mut self, resolution: &TypeNs) {
+    /// This returns whether to keep the resolution (`true`) of throw it (`false`).
+    #[must_use]
+    fn handle_type_ns_resolution(&mut self, resolution: &TypeNs) -> bool {
         let mut prohibit_generics_on_resolved = |reason| {
             if self.current_or_prev_segment.args_and_bindings.is_some() {
                 let segment = self.current_segment_u32();
@@ -302,7 +300,13 @@
                 prohibit_generics_on_resolved(GenericArgsProhibitedReason::TyParam)
             }
             TypeNs::AdtSelfType(_) => {
-                prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy)
+                prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy);
+
+                if self.ctx.lowering_param_default.is_some() {
+                    // Generic defaults are not allowed to refer to `Self`.
+                    // FIXME: Emit an error.
+                    return false;
+                }
             }
             TypeNs::BuiltinType(_) => {
                 prohibit_generics_on_resolved(GenericArgsProhibitedReason::PrimitiveTy)
@@ -315,6 +319,8 @@
             | TypeNs::TypeAliasId(_)
             | TypeNs::TraitId(_) => {}
         }
+
+        true
     }
 
     pub(crate) fn resolve_path_in_type_ns_fully(&mut self) -> Option<TypeNs> {
@@ -325,6 +331,7 @@
         Some(res)
     }
 
+    #[tracing::instrument(skip(self), ret)]
     pub(crate) fn resolve_path_in_type_ns(&mut self) -> Option<(TypeNs, Option<usize>)> {
         let (resolution, remaining_index, _, prefix_info) =
             self.ctx.resolver.resolve_path_in_type_ns_with_prefix_info(self.ctx.db, self.path)?;
@@ -347,11 +354,6 @@
         self.current_or_prev_segment =
             segments.get(resolved_segment_idx).expect("should have resolved segment");
 
-        if matches!(self.path, Path::BarePath(..)) {
-            // Bare paths cannot have generics, so skip them as an optimization.
-            return Some((resolution, remaining_index));
-        }
-
         for (i, mod_segment) in module_segments.iter().enumerate() {
             if mod_segment.args_and_bindings.is_some() {
                 self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
@@ -371,87 +373,233 @@
             });
         }
 
-        self.handle_type_ns_resolution(&resolution);
+        if !self.handle_type_ns_resolution(&resolution) {
+            return None;
+        }
 
         Some((resolution, remaining_index))
     }
 
-    fn select_associated_type(&mut self, res: Option<TypeNs>, infer_args: bool) -> Ty {
-        let Some(res) = res else {
-            return TyKind::Error.intern(Interner);
-        };
-        let segment = self.current_or_prev_segment;
-        let ty = named_associated_type_shorthand_candidates(
+    pub(crate) fn resolve_path_in_value_ns(
+        &mut self,
+        hygiene_id: HygieneId,
+    ) -> Option<ResolveValueResult> {
+        let (res, prefix_info) = self.ctx.resolver.resolve_path_in_value_ns_with_prefix_info(
             self.ctx.db,
-            self.ctx.def,
-            res,
-            Some(segment.name.clone()),
-            move |name, t, associated_ty| {
-                if name != segment.name {
-                    return None;
-                }
-                let generics = self.ctx.generics();
+            self.path,
+            hygiene_id,
+        )?;
 
-                let parent_subst = t.substitution.clone();
-                let parent_subst = match self.ctx.type_param_mode {
-                    ParamLoweringMode::Placeholder => {
-                        // if we're lowering to placeholders, we have to put them in now.
-                        let s = generics.placeholder_subst(self.ctx.db);
-                        s.apply(parent_subst, Interner)
-                    }
-                    ParamLoweringMode::Variable => {
-                        // We need to shift in the bound vars, since
-                        // `named_associated_type_shorthand_candidates` does not do that.
-                        parent_subst.shifted_in_from(Interner, self.ctx.in_binders)
+        let segments = self.segments;
+        if segments.is_empty() || matches!(self.path, Path::LangItem(..)) {
+            // `segments.is_empty()` can occur with `self`.
+            return Some(res);
+        }
+
+        let (mod_segments, enum_segment, resolved_segment_idx) = match res {
+            ResolveValueResult::Partial(_, unresolved_segment, _) => {
+                (segments.take(unresolved_segment - 1), None, unresolved_segment - 1)
+            }
+            ResolveValueResult::ValueNs(ValueNs::EnumVariantId(_), _)
+                if prefix_info.enum_variant =>
+            {
+                (segments.strip_last_two(), segments.len().checked_sub(2), segments.len() - 1)
+            }
+            ResolveValueResult::ValueNs(..) => (segments.strip_last(), None, segments.len() - 1),
+        };
+
+        self.current_segment_idx = resolved_segment_idx;
+        self.current_or_prev_segment =
+            segments.get(resolved_segment_idx).expect("should have resolved segment");
+
+        for (i, mod_segment) in mod_segments.iter().enumerate() {
+            if mod_segment.args_and_bindings.is_some() {
+                self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
+                    segment: i as u32,
+                    reason: GenericArgsProhibitedReason::Module,
+                });
+            }
+        }
+
+        if let Some(enum_segment) = enum_segment
+            && segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some())
+            && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some())
+        {
+            self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
+                segment: (enum_segment + 1) as u32,
+                reason: GenericArgsProhibitedReason::EnumVariant,
+            });
+        }
+
+        match &res {
+            ResolveValueResult::ValueNs(resolution, _) => {
+                let resolved_segment_idx = self.current_segment_u32();
+                let resolved_segment = self.current_or_prev_segment;
+
+                let mut prohibit_generics_on_resolved = |reason| {
+                    if resolved_segment.args_and_bindings.is_some() {
+                        self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
+                            segment: resolved_segment_idx,
+                            reason,
+                        });
                     }
                 };
 
-                // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
-                // generic params. It's inefficient to splice the `Substitution`s, so we may want
-                // that method to optionally take parent `Substitution` as we already know them at
-                // this point (`t.substitution`).
-                let substs =
-                    self.substs_from_path_segment(associated_ty.into(), infer_args, None, true);
-
-                let substs = Substitution::from_iter(
-                    Interner,
-                    parent_subst
-                        .iter(Interner)
-                        .chain(substs.iter(Interner).skip(parent_subst.len(Interner))),
-                );
-
-                Some(
-                    TyKind::Alias(AliasTy::Projection(ProjectionTy {
-                        associated_ty_id: to_assoc_type_id(associated_ty),
-                        substitution: substs,
-                    }))
-                    .intern(Interner),
-                )
-            },
-        );
-
-        ty.unwrap_or_else(|| TyKind::Error.intern(Interner))
+                match resolution {
+                    ValueNs::ImplSelf(_) => {
+                        prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy);
+                    }
+                    // FIXME: rustc generates E0107 (incorrect number of generic arguments) and not
+                    // E0109 (generic arguments provided for a type that doesn't accept them) for
+                    // consts and statics, presumably as a defense against future in which consts
+                    // and statics can be generic, or just because it was easier for rustc implementors.
+                    // That means we'll show the wrong error code. Because of us it's easier to do it
+                    // this way :)
+                    ValueNs::GenericParam(_) => {
+                        prohibit_generics_on_resolved(GenericArgsProhibitedReason::Const)
+                    }
+                    ValueNs::StaticId(_) => {
+                        prohibit_generics_on_resolved(GenericArgsProhibitedReason::Static)
+                    }
+                    ValueNs::LocalBinding(_) => {
+                        prohibit_generics_on_resolved(GenericArgsProhibitedReason::LocalVariable)
+                    }
+                    ValueNs::FunctionId(_)
+                    | ValueNs::StructId(_)
+                    | ValueNs::EnumVariantId(_)
+                    | ValueNs::ConstId(_) => {}
+                }
+            }
+            ResolveValueResult::Partial(resolution, _, _) => {
+                if !self.handle_type_ns_resolution(resolution) {
+                    return None;
+                }
+            }
+        };
+        Some(res)
     }
 
-    fn lower_path_inner(&mut self, typeable: TyDefId, infer_args: bool) -> Ty {
+    #[tracing::instrument(skip(self), ret)]
+    fn select_associated_type(&mut self, res: Option<TypeNs>, infer_args: bool) -> Ty<'db> {
+        let interner = self.ctx.interner;
+        let Some(res) = res else {
+            return Ty::new_error(self.ctx.interner, ErrorGuaranteed);
+        };
+        let def = self.ctx.def;
+        let segment = self.current_or_prev_segment;
+        let assoc_name = segment.name;
+        let check_alias = |name: &Name, t: TraitRef<'db>, associated_ty: TypeAliasId| {
+            if name != assoc_name {
+                return None;
+            }
+
+            // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
+            // generic params. It's inefficient to splice the `Substitution`s, so we may want
+            // that method to optionally take parent `Substitution` as we already know them at
+            // this point (`t.substitution`).
+            let substs =
+                self.substs_from_path_segment(associated_ty.into(), infer_args, None, true);
+
+            let substs = GenericArgs::new_from_iter(
+                interner,
+                t.args.iter().chain(substs.iter().skip(t.args.len())),
+            );
+
+            Some(Ty::new_alias(
+                interner,
+                AliasTyKind::Projection,
+                AliasTy::new(interner, associated_ty.into(), substs),
+            ))
+        };
+        named_associated_type_shorthand_candidates(
+            interner,
+            def,
+            res,
+            Some(assoc_name.clone()),
+            check_alias,
+        )
+        .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed))
+    }
+
+    fn lower_path_inner(&mut self, typeable: TyDefId, infer_args: bool) -> Ty<'db> {
         let generic_def = match typeable {
-            TyDefId::BuiltinType(builtin) => return TyBuilder::builtin(builtin),
+            TyDefId::BuiltinType(builtinty) => {
+                return Ty::from_builtin_type(self.ctx.interner, builtinty);
+            }
             TyDefId::AdtId(it) => it.into(),
             TyDefId::TypeAliasId(it) => it.into(),
         };
-        let substs = self.substs_from_path_segment(generic_def, infer_args, None, false);
-        let interner = DbInterner::conjure();
-        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
-        self.ctx.db.ty(typeable).instantiate(interner, args).to_chalk(interner)
+        let args = self.substs_from_path_segment(generic_def, infer_args, None, false);
+        let ty = ty_query(self.ctx.db, typeable);
+        ty.instantiate(self.ctx.interner, args)
+    }
+
+    /// Collect generic arguments from a path into a `Substs`. See also
+    /// `create_substs_for_ast_path` and `def_to_ty` in rustc.
+    pub(crate) fn substs_from_path(
+        &mut self,
+        // Note that we don't call `db.value_type(resolved)` here,
+        // `ValueTyDefId` is just a convenient way to pass generics and
+        // special-case enum variants
+        resolved: ValueTyDefId,
+        infer_args: bool,
+        lowering_assoc_type_generics: bool,
+    ) -> GenericArgs<'db> {
+        let interner = self.ctx.interner;
+        let prev_current_segment_idx = self.current_segment_idx;
+        let prev_current_segment = self.current_or_prev_segment;
+
+        let generic_def = match resolved {
+            ValueTyDefId::FunctionId(it) => it.into(),
+            ValueTyDefId::StructId(it) => it.into(),
+            ValueTyDefId::UnionId(it) => it.into(),
+            ValueTyDefId::ConstId(it) => it.into(),
+            ValueTyDefId::StaticId(_) => {
+                return GenericArgs::new_from_iter(interner, []);
+            }
+            ValueTyDefId::EnumVariantId(var) => {
+                // the generic args for an enum variant may be either specified
+                // on the segment referring to the enum, or on the segment
+                // referring to the variant. So `Option::<T>::None` and
+                // `Option::None::<T>` are both allowed (though the former is
+                // FIXME: This isn't strictly correct, enum variants may be used not through the enum
+                // (via `use Enum::Variant`). The resolver returns whether they were, but we don't have its result
+                // available here. The worst that can happen is that we will show some confusing diagnostics to the user,
+                // if generics exist on the module and they don't match with the variant.
+                // preferred). See also `def_ids_for_path_segments` in rustc.
+                //
+                // `wrapping_sub(1)` will return a number which `get` will return None for if current_segment_idx<2.
+                // This simplifies the code a bit.
+                let penultimate_idx = self.current_segment_idx.wrapping_sub(1);
+                let penultimate = self.segments.get(penultimate_idx);
+                if let Some(penultimate) = penultimate
+                    && self.current_or_prev_segment.args_and_bindings.is_none()
+                    && penultimate.args_and_bindings.is_some()
+                {
+                    self.current_segment_idx = penultimate_idx;
+                    self.current_or_prev_segment = penultimate;
+                }
+                var.lookup(self.ctx.db).parent.into()
+            }
+        };
+        let result = self.substs_from_path_segment(
+            generic_def,
+            infer_args,
+            None,
+            lowering_assoc_type_generics,
+        );
+        self.current_segment_idx = prev_current_segment_idx;
+        self.current_or_prev_segment = prev_current_segment;
+        result
     }
 
     pub(crate) fn substs_from_path_segment(
         &mut self,
         def: GenericDefId,
         infer_args: bool,
-        explicit_self_ty: Option<Ty>,
+        explicit_self_ty: Option<Ty<'db>>,
         lowering_assoc_type_generics: bool,
-    ) -> Substitution {
+    ) -> GenericArgs<'db> {
         let old_lifetime_elision = self.ctx.lifetime_elision.clone();
 
         if let Some(args) = self.current_or_prev_segment.args_and_bindings
@@ -478,7 +626,7 @@
                     PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment },
                 );
 
-                return TyBuilder::unknown_subst(self.ctx.db, def);
+                return unknown_subst(self.ctx.interner, def);
             }
 
             // `Fn()`-style generics are treated like functions for the purpose of lifetime elision.
@@ -501,20 +649,20 @@
 
     pub(super) fn substs_from_args_and_bindings(
         &mut self,
-        args_and_bindings: Option<&GenericArgs>,
+        args_and_bindings: Option<&HirGenericArgs>,
         def: GenericDefId,
         infer_args: bool,
-        explicit_self_ty: Option<Ty>,
+        explicit_self_ty: Option<Ty<'db>>,
         generics_source: PathGenericsSource,
         lowering_assoc_type_generics: bool,
-        lifetime_elision: LifetimeElisionKind,
-    ) -> Substitution {
-        struct LowererCtx<'a, 'b, 'c> {
-            ctx: &'a mut PathLoweringContext<'b, 'c>,
+        lifetime_elision: LifetimeElisionKind<'db>,
+    ) -> GenericArgs<'db> {
+        struct LowererCtx<'a, 'b, 'c, 'db> {
+            ctx: &'a mut PathLoweringContext<'b, 'c, 'db>,
             generics_source: PathGenericsSource,
         }
 
-        impl GenericArgsLowerer for LowererCtx<'_, '_, '_> {
+        impl<'db> GenericArgsLowerer<'db> for LowererCtx<'_, '_, '_, 'db> {
             fn report_len_mismatch(
                 &mut self,
                 def: GenericDefId,
@@ -549,23 +697,24 @@
                 &mut self,
                 param_id: GenericParamId,
                 param: GenericParamDataRef<'_>,
-                arg: &GenericArg,
-            ) -> crate::GenericArg {
-                match (param, arg) {
-                    (GenericParamDataRef::LifetimeParamData(_), GenericArg::Lifetime(lifetime)) => {
-                        self.ctx.ctx.lower_lifetime(*lifetime).cast(Interner)
+                arg: &HirGenericArg,
+            ) -> GenericArg<'db> {
+                match (param, *arg) {
+                    (
+                        GenericParamDataRef::LifetimeParamData(_),
+                        HirGenericArg::Lifetime(lifetime),
+                    ) => self.ctx.ctx.lower_lifetime(lifetime).into(),
+                    (GenericParamDataRef::TypeParamData(_), HirGenericArg::Type(type_ref)) => {
+                        self.ctx.ctx.lower_ty(type_ref).into()
                     }
-                    (GenericParamDataRef::TypeParamData(_), GenericArg::Type(type_ref)) => {
-                        self.ctx.ctx.lower_ty(*type_ref).cast(Interner)
-                    }
-                    (GenericParamDataRef::ConstParamData(_), GenericArg::Const(konst)) => {
+                    (GenericParamDataRef::ConstParamData(_), HirGenericArg::Const(konst)) => {
                         let GenericParamId::ConstParamId(const_id) = param_id else {
                             unreachable!("non-const param ID for const param");
                         };
                         self.ctx
                             .ctx
-                            .lower_const(konst, self.ctx.ctx.db.const_param_ty(const_id))
-                            .cast(Interner)
+                            .lower_const(konst, const_param_ty_query(self.ctx.ctx.db, const_id))
+                            .into()
                     }
                     _ => unreachable!("unmatching param kinds were passed to `provided_kind()`"),
                 }
@@ -573,9 +722,9 @@
 
             fn provided_type_like_const(
                 &mut self,
-                const_ty: Ty,
+                const_ty: Ty<'db>,
                 arg: TypeLikeConst<'_>,
-            ) -> crate::Const {
+            ) -> Const<'db> {
                 match arg {
                     TypeLikeConst::Path(path) => self.ctx.ctx.lower_path_as_const(path, const_ty),
                     TypeLikeConst::Infer => unknown_const(const_ty),
@@ -588,18 +737,19 @@
                 param_id: GenericParamId,
                 param: GenericParamDataRef<'_>,
                 infer_args: bool,
-                preceding_args: &[crate::GenericArg],
-            ) -> crate::GenericArg {
-                let default = || {
-                    self.ctx
-                        .ctx
-                        .db
-                        .generic_defaults(def)
-                        .get(preceding_args.len())
-                        .map(|default| default.clone().substitute(Interner, preceding_args))
-                };
+                preceding_args: &[GenericArg<'db>],
+            ) -> GenericArg<'db> {
+                let default =
+                    || {
+                        self.ctx.ctx.db.generic_defaults(def).get(preceding_args.len()).map(
+                            |default| default.instantiate(self.ctx.ctx.interner, preceding_args),
+                        )
+                    };
                 match param {
-                    GenericParamDataRef::LifetimeParamData(_) => error_lifetime().cast(Interner),
+                    GenericParamDataRef::LifetimeParamData(_) => {
+                        Region::new(self.ctx.ctx.interner, rustc_type_ir::ReError(ErrorGuaranteed))
+                            .into()
+                    }
                     GenericParamDataRef::TypeParamData(param) => {
                         if !infer_args
                             && param.default.is_some()
@@ -607,7 +757,7 @@
                         {
                             return default;
                         }
-                        TyKind::Error.intern(Interner).cast(Interner)
+                        Ty::new_error(self.ctx.ctx.interner, ErrorGuaranteed).into()
                     }
                     GenericParamDataRef::ConstParamData(param) => {
                         if !infer_args
@@ -619,19 +769,23 @@
                         let GenericParamId::ConstParamId(const_id) = param_id else {
                             unreachable!("non-const param ID for const param");
                         };
-                        unknown_const_as_generic(self.ctx.ctx.db.const_param_ty(const_id))
-                            .cast(Interner)
+                        unknown_const_as_generic(const_param_ty_query(self.ctx.ctx.db, const_id))
                     }
                 }
             }
 
-            fn parent_arg(&mut self, param_id: GenericParamId) -> crate::GenericArg {
+            fn parent_arg(&mut self, param_id: GenericParamId) -> GenericArg<'db> {
                 match param_id {
-                    GenericParamId::TypeParamId(_) => TyKind::Error.intern(Interner).cast(Interner),
-                    GenericParamId::ConstParamId(const_id) => {
-                        unknown_const_as_generic(self.ctx.ctx.db.const_param_ty(const_id))
+                    GenericParamId::TypeParamId(_) => {
+                        Ty::new_error(self.ctx.ctx.interner, ErrorGuaranteed).into()
                     }
-                    GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner),
+                    GenericParamId::ConstParamId(const_id) => {
+                        unknown_const_as_generic(const_param_ty_query(self.ctx.ctx.db, const_id))
+                    }
+                    GenericParamId::LifetimeParamId(_) => {
+                        Region::new(self.ctx.ctx.interner, rustc_type_ir::ReError(ErrorGuaranteed))
+                            .into()
+                    }
                 }
             }
 
@@ -649,6 +803,14 @@
                 });
             }
 
+            fn report_elision_failure(&mut self, def: GenericDefId, expected_count: u32) {
+                self.ctx.on_diagnostic(PathLoweringDiagnostic::ElisionFailure {
+                    generics_source: self.generics_source,
+                    def,
+                    expected_count,
+                });
+            }
+
             fn report_missing_lifetime(&mut self, def: GenericDefId, expected_count: u32) {
                 self.ctx.on_diagnostic(PathLoweringDiagnostic::MissingLifetime {
                     generics_source: self.generics_source,
@@ -674,38 +836,39 @@
     pub(crate) fn lower_trait_ref_from_resolved_path(
         &mut self,
         resolved: TraitId,
-        explicit_self_ty: Ty,
+        explicit_self_ty: Ty<'db>,
         infer_args: bool,
-    ) -> TraitRef {
-        let substs = self.trait_ref_substs_from_path(resolved, explicit_self_ty, infer_args);
-        TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs }
+    ) -> TraitRef<'db> {
+        let args = self.trait_ref_substs_from_path(resolved, explicit_self_ty, infer_args);
+        TraitRef::new_from_args(self.ctx.interner, resolved.into(), args)
     }
 
     fn trait_ref_substs_from_path(
         &mut self,
         resolved: TraitId,
-        explicit_self_ty: Ty,
+        explicit_self_ty: Ty<'db>,
         infer_args: bool,
-    ) -> Substitution {
+    ) -> GenericArgs<'db> {
         self.substs_from_path_segment(resolved.into(), infer_args, Some(explicit_self_ty), false)
     }
 
     pub(super) fn assoc_type_bindings_from_type_bound<'c>(
         mut self,
-        trait_ref: TraitRef,
-    ) -> Option<impl Iterator<Item = QuantifiedWhereClause> + use<'a, 'b, 'c>> {
+        trait_ref: TraitRef<'db>,
+    ) -> Option<impl Iterator<Item = Clause<'db>> + use<'a, 'b, 'c, 'db>> {
+        let interner = self.ctx.interner;
         self.current_or_prev_segment.args_and_bindings.map(|args_and_bindings| {
             args_and_bindings.bindings.iter().enumerate().flat_map(move |(binding_idx, binding)| {
                 let found = associated_type_by_name_including_super_traits(
                     self.ctx.db,
-                    trait_ref.clone(),
+                    trait_ref,
                     &binding.name,
                 );
                 let (super_trait_ref, associated_ty) = match found {
                     None => return SmallVec::new(),
                     Some(t) => t,
                 };
-                let substitution =
+                let args =
                     self.with_lifetime_elision(LifetimeElisionKind::AnonymousReportError, |this| {
                         // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
                         // generic params. It's inefficient to splice the `Substitution`s, so we may want
@@ -715,7 +878,7 @@
                             binding.args.as_ref(),
                             associated_ty.into(),
                             false, // this is not relevant
-                            Some(super_trait_ref.self_type_parameter(Interner)),
+                            Some(super_trait_ref.self_ty()),
                             PathGenericsSource::AssocType {
                                 segment: this.current_segment_u32(),
                                 assoc_type: binding_idx as u32,
@@ -724,27 +887,20 @@
                             this.ctx.lifetime_elision.clone(),
                         )
                     });
-                let substitution = Substitution::from_iter(
-                    Interner,
-                    super_trait_ref.substitution.iter(Interner).chain(
-                        substitution
-                            .iter(Interner)
-                            .skip(super_trait_ref.substitution.len(Interner)),
-                    ),
+                let args = GenericArgs::new_from_iter(
+                    interner,
+                    super_trait_ref.args.iter().chain(args.iter().skip(super_trait_ref.args.len())),
                 );
-                let projection_ty = ProjectionTy {
-                    associated_ty_id: to_assoc_type_id(associated_ty),
-                    substitution,
-                };
+                let projection_term =
+                    AliasTerm::new_from_args(interner, associated_ty.into(), args);
                 let mut predicates: SmallVec<[_; 1]> = SmallVec::with_capacity(
                     binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
                 );
-
                 if let Some(type_ref) = binding.type_ref {
                     let lifetime_elision =
                         if args_and_bindings.parenthesized == GenericArgsParentheses::ParenSugar {
                             // `Fn()`-style generics are elided like functions. This is `Output` (we lower to it in hir-def).
-                            LifetimeElisionKind::for_fn_ret()
+                            LifetimeElisionKind::for_fn_ret(self.ctx.interner)
                         } else {
                             self.ctx.lifetime_elision.clone()
                         };
@@ -756,31 +912,33 @@
                                 ImplTraitLoweringMode::Disallowed | ImplTraitLoweringMode::Opaque,
                             ) => {
                                 let ty = this.ctx.lower_ty(type_ref);
-                                let alias_eq = AliasEq {
-                                    alias: AliasTy::Projection(projection_ty.clone()),
-                                    ty,
-                                };
-                                predicates.push(crate::wrap_empty_binders(WhereClause::AliasEq(
-                                    alias_eq,
-                                )));
+                                let pred = Clause(Predicate::new(
+                                    interner,
+                                    Binder::dummy(rustc_type_ir::PredicateKind::Clause(
+                                        rustc_type_ir::ClauseKind::Projection(
+                                            ProjectionPredicate {
+                                                projection_term,
+                                                term: ty.into(),
+                                            },
+                                        ),
+                                    )),
+                                ));
+                                predicates.push(pred);
                             }
                         }
-                    });
+                    })
                 }
-
-                self.with_lifetime_elision(LifetimeElisionKind::AnonymousReportError, |this| {
-                    for bound in binding.bounds.iter() {
-                        predicates.extend(
-                            this.ctx.lower_type_bound(
-                                bound,
-                                TyKind::Alias(AliasTy::Projection(projection_ty.clone()))
-                                    .intern(Interner),
-                                false,
-                            ),
-                        );
-                    }
-                });
-
+                for bound in binding.bounds.iter() {
+                    predicates.extend(self.ctx.lower_type_bound(
+                        bound,
+                        Ty::new_alias(
+                            self.ctx.interner,
+                            AliasTyKind::Projection,
+                            AliasTy::new_from_args(self.ctx.interner, associated_ty.into(), args),
+                        ),
+                        false,
+                    ));
+                }
                 predicates
             })
         })
@@ -793,7 +951,7 @@
     Path(&'a Path),
 }
 
-pub(crate) trait GenericArgsLowerer {
+pub(crate) trait GenericArgsLowerer<'db> {
     fn report_elided_lifetimes_in_path(
         &mut self,
         def: GenericDefId,
@@ -801,6 +959,8 @@
         hard_error: bool,
     );
 
+    fn report_elision_failure(&mut self, def: GenericDefId, expected_count: u32);
+
     fn report_missing_lifetime(&mut self, def: GenericDefId, expected_count: u32);
 
     fn report_len_mismatch(
@@ -817,10 +977,11 @@
         &mut self,
         param_id: GenericParamId,
         param: GenericParamDataRef<'_>,
-        arg: &GenericArg,
-    ) -> crate::GenericArg;
+        arg: &HirGenericArg,
+    ) -> GenericArg<'db>;
 
-    fn provided_type_like_const(&mut self, const_ty: Ty, arg: TypeLikeConst<'_>) -> crate::Const;
+    fn provided_type_like_const(&mut self, const_ty: Ty<'db>, arg: TypeLikeConst<'_>)
+    -> Const<'db>;
 
     fn inferred_kind(
         &mut self,
@@ -828,21 +989,21 @@
         param_id: GenericParamId,
         param: GenericParamDataRef<'_>,
         infer_args: bool,
-        preceding_args: &[crate::GenericArg],
-    ) -> crate::GenericArg;
+        preceding_args: &[GenericArg<'db>],
+    ) -> GenericArg<'db>;
 
-    fn parent_arg(&mut self, param_id: GenericParamId) -> crate::GenericArg;
+    fn parent_arg(&mut self, param_id: GenericParamId) -> GenericArg<'db>;
 }
 
 /// Returns true if there was an error.
-fn check_generic_args_len(
-    args_and_bindings: Option<&GenericArgs>,
+fn check_generic_args_len<'db>(
+    args_and_bindings: Option<&HirGenericArgs>,
     def: GenericDefId,
     def_generics: &Generics,
     infer_args: bool,
-    lifetime_elision: &LifetimeElisionKind,
+    lifetime_elision: &LifetimeElisionKind<'db>,
     lowering_assoc_type_generics: bool,
-    ctx: &mut impl GenericArgsLowerer,
+    ctx: &mut impl GenericArgsLowerer<'db>,
 ) -> bool {
     let mut had_error = false;
 
@@ -851,8 +1012,10 @@
         let args_no_self = &args_and_bindings.args[usize::from(args_and_bindings.has_self_type)..];
         for arg in args_no_self {
             match arg {
-                GenericArg::Lifetime(_) => provided_lifetimes_count += 1,
-                GenericArg::Type(_) | GenericArg::Const(_) => provided_types_and_consts_count += 1,
+                HirGenericArg::Lifetime(_) => provided_lifetimes_count += 1,
+                HirGenericArg::Type(_) | HirGenericArg::Const(_) => {
+                    provided_types_and_consts_count += 1
+                }
             }
         }
     }
@@ -873,6 +1036,13 @@
                 ctx.report_missing_lifetime(def, lifetime_args_len as u32);
                 had_error = true
             }
+            LifetimeElisionKind::ElisionFailure => {
+                ctx.report_elision_failure(def, lifetime_args_len as u32);
+                had_error = true;
+            }
+            LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: _ } => {
+                // FIXME: Check there are other lifetimes in scope, and error/lint.
+            }
             LifetimeElisionKind::Elided(_) => {
                 ctx.report_elided_lifetimes_in_path(def, lifetime_args_len as u32, false);
             }
@@ -919,17 +1089,21 @@
     had_error
 }
 
-pub(crate) fn substs_from_args_and_bindings(
-    db: &dyn HirDatabase,
+pub(crate) fn substs_from_args_and_bindings<'db>(
+    db: &'db dyn HirDatabase,
     store: &ExpressionStore,
-    args_and_bindings: Option<&GenericArgs>,
+    args_and_bindings: Option<&HirGenericArgs>,
     def: GenericDefId,
     mut infer_args: bool,
-    lifetime_elision: LifetimeElisionKind,
+    lifetime_elision: LifetimeElisionKind<'db>,
     lowering_assoc_type_generics: bool,
-    explicit_self_ty: Option<Ty>,
-    ctx: &mut impl GenericArgsLowerer,
-) -> Substitution {
+    explicit_self_ty: Option<Ty<'db>>,
+    ctx: &mut impl GenericArgsLowerer<'db>,
+) -> GenericArgs<'db> {
+    let interner = DbInterner::new_with(db, None, None);
+
+    tracing::debug!(?args_and_bindings);
+
     // Order is
     // - Parent parameters
     // - Optional Self parameter
@@ -940,7 +1114,7 @@
 
     // We do not allow inference if there are specified args, i.e. we do not allow partial inference.
     let has_non_lifetime_args =
-        args_slice.iter().any(|arg| !matches!(arg, GenericArg::Lifetime(_)));
+        args_slice.iter().any(|arg| !matches!(arg, HirGenericArg::Lifetime(_)));
     infer_args &= !has_non_lifetime_args;
 
     let had_count_error = check_generic_args_len(
@@ -981,7 +1155,7 @@
             let (_, self_ty) = args.next().expect("has_self_type=true, should have Self type");
             ctx.provided_kind(self_param_id, self_param, self_ty)
         } else {
-            explicit_self_ty.map(|it| it.cast(Interner)).unwrap_or_else(|| {
+            explicit_self_ty.map(|it| it.into()).unwrap_or_else(|| {
                 ctx.inferred_kind(def, self_param_id, self_param, infer_args, &substs)
             })
         };
@@ -996,7 +1170,7 @@
         // input. We try to handle both sensibly.
         match (args.peek(), params.peek()) {
             (Some(&(arg_idx, arg)), Some(&(param_id, param))) => match (arg, param) {
-                (GenericArg::Type(_), GenericParamDataRef::TypeParamData(type_param))
+                (HirGenericArg::Type(_), GenericParamDataRef::TypeParamData(type_param))
                     if type_param.provenance == TypeParamProvenance::ArgumentImplTrait =>
                 {
                     // Do not allow specifying `impl Trait` explicitly. We already err at that, but if we won't handle it here
@@ -1004,15 +1178,15 @@
                     substs.push(ctx.inferred_kind(def, param_id, param, infer_args, &substs));
                     params.next();
                 }
-                (GenericArg::Lifetime(_), GenericParamDataRef::LifetimeParamData(_))
-                | (GenericArg::Type(_), GenericParamDataRef::TypeParamData(_))
-                | (GenericArg::Const(_), GenericParamDataRef::ConstParamData(_)) => {
+                (HirGenericArg::Lifetime(_), GenericParamDataRef::LifetimeParamData(_))
+                | (HirGenericArg::Type(_), GenericParamDataRef::TypeParamData(_))
+                | (HirGenericArg::Const(_), GenericParamDataRef::ConstParamData(_)) => {
                     substs.push(ctx.provided_kind(param_id, param, arg));
                     args.next();
                     params.next();
                 }
                 (
-                    GenericArg::Type(_) | GenericArg::Const(_),
+                    HirGenericArg::Type(_) | HirGenericArg::Const(_),
                     GenericParamDataRef::LifetimeParamData(_),
                 ) => {
                     // We expected a lifetime argument, but got a type or const
@@ -1021,13 +1195,13 @@
                     params.next();
                     force_infer_lt = Some((arg_idx as u32, param_id));
                 }
-                (GenericArg::Type(type_ref), GenericParamDataRef::ConstParamData(_)) => {
+                (HirGenericArg::Type(type_ref), GenericParamDataRef::ConstParamData(_)) => {
                     if let Some(konst) = type_looks_like_const(store, *type_ref) {
                         let GenericParamId::ConstParamId(param_id) = param_id else {
                             panic!("unmatching param kinds");
                         };
-                        let const_ty = db.const_param_ty(param_id);
-                        substs.push(ctx.provided_type_like_const(const_ty, konst).cast(Interner));
+                        let const_ty = const_param_ty_query(db, param_id);
+                        substs.push(ctx.provided_type_like_const(const_ty, konst).into());
                         args.next();
                         params.next();
                     } else {
@@ -1066,7 +1240,7 @@
                 //     after a type or const). We want to throw an error in this case.
                 if !had_count_error {
                     assert!(
-                        matches!(arg, GenericArg::Lifetime(_)),
+                        matches!(arg, HirGenericArg::Lifetime(_)),
                         "the only possible situation here is incorrect lifetime order"
                     );
                     let (provided_arg_idx, param_id) =
@@ -1081,12 +1255,16 @@
                 // If there are fewer arguments than parameters, it means we're inferring the remaining arguments.
                 let param = if let GenericParamId::LifetimeParamId(_) = param_id {
                     match &lifetime_elision {
-                        LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }
+                        LifetimeElisionKind::ElisionFailure
+                        | LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }
                         | LifetimeElisionKind::AnonymousReportError => {
                             assert!(had_count_error);
                             ctx.inferred_kind(def, param_id, param, infer_args, &substs)
                         }
-                        LifetimeElisionKind::Elided(lifetime) => lifetime.clone().cast(Interner),
+                        LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: _ } => {
+                            Region::new_static(interner).into()
+                        }
+                        LifetimeElisionKind::Elided(lifetime) => (*lifetime).into(),
                         LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false }
                         | LifetimeElisionKind::Infer => {
                             // FIXME: With `AnonymousCreateParameter`, we need to create a new lifetime parameter here
@@ -1105,7 +1283,7 @@
         }
     }
 
-    Substitution::from_iter(Interner, substs)
+    GenericArgs::new_from_iter(interner, substs)
 }
 
 fn type_looks_like_const(
@@ -1124,3 +1302,17 @@
         _ => None,
     }
 }
+
+fn unknown_subst<'db>(interner: DbInterner<'db>, def: impl Into<GenericDefId>) -> GenericArgs<'db> {
+    let params = generics(interner.db(), def.into());
+    GenericArgs::new_from_iter(
+        interner,
+        params.iter_id().map(|id| match id {
+            GenericParamId::TypeParamId(_) => Ty::new_error(interner, ErrorGuaranteed).into(),
+            GenericParamId::ConstParamId(id) => {
+                unknown_const_as_generic(const_param_ty_query(interner.db(), id))
+            }
+            GenericParamId::LifetimeParamId(_) => Region::error(interner).into(),
+        }),
+    )
+}
diff --git a/crates/hir-ty/src/lower_nextsolver.rs b/crates/hir-ty/src/lower_nextsolver.rs
deleted file mode 100644
index abca6b6..0000000
--- a/crates/hir-ty/src/lower_nextsolver.rs
+++ /dev/null
@@ -1,2220 +0,0 @@
-//! Methods for lowering the HIR to types. There are two main cases here:
-//!
-//!  - Lowering a type reference like `&usize` or `Option<foo::bar::Baz>` to a
-//!    type: The entry point for this is `TyLoweringContext::lower_ty`.
-//!  - Building the type for an item: This happens through the `ty` query.
-//!
-//! This usually involves resolving names, collecting generic arguments etc.
-#![allow(unused)]
-// FIXME(next-solver): this should get removed as things get moved to rustc_type_ir from chalk_ir
-pub(crate) mod path;
-
-use std::{
-    cell::OnceCell,
-    iter, mem,
-    ops::{self, Deref, Not as _},
-};
-
-use base_db::Crate;
-use either::Either;
-use hir_def::hir::generics::GenericParamDataRef;
-use hir_def::item_tree::FieldsShape;
-use hir_def::{
-    AdtId, AssocItemId, CallableDefId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId,
-    GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup,
-    StructId, TraitId, TypeAliasId, TypeOrConstParamId, VariantId,
-    expr_store::{
-        ExpressionStore,
-        path::{GenericArg, Path},
-    },
-    hir::generics::{TypeOrConstParamData, WherePredicate},
-    lang_item::LangItem,
-    resolver::{HasResolver, LifetimeNs, Resolver, TypeNs},
-    signatures::{FunctionSignature, TraitFlags, TypeAliasFlags},
-    type_ref::{
-        ConstRef, LifetimeRefId, LiteralConstRef, PathId, TraitBoundModifier,
-        TraitRef as HirTraitRef, TypeBound, TypeRef, TypeRefId,
-    },
-};
-use hir_def::{ConstId, LifetimeParamId, StaticId, TypeParamId};
-use hir_expand::name::Name;
-use intern::{Symbol, sym};
-use la_arena::{Arena, ArenaMap, Idx};
-use path::{PathDiagnosticCallback, PathLoweringContext};
-use rustc_ast_ir::Mutability;
-use rustc_hash::FxHashSet;
-use rustc_pattern_analysis::Captures;
-use rustc_type_ir::{
-    AliasTyKind, ConstKind, DebruijnIndex, ExistentialPredicate, ExistentialProjection,
-    ExistentialTraitRef, FnSig, OutlivesPredicate,
-    TyKind::{self},
-    TypeVisitableExt,
-    inherent::{GenericArg as _, GenericArgs as _, IntoKind as _, Region as _, SliceLike, Ty as _},
-};
-use rustc_type_ir::{TypeFoldable, TypeFolder, Upcast};
-use salsa::plumbing::AsId;
-use smallvec::{SmallVec, smallvec};
-use stdx::never;
-use triomphe::Arc;
-
-use crate::ValueTyDefId;
-use crate::next_solver::ParamConst;
-use crate::{
-    FnAbi, ImplTraitId, Interner, ParamKind, TraitEnvironment, TyDefId, TyLoweringDiagnostic,
-    TyLoweringDiagnosticKind,
-    consteval::{intern_const_ref, path_to_const, unknown_const_as_generic},
-    db::HirDatabase,
-    generics::{Generics, generics, trait_self_param_idx},
-    lower::{Diagnostics, PathDiagnosticCallbackData, create_diagnostics},
-    next_solver::{
-        AdtDef, AliasTy, Binder, BoundExistentialPredicates, BoundRegionKind, BoundTyKind,
-        BoundVarKind, BoundVarKinds, Clause, Clauses, Const, DbInterner, EarlyBinder,
-        EarlyParamRegion, ErrorGuaranteed, GenericArgs, ParamEnv, PolyFnSig, Predicate, Region,
-        SolverDefId, TraitPredicate, TraitRef, Ty, Tys,
-        abi::Safety,
-        mapping::{ChalkToNextSolver, convert_ty_for_result},
-    },
-};
-
-#[derive(PartialEq, Eq, Debug, Hash)]
-pub struct ImplTraits<'db> {
-    pub(crate) impl_traits: Arena<ImplTrait<'db>>,
-}
-
-#[derive(PartialEq, Eq, Debug, Hash)]
-pub struct ImplTrait<'db> {
-    pub(crate) predicates: Vec<Clause<'db>>,
-}
-
-pub type ImplTraitIdx<'db> = Idx<ImplTrait<'db>>;
-
-#[derive(Debug, Default)]
-struct ImplTraitLoweringState<'db> {
-    /// When turning `impl Trait` into opaque types, we have to collect the
-    /// bounds at the same time to get the IDs correct (without becoming too
-    /// complicated).
-    mode: ImplTraitLoweringMode,
-    // This is structured as a struct with fields and not as an enum because it helps with the borrow checker.
-    opaque_type_data: Arena<ImplTrait<'db>>,
-    param_and_variable_counter: u16,
-}
-impl<'db> ImplTraitLoweringState<'db> {
-    fn new(mode: ImplTraitLoweringMode) -> ImplTraitLoweringState<'db> {
-        Self { mode, opaque_type_data: Arena::new(), param_and_variable_counter: 0 }
-    }
-}
-
-#[derive(Debug, Clone)]
-pub enum LifetimeElisionKind<'db> {
-    /// Create a new anonymous lifetime parameter and reference it.
-    ///
-    /// If `report_in_path`, report an error when encountering lifetime elision in a path:
-    /// ```compile_fail
-    /// struct Foo<'a> { x: &'a () }
-    /// async fn foo(x: Foo) {}
-    /// ```
-    ///
-    /// Note: the error should not trigger when the elided lifetime is in a pattern or
-    /// expression-position path:
-    /// ```
-    /// struct Foo<'a> { x: &'a () }
-    /// async fn foo(Foo { x: _ }: Foo<'_>) {}
-    /// ```
-    AnonymousCreateParameter { report_in_path: bool },
-
-    /// Replace all anonymous lifetimes by provided lifetime.
-    Elided(Region<'db>),
-
-    /// Give a hard error when either `&` or `'_` is written. Used to
-    /// rule out things like `where T: Foo<'_>`. Does not imply an
-    /// error on default object bounds (e.g., `Box<dyn Foo>`).
-    AnonymousReportError,
-
-    /// Resolves elided lifetimes to `'static` if there are no other lifetimes in scope,
-    /// otherwise give a warning that the previous behavior of introducing a new early-bound
-    /// lifetime is a bug and will be removed (if `only_lint` is enabled).
-    StaticIfNoLifetimeInScope { only_lint: bool },
-
-    /// Signal we cannot find which should be the anonymous lifetime.
-    ElisionFailure,
-
-    /// Infer all elided lifetimes.
-    Infer,
-}
-
-impl<'db> LifetimeElisionKind<'db> {
-    #[inline]
-    pub(crate) fn for_const(
-        interner: DbInterner<'db>,
-        const_parent: ItemContainerId,
-    ) -> LifetimeElisionKind<'db> {
-        match const_parent {
-            ItemContainerId::ExternBlockId(_) | ItemContainerId::ModuleId(_) => {
-                LifetimeElisionKind::Elided(Region::new_static(interner))
-            }
-            ItemContainerId::ImplId(_) => {
-                LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: true }
-            }
-            ItemContainerId::TraitId(_) => {
-                LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: false }
-            }
-        }
-    }
-
-    #[inline]
-    pub(crate) fn for_fn_params(data: &FunctionSignature) -> LifetimeElisionKind<'db> {
-        LifetimeElisionKind::AnonymousCreateParameter { report_in_path: data.is_async() }
-    }
-
-    #[inline]
-    pub(crate) fn for_fn_ret(interner: DbInterner<'db>) -> LifetimeElisionKind<'db> {
-        // FIXME: We should use the elided lifetime here, or `ElisionFailure`.
-        LifetimeElisionKind::Elided(Region::error(interner))
-    }
-}
-
-#[derive(Debug)]
-pub struct TyLoweringContext<'db, 'a> {
-    pub db: &'db dyn HirDatabase,
-    interner: DbInterner<'db>,
-    resolver: &'a Resolver<'db>,
-    store: &'a ExpressionStore,
-    def: GenericDefId,
-    generics: OnceCell<Generics>,
-    in_binders: DebruijnIndex,
-    impl_trait_mode: ImplTraitLoweringState<'db>,
-    /// Tracks types with explicit `?Sized` bounds.
-    pub(crate) unsized_types: FxHashSet<Ty<'db>>,
-    pub(crate) diagnostics: Vec<TyLoweringDiagnostic>,
-    lifetime_elision: LifetimeElisionKind<'db>,
-    /// We disallow referencing generic parameters that have an index greater than or equal to this number.
-    disallow_params_after: u32,
-}
-
-impl<'db, 'a> TyLoweringContext<'db, 'a> {
-    pub fn new(
-        db: &'db dyn HirDatabase,
-        resolver: &'a Resolver<'db>,
-        store: &'a ExpressionStore,
-        def: GenericDefId,
-        lifetime_elision: LifetimeElisionKind<'db>,
-    ) -> Self {
-        let impl_trait_mode = ImplTraitLoweringState::new(ImplTraitLoweringMode::Disallowed);
-        let in_binders = DebruijnIndex::ZERO;
-        Self {
-            db,
-            interner: DbInterner::new_with(db, Some(resolver.krate()), None),
-            resolver,
-            def,
-            generics: Default::default(),
-            store,
-            in_binders,
-            impl_trait_mode,
-            unsized_types: FxHashSet::default(),
-            diagnostics: Vec::new(),
-            lifetime_elision,
-            disallow_params_after: u32::MAX,
-        }
-    }
-
-    pub(crate) fn set_lifetime_elision(&mut self, lifetime_elision: LifetimeElisionKind<'db>) {
-        self.lifetime_elision = lifetime_elision;
-    }
-
-    pub(crate) fn with_debruijn<T>(
-        &mut self,
-        debruijn: DebruijnIndex,
-        f: impl FnOnce(&mut TyLoweringContext<'db, '_>) -> T,
-    ) -> T {
-        let old_debruijn = mem::replace(&mut self.in_binders, debruijn);
-        let result = f(self);
-        self.in_binders = old_debruijn;
-        result
-    }
-
-    pub(crate) fn with_shifted_in<T>(
-        &mut self,
-        debruijn: DebruijnIndex,
-        f: impl FnOnce(&mut TyLoweringContext<'db, '_>) -> T,
-    ) -> T {
-        self.with_debruijn(self.in_binders.shifted_in(debruijn.as_u32()), f)
-    }
-
-    pub(crate) fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self {
-        Self { impl_trait_mode: ImplTraitLoweringState::new(impl_trait_mode), ..self }
-    }
-
-    pub(crate) fn impl_trait_mode(&mut self, impl_trait_mode: ImplTraitLoweringMode) -> &mut Self {
-        self.impl_trait_mode = ImplTraitLoweringState::new(impl_trait_mode);
-        self
-    }
-
-    pub(crate) fn disallow_params_after(&mut self, after: u32) {
-        self.disallow_params_after = after;
-    }
-
-    pub(crate) fn push_diagnostic(&mut self, type_ref: TypeRefId, kind: TyLoweringDiagnosticKind) {
-        self.diagnostics.push(TyLoweringDiagnostic { source: type_ref, kind });
-    }
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
-pub(crate) enum ImplTraitLoweringMode {
-    /// `impl Trait` gets lowered into an opaque type that doesn't unify with
-    /// anything except itself. This is used in places where values flow 'out',
-    /// i.e. for arguments of the function we're currently checking, and return
-    /// types of functions we're calling.
-    Opaque,
-    /// `impl Trait` is disallowed and will be an error.
-    #[default]
-    Disallowed,
-}
-
-impl<'db, 'a> TyLoweringContext<'db, 'a> {
-    pub fn lower_ty(&mut self, type_ref: TypeRefId) -> Ty<'db> {
-        self.lower_ty_ext(type_ref).0
-    }
-
-    pub(crate) fn lower_const(&mut self, const_ref: ConstRef, const_type: Ty<'db>) -> Const<'db> {
-        let const_ref = &self.store[const_ref.expr];
-        match const_ref {
-            hir_def::hir::Expr::Path(path) => {
-                path_to_const(self.db, self.resolver, path, || self.generics(), const_type)
-                    .unwrap_or_else(|| unknown_const(const_type))
-            }
-            hir_def::hir::Expr::Literal(literal) => intern_const_ref(
-                self.db,
-                &match *literal {
-                    hir_def::hir::Literal::Float(_, _)
-                    | hir_def::hir::Literal::String(_)
-                    | hir_def::hir::Literal::ByteString(_)
-                    | hir_def::hir::Literal::CString(_) => LiteralConstRef::Unknown,
-                    hir_def::hir::Literal::Char(c) => LiteralConstRef::Char(c),
-                    hir_def::hir::Literal::Bool(b) => LiteralConstRef::Bool(b),
-                    hir_def::hir::Literal::Int(val, _) => LiteralConstRef::Int(val),
-                    hir_def::hir::Literal::Uint(val, _) => LiteralConstRef::UInt(val),
-                },
-                const_type,
-                self.resolver.krate(),
-            ),
-            hir_def::hir::Expr::UnaryOp { expr: inner_expr, op: hir_def::hir::UnaryOp::Neg } => {
-                if let hir_def::hir::Expr::Literal(literal) = &self.store[*inner_expr] {
-                    // Only handle negation for signed integers and floats
-                    match literal {
-                        hir_def::hir::Literal::Int(_, _) | hir_def::hir::Literal::Float(_, _) => {
-                            if let Some(negated_literal) = literal.clone().negate() {
-                                intern_const_ref(
-                                    self.db,
-                                    &negated_literal.into(),
-                                    const_type,
-                                    self.resolver.krate(),
-                                )
-                            } else {
-                                unknown_const(const_type)
-                            }
-                        }
-                        // For unsigned integers, chars, bools, etc., negation is not meaningful
-                        _ => unknown_const(const_type),
-                    }
-                } else {
-                    unknown_const(const_type)
-                }
-            }
-            _ => unknown_const(const_type),
-        }
-    }
-
-    pub(crate) fn lower_path_as_const(&mut self, path: &Path, const_type: Ty<'db>) -> Const<'db> {
-        path_to_const(self.db, self.resolver, path, || self.generics(), const_type)
-            .unwrap_or_else(|| unknown_const(const_type))
-    }
-
-    fn generics(&self) -> &Generics {
-        self.generics.get_or_init(|| generics(self.db, self.def))
-    }
-
-    fn type_param(&mut self, id: TypeParamId, index: u32, name: Symbol) -> Ty<'db> {
-        if index >= self.disallow_params_after {
-            // FIXME: Report an error.
-            Ty::new_error(self.interner, ErrorGuaranteed)
-        } else {
-            Ty::new_param(self.interner, id, index, name)
-        }
-    }
-
-    fn const_param(&mut self, id: ConstParamId, index: u32) -> Const<'db> {
-        if index >= self.disallow_params_after {
-            // FIXME: Report an error.
-            Const::error(self.interner)
-        } else {
-            Const::new_param(self.interner, ParamConst { id, index })
-        }
-    }
-
-    fn region_param(&mut self, id: LifetimeParamId, index: u32) -> Region<'db> {
-        if index >= self.disallow_params_after {
-            // FIXME: Report an error.
-            Region::error(self.interner)
-        } else {
-            Region::new_early_param(self.interner, EarlyParamRegion { id, index })
-        }
-    }
-
-    #[tracing::instrument(skip(self), ret)]
-    pub fn lower_ty_ext(&mut self, type_ref_id: TypeRefId) -> (Ty<'db>, Option<TypeNs>) {
-        let interner = self.interner;
-        let mut res = None;
-        let type_ref = &self.store[type_ref_id];
-        tracing::debug!(?type_ref);
-        let ty = match type_ref {
-            TypeRef::Never => Ty::new(interner, TyKind::Never),
-            TypeRef::Tuple(inner) => {
-                let inner_tys = inner.iter().map(|&tr| self.lower_ty(tr));
-                Ty::new_tup_from_iter(interner, inner_tys)
-            }
-            TypeRef::Path(path) => {
-                let (ty, res_) =
-                    self.lower_path(path, PathId::from_type_ref_unchecked(type_ref_id));
-                res = res_;
-                ty
-            }
-            &TypeRef::TypeParam(type_param_id) => {
-                res = Some(TypeNs::GenericParam(type_param_id));
-
-                let generics = self.generics();
-                let (idx, data) =
-                    generics.type_or_const_param(type_param_id.into()).expect("matching generics");
-                let type_data = match data {
-                    TypeOrConstParamData::TypeParamData(ty) => ty,
-                    _ => unreachable!(),
-                };
-                self.type_param(
-                    type_param_id,
-                    idx as u32,
-                    type_data
-                        .name
-                        .as_ref()
-                        .map_or_else(|| sym::MISSING_NAME.clone(), |d| d.symbol().clone()),
-                )
-            }
-            &TypeRef::RawPtr(inner, mutability) => {
-                let inner_ty = self.lower_ty(inner);
-                Ty::new(interner, TyKind::RawPtr(inner_ty, lower_mutability(mutability)))
-            }
-            TypeRef::Array(array) => {
-                let inner_ty = self.lower_ty(array.ty);
-                let const_len = self.lower_const(array.len, Ty::new_usize(interner));
-                Ty::new_array_with_const_len(interner, inner_ty, const_len)
-            }
-            &TypeRef::Slice(inner) => {
-                let inner_ty = self.lower_ty(inner);
-                Ty::new_slice(interner, inner_ty)
-            }
-            TypeRef::Reference(ref_) => {
-                let inner_ty = self.lower_ty(ref_.ty);
-                // FIXME: It should infer the eldided lifetimes instead of stubbing with error
-                let lifetime = ref_
-                    .lifetime
-                    .map_or_else(|| Region::error(interner), |lr| self.lower_lifetime(lr));
-                Ty::new_ref(interner, lifetime, inner_ty, lower_mutability(ref_.mutability))
-            }
-            TypeRef::Placeholder => Ty::new_error(interner, ErrorGuaranteed),
-            TypeRef::Fn(fn_) => {
-                let substs = self.with_shifted_in(
-                    DebruijnIndex::from_u32(1),
-                    |ctx: &mut TyLoweringContext<'_, '_>| {
-                        Tys::new_from_iter(
-                            interner,
-                            fn_.params.iter().map(|&(_, tr)| ctx.lower_ty(tr)),
-                        )
-                    },
-                );
-                Ty::new_fn_ptr(
-                    interner,
-                    Binder::dummy(FnSig {
-                        abi: fn_.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol),
-                        safety: if fn_.is_unsafe { Safety::Unsafe } else { Safety::Safe },
-                        c_variadic: fn_.is_varargs,
-                        inputs_and_output: substs,
-                    }),
-                )
-            }
-            TypeRef::DynTrait(bounds) => self.lower_dyn_trait(bounds),
-            TypeRef::ImplTrait(bounds) => {
-                match self.impl_trait_mode.mode {
-                    ImplTraitLoweringMode::Opaque => {
-                        let origin = match self.resolver.generic_def() {
-                            Some(GenericDefId::FunctionId(it)) => Either::Left(it),
-                            Some(GenericDefId::TypeAliasId(it)) => Either::Right(it),
-                            _ => panic!(
-                                "opaque impl trait lowering must be in function or type alias"
-                            ),
-                        };
-
-                        // this dance is to make sure the data is in the right
-                        // place even if we encounter more opaque types while
-                        // lowering the bounds
-                        let idx = self
-                            .impl_trait_mode
-                            .opaque_type_data
-                            .alloc(ImplTrait { predicates: Vec::default() });
-
-                        // FIXME(next-solver): this from_raw/into_raw dance isn't nice, but it's minimal
-                        let impl_trait_id = origin.either(
-                            |f| ImplTraitId::ReturnTypeImplTrait(f, Idx::from_raw(idx.into_raw())),
-                            |a| ImplTraitId::TypeAliasImplTrait(a, Idx::from_raw(idx.into_raw())),
-                        );
-                        let opaque_ty_id: SolverDefId =
-                            self.db.intern_impl_trait_id(impl_trait_id).into();
-
-                        // We don't want to lower the bounds inside the binders
-                        // we're currently in, because they don't end up inside
-                        // those binders. E.g. when we have `impl Trait<impl
-                        // OtherTrait<T>>`, the `impl OtherTrait<T>` can't refer
-                        // to the self parameter from `impl Trait`, and the
-                        // bounds aren't actually stored nested within each
-                        // other, but separately. So if the `T` refers to a type
-                        // parameter of the outer function, it's just one binder
-                        // away instead of two.
-                        let actual_opaque_type_data = self
-                            .with_debruijn(DebruijnIndex::ZERO, |ctx| {
-                                ctx.lower_impl_trait(opaque_ty_id, bounds, self.resolver.krate())
-                            });
-                        self.impl_trait_mode.opaque_type_data[idx] = actual_opaque_type_data;
-
-                        let args = GenericArgs::identity_for_item(self.interner, opaque_ty_id);
-                        Ty::new_alias(
-                            self.interner,
-                            AliasTyKind::Opaque,
-                            AliasTy::new_from_args(self.interner, opaque_ty_id, args),
-                        )
-                    }
-                    ImplTraitLoweringMode::Disallowed => {
-                        // FIXME: report error
-                        Ty::new_error(self.interner, ErrorGuaranteed)
-                    }
-                }
-            }
-            TypeRef::Error => Ty::new_error(self.interner, ErrorGuaranteed),
-        };
-        (ty, res)
-    }
-
-    /// This is only for `generic_predicates_for_param`, where we can't just
-    /// lower the self types of the predicates since that could lead to cycles.
-    /// So we just check here if the `type_ref` resolves to a generic param, and which.
-    fn lower_ty_only_param(&self, type_ref: TypeRefId) -> Option<TypeOrConstParamId> {
-        let type_ref = &self.store[type_ref];
-        let path = match type_ref {
-            TypeRef::Path(path) => path,
-            &TypeRef::TypeParam(idx) => return Some(idx.into()),
-            _ => return None,
-        };
-        if path.type_anchor().is_some() {
-            return None;
-        }
-        if path.segments().len() > 1 {
-            return None;
-        }
-        let resolution = match self.resolver.resolve_path_in_type_ns(self.db, path) {
-            Some((it, None, _)) => it,
-            _ => return None,
-        };
-        match resolution {
-            TypeNs::GenericParam(param_id) => Some(param_id.into()),
-            _ => None,
-        }
-    }
-
-    #[inline]
-    fn on_path_diagnostic_callback<'b>(type_ref: TypeRefId) -> PathDiagnosticCallback<'b, 'db> {
-        PathDiagnosticCallback {
-            data: Either::Left(PathDiagnosticCallbackData(type_ref)),
-            callback: |data, this, diag| {
-                let type_ref = data.as_ref().left().unwrap().0;
-                this.push_diagnostic(type_ref, TyLoweringDiagnosticKind::PathDiagnostic(diag))
-            },
-        }
-    }
-
-    #[inline]
-    fn at_path(&mut self, path_id: PathId) -> PathLoweringContext<'_, 'a, 'db> {
-        PathLoweringContext::new(
-            self,
-            Self::on_path_diagnostic_callback(path_id.type_ref()),
-            &self.store[path_id],
-        )
-    }
-
-    pub(crate) fn lower_path(&mut self, path: &Path, path_id: PathId) -> (Ty<'db>, Option<TypeNs>) {
-        // Resolve the path (in type namespace)
-        if let Some(type_ref) = path.type_anchor() {
-            let (ty, res) = self.lower_ty_ext(type_ref);
-            let mut ctx = self.at_path(path_id);
-            return ctx.lower_ty_relative_path(ty, res, false);
-        }
-
-        let mut ctx = self.at_path(path_id);
-        let (resolution, remaining_index) = match ctx.resolve_path_in_type_ns() {
-            Some(it) => it,
-            None => return (Ty::new_error(self.interner, ErrorGuaranteed), None),
-        };
-
-        if matches!(resolution, TypeNs::TraitId(_)) && remaining_index.is_none() {
-            // trait object type without dyn
-            let bound = TypeBound::Path(path_id, TraitBoundModifier::None);
-            let ty = self.lower_dyn_trait(&[bound]);
-            return (ty, None);
-        }
-
-        ctx.lower_partly_resolved_path(resolution, false)
-    }
-
-    fn lower_trait_ref_from_path(
-        &mut self,
-        path_id: PathId,
-        explicit_self_ty: Ty<'db>,
-    ) -> Option<(TraitRef<'db>, PathLoweringContext<'_, 'a, 'db>)> {
-        let mut ctx = self.at_path(path_id);
-        let resolved = match ctx.resolve_path_in_type_ns_fully()? {
-            // FIXME(trait_alias): We need to handle trait alias here.
-            TypeNs::TraitId(tr) => tr,
-            _ => return None,
-        };
-        Some((ctx.lower_trait_ref_from_resolved_path(resolved, explicit_self_ty, false), ctx))
-    }
-
-    fn lower_trait_ref(
-        &mut self,
-        trait_ref: &HirTraitRef,
-        explicit_self_ty: Ty<'db>,
-    ) -> Option<TraitRef<'db>> {
-        self.lower_trait_ref_from_path(trait_ref.path, explicit_self_ty).map(|it| it.0)
-    }
-
-    pub(crate) fn lower_where_predicate<'b>(
-        &'b mut self,
-        where_predicate: &'b WherePredicate,
-        ignore_bindings: bool,
-        generics: &Generics,
-        predicate_filter: PredicateFilter,
-    ) -> impl Iterator<Item = Clause<'db>> + use<'a, 'b, 'db> {
-        match where_predicate {
-            WherePredicate::ForLifetime { target, bound, .. }
-            | WherePredicate::TypeBound { target, bound } => {
-                if let PredicateFilter::SelfTrait = predicate_filter {
-                    let target_type = &self.store[*target];
-                    let self_type = 'is_self: {
-                        if let TypeRef::Path(path) = target_type
-                            && path.is_self_type()
-                        {
-                            break 'is_self true;
-                        }
-                        if let TypeRef::TypeParam(param) = target_type
-                            && generics[param.local_id()].is_trait_self()
-                        {
-                            break 'is_self true;
-                        }
-                        false
-                    };
-                    if !self_type {
-                        return Either::Left(Either::Left(iter::empty()));
-                    }
-                }
-                let self_ty = self.lower_ty(*target);
-                Either::Left(Either::Right(self.lower_type_bound(bound, self_ty, ignore_bindings)))
-            }
-            &WherePredicate::Lifetime { bound, target } => {
-                Either::Right(iter::once(Clause(Predicate::new(
-                    self.interner,
-                    Binder::dummy(rustc_type_ir::PredicateKind::Clause(
-                        rustc_type_ir::ClauseKind::RegionOutlives(OutlivesPredicate(
-                            self.lower_lifetime(bound),
-                            self.lower_lifetime(target),
-                        )),
-                    )),
-                ))))
-            }
-        }
-        .into_iter()
-    }
-
-    pub(crate) fn lower_type_bound<'b>(
-        &'b mut self,
-        bound: &'b TypeBound,
-        self_ty: Ty<'db>,
-        ignore_bindings: bool,
-    ) -> impl Iterator<Item = Clause<'db>> + use<'b, 'a, 'db> {
-        let interner = self.interner;
-        let mut assoc_bounds = None;
-        let mut clause = None;
-        match bound {
-            &TypeBound::Path(path, TraitBoundModifier::None) | &TypeBound::ForLifetime(_, path) => {
-                // FIXME Don't silently drop the hrtb lifetimes here
-                if let Some((trait_ref, mut ctx)) = self.lower_trait_ref_from_path(path, self_ty) {
-                    // FIXME(sized-hierarchy): Remove this bound modifications once we have implemented
-                    // sized-hierarchy correctly.
-                    let meta_sized = LangItem::MetaSized
-                        .resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate());
-                    let pointee_sized = LangItem::PointeeSized
-                        .resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate());
-                    if meta_sized.is_some_and(|it| it == trait_ref.def_id.0) {
-                        // Ignore this bound
-                    } else if pointee_sized.is_some_and(|it| it == trait_ref.def_id.0) {
-                        // Regard this as `?Sized` bound
-                        ctx.ty_ctx().unsized_types.insert(self_ty);
-                    } else {
-                        if !ignore_bindings {
-                            assoc_bounds = ctx.assoc_type_bindings_from_type_bound(trait_ref);
-                        }
-                        clause = Some(Clause(Predicate::new(
-                            interner,
-                            Binder::dummy(rustc_type_ir::PredicateKind::Clause(
-                                rustc_type_ir::ClauseKind::Trait(TraitPredicate {
-                                    trait_ref,
-                                    polarity: rustc_type_ir::PredicatePolarity::Positive,
-                                }),
-                            )),
-                        )));
-                    }
-                }
-            }
-            &TypeBound::Path(path, TraitBoundModifier::Maybe) => {
-                let sized_trait = LangItem::Sized.resolve_trait(self.db, self.resolver.krate());
-                // Don't lower associated type bindings as the only possible relaxed trait bound
-                // `?Sized` has no of them.
-                // If we got another trait here ignore the bound completely.
-                let trait_id = self
-                    .lower_trait_ref_from_path(path, self_ty)
-                    .map(|(trait_ref, _)| trait_ref.def_id.0);
-                if trait_id == sized_trait {
-                    self.unsized_types.insert(self_ty);
-                }
-            }
-            &TypeBound::Lifetime(l) => {
-                let lifetime = self.lower_lifetime(l);
-                clause = Some(Clause(Predicate::new(
-                    self.interner,
-                    Binder::dummy(rustc_type_ir::PredicateKind::Clause(
-                        rustc_type_ir::ClauseKind::TypeOutlives(OutlivesPredicate(
-                            self_ty, lifetime,
-                        )),
-                    )),
-                )));
-            }
-            TypeBound::Use(_) | TypeBound::Error => {}
-        }
-        clause.into_iter().chain(assoc_bounds.into_iter().flatten())
-    }
-
-    fn lower_dyn_trait(&mut self, bounds: &[TypeBound]) -> Ty<'db> {
-        let interner = self.interner;
-        // FIXME: we should never create non-existential predicates in the first place
-        // For now, use an error type so we don't run into dummy binder issues
-        let self_ty = Ty::new_error(interner, ErrorGuaranteed);
-        // INVARIANT: The principal trait bound, if present, must come first. Others may be in any
-        // order but should be in the same order for the same set but possibly different order of
-        // bounds in the input.
-        // INVARIANT: If this function returns `DynTy`, there should be at least one trait bound.
-        // These invariants are utilized by `TyExt::dyn_trait()` and chalk.
-        let mut lifetime = None;
-        let bounds = self.with_shifted_in(DebruijnIndex::from_u32(1), |ctx| {
-            let mut lowered_bounds: Vec<
-                rustc_type_ir::Binder<DbInterner<'db>, ExistentialPredicate<DbInterner<'db>>>,
-            > = Vec::new();
-            for b in bounds {
-                let db = ctx.db;
-                ctx.lower_type_bound(b, self_ty, false).for_each(|b| {
-                    if let Some(bound) = b
-                        .kind()
-                        .map_bound(|c| match c {
-                            rustc_type_ir::ClauseKind::Trait(t) => {
-                                let id = t.def_id();
-                                let is_auto =
-                                    db.trait_signature(id.0).flags.contains(TraitFlags::AUTO);
-                                if is_auto {
-                                    Some(ExistentialPredicate::AutoTrait(t.def_id()))
-                                } else {
-                                    Some(ExistentialPredicate::Trait(
-                                        ExistentialTraitRef::new_from_args(
-                                            interner,
-                                            t.def_id(),
-                                            GenericArgs::new_from_iter(
-                                                interner,
-                                                t.trait_ref.args.iter().skip(1),
-                                            ),
-                                        ),
-                                    ))
-                                }
-                            }
-                            rustc_type_ir::ClauseKind::Projection(p) => {
-                                Some(ExistentialPredicate::Projection(
-                                    ExistentialProjection::new_from_args(
-                                        interner,
-                                        p.def_id(),
-                                        GenericArgs::new_from_iter(
-                                            interner,
-                                            p.projection_term.args.iter().skip(1),
-                                        ),
-                                        p.term,
-                                    ),
-                                ))
-                            }
-                            rustc_type_ir::ClauseKind::TypeOutlives(outlives_predicate) => {
-                                lifetime = Some(outlives_predicate.1);
-                                None
-                            }
-                            rustc_type_ir::ClauseKind::RegionOutlives(_)
-                            | rustc_type_ir::ClauseKind::ConstArgHasType(_, _)
-                            | rustc_type_ir::ClauseKind::WellFormed(_)
-                            | rustc_type_ir::ClauseKind::ConstEvaluatable(_)
-                            | rustc_type_ir::ClauseKind::HostEffect(_)
-                            | rustc_type_ir::ClauseKind::UnstableFeature(_) => unreachable!(),
-                        })
-                        .transpose()
-                    {
-                        lowered_bounds.push(bound);
-                    }
-                })
-            }
-
-            let mut multiple_regular_traits = false;
-            let mut multiple_same_projection = false;
-            lowered_bounds.sort_unstable_by(|lhs, rhs| {
-                use std::cmp::Ordering;
-                match ((*lhs).skip_binder(), (*rhs).skip_binder()) {
-                    (ExistentialPredicate::Trait(_), ExistentialPredicate::Trait(_)) => {
-                        multiple_regular_traits = true;
-                        // Order doesn't matter - we error
-                        Ordering::Equal
-                    }
-                    (
-                        ExistentialPredicate::AutoTrait(lhs_id),
-                        ExistentialPredicate::AutoTrait(rhs_id),
-                    ) => lhs_id.0.cmp(&rhs_id.0),
-                    (ExistentialPredicate::Trait(_), _) => Ordering::Less,
-                    (_, ExistentialPredicate::Trait(_)) => Ordering::Greater,
-                    (ExistentialPredicate::AutoTrait(_), _) => Ordering::Less,
-                    (_, ExistentialPredicate::AutoTrait(_)) => Ordering::Greater,
-                    (
-                        ExistentialPredicate::Projection(lhs),
-                        ExistentialPredicate::Projection(rhs),
-                    ) => {
-                        let lhs_id = match lhs.def_id {
-                            SolverDefId::TypeAliasId(id) => id,
-                            _ => unreachable!(),
-                        };
-                        let rhs_id = match rhs.def_id {
-                            SolverDefId::TypeAliasId(id) => id,
-                            _ => unreachable!(),
-                        };
-                        // We only compare the `associated_ty_id`s. We shouldn't have
-                        // multiple bounds for an associated type in the correct Rust code,
-                        // and if we do, we error out.
-                        if lhs_id == rhs_id {
-                            multiple_same_projection = true;
-                        }
-                        lhs_id.as_id().index().cmp(&rhs_id.as_id().index())
-                    }
-                }
-            });
-
-            if multiple_regular_traits || multiple_same_projection {
-                return None;
-            }
-
-            if !lowered_bounds.first().map_or(false, |b| {
-                matches!(
-                    b.as_ref().skip_binder(),
-                    ExistentialPredicate::Trait(_) | ExistentialPredicate::AutoTrait(_)
-                )
-            }) {
-                return None;
-            }
-
-            // As multiple occurrences of the same auto traits *are* permitted, we deduplicate the
-            // bounds. We shouldn't have repeated elements besides auto traits at this point.
-            lowered_bounds.dedup();
-
-            Some(BoundExistentialPredicates::new_from_iter(interner, lowered_bounds))
-        });
-
-        if let Some(bounds) = bounds {
-            let region = match lifetime {
-                Some(it) => match it.kind() {
-                    rustc_type_ir::RegionKind::ReBound(db, var) => Region::new_bound(
-                        self.interner,
-                        db.shifted_out_to_binder(DebruijnIndex::from_u32(2)),
-                        var,
-                    ),
-                    _ => it,
-                },
-                None => Region::new_static(self.interner),
-            };
-            Ty::new_dynamic(self.interner, bounds, region)
-        } else {
-            // FIXME: report error
-            // (additional non-auto traits, associated type rebound, or no resolved trait)
-            Ty::new_error(self.interner, ErrorGuaranteed)
-        }
-    }
-
-    fn lower_impl_trait(
-        &mut self,
-        def_id: SolverDefId,
-        bounds: &[TypeBound],
-        krate: Crate,
-    ) -> ImplTrait<'db> {
-        let interner = self.interner;
-        cov_mark::hit!(lower_rpit);
-        let args = GenericArgs::identity_for_item(interner, def_id);
-        let self_ty = Ty::new_alias(
-            self.interner,
-            rustc_type_ir::AliasTyKind::Opaque,
-            AliasTy::new_from_args(interner, def_id, args),
-        );
-        let predicates = self.with_shifted_in(DebruijnIndex::from_u32(1), |ctx| {
-            let mut predicates = Vec::new();
-            for b in bounds {
-                predicates.extend(ctx.lower_type_bound(b, self_ty, false));
-            }
-
-            if !ctx.unsized_types.contains(&self_ty) {
-                let sized_trait = LangItem::Sized.resolve_trait(self.db, krate);
-                let sized_clause = sized_trait.map(|trait_id| {
-                    let trait_ref = TraitRef::new_from_args(
-                        interner,
-                        trait_id.into(),
-                        GenericArgs::new_from_iter(interner, [self_ty.into()]),
-                    );
-                    Clause(Predicate::new(
-                        interner,
-                        Binder::dummy(rustc_type_ir::PredicateKind::Clause(
-                            rustc_type_ir::ClauseKind::Trait(TraitPredicate {
-                                trait_ref,
-                                polarity: rustc_type_ir::PredicatePolarity::Positive,
-                            }),
-                        )),
-                    ))
-                });
-                predicates.extend(sized_clause);
-            }
-            predicates.shrink_to_fit();
-            predicates
-        });
-        ImplTrait { predicates }
-    }
-
-    pub(crate) fn lower_lifetime(&mut self, lifetime: LifetimeRefId) -> Region<'db> {
-        match self.resolver.resolve_lifetime(&self.store[lifetime]) {
-            Some(resolution) => match resolution {
-                LifetimeNs::Static => Region::new_static(self.interner),
-                LifetimeNs::LifetimeParam(id) => {
-                    let idx = match self.generics().lifetime_idx(id) {
-                        None => return Region::error(self.interner),
-                        Some(idx) => idx,
-                    };
-                    self.region_param(id, idx as u32)
-                }
-            },
-            None => Region::error(self.interner),
-        }
-    }
-}
-
-pub(crate) fn lower_mutability(m: hir_def::type_ref::Mutability) -> Mutability {
-    match m {
-        hir_def::type_ref::Mutability::Shared => Mutability::Not,
-        hir_def::type_ref::Mutability::Mut => Mutability::Mut,
-    }
-}
-
-fn unknown_const(_ty: Ty<'_>) -> Const<'_> {
-    Const::new(DbInterner::conjure(), ConstKind::Error(ErrorGuaranteed))
-}
-
-pub(crate) fn impl_trait_query<'db>(
-    db: &'db dyn HirDatabase,
-    impl_id: ImplId,
-) -> Option<EarlyBinder<'db, TraitRef<'db>>> {
-    db.impl_trait_with_diagnostics(impl_id).map(|it| it.0)
-}
-
-pub(crate) fn impl_trait_with_diagnostics_query<'db>(
-    db: &'db dyn HirDatabase,
-    impl_id: ImplId,
-) -> Option<(EarlyBinder<'db, TraitRef<'db>>, Diagnostics)> {
-    let impl_data = db.impl_signature(impl_id);
-    let resolver = impl_id.resolver(db);
-    let mut ctx = TyLoweringContext::new(
-        db,
-        &resolver,
-        &impl_data.store,
-        impl_id.into(),
-        LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true },
-    );
-    let self_ty = db.impl_self_ty(impl_id).skip_binder();
-    let target_trait = impl_data.target_trait.as_ref()?;
-    let trait_ref = EarlyBinder::bind(ctx.lower_trait_ref(target_trait, self_ty)?);
-    Some((trait_ref, create_diagnostics(ctx.diagnostics)))
-}
-
-pub(crate) fn return_type_impl_traits<'db>(
-    db: &'db dyn HirDatabase,
-    def: hir_def::FunctionId,
-) -> Option<Arc<EarlyBinder<'db, ImplTraits<'db>>>> {
-    // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe
-    let data = db.function_signature(def);
-    let resolver = def.resolver(db);
-    let mut ctx_ret =
-        TyLoweringContext::new(db, &resolver, &data.store, def.into(), LifetimeElisionKind::Infer)
-            .with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
-    if let Some(ret_type) = data.ret_type {
-        let _ret = ctx_ret.lower_ty(ret_type);
-    }
-    let return_type_impl_traits =
-        ImplTraits { impl_traits: ctx_ret.impl_trait_mode.opaque_type_data };
-    if return_type_impl_traits.impl_traits.is_empty() {
-        None
-    } else {
-        Some(Arc::new(EarlyBinder::bind(return_type_impl_traits)))
-    }
-}
-
-pub(crate) fn type_alias_impl_traits<'db>(
-    db: &'db dyn HirDatabase,
-    def: hir_def::TypeAliasId,
-) -> Option<Arc<EarlyBinder<'db, ImplTraits<'db>>>> {
-    let data = db.type_alias_signature(def);
-    let resolver = def.resolver(db);
-    let mut ctx = TyLoweringContext::new(
-        db,
-        &resolver,
-        &data.store,
-        def.into(),
-        LifetimeElisionKind::AnonymousReportError,
-    )
-    .with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
-    if let Some(type_ref) = data.ty {
-        let _ty = ctx.lower_ty(type_ref);
-    }
-    let type_alias_impl_traits = ImplTraits { impl_traits: ctx.impl_trait_mode.opaque_type_data };
-    if type_alias_impl_traits.impl_traits.is_empty() {
-        None
-    } else {
-        Some(Arc::new(EarlyBinder::bind(type_alias_impl_traits)))
-    }
-}
-
-/// Build the declared type of an item. This depends on the namespace; e.g. for
-/// `struct Foo(usize)`, we have two types: The type of the struct itself, and
-/// the constructor function `(usize) -> Foo` which lives in the values
-/// namespace.
-pub(crate) fn ty_query<'db>(db: &'db dyn HirDatabase, def: TyDefId) -> EarlyBinder<'db, Ty<'db>> {
-    let interner = DbInterner::new_with(db, None, None);
-    match def {
-        TyDefId::BuiltinType(it) => EarlyBinder::bind(Ty::from_builtin_type(interner, it)),
-        TyDefId::AdtId(it) => EarlyBinder::bind(Ty::new_adt(
-            interner,
-            it,
-            GenericArgs::identity_for_item(interner, it.into()),
-        )),
-        TyDefId::TypeAliasId(it) => db.type_for_type_alias_with_diagnostics(it).0,
-    }
-}
-
-/// Build the declared type of a function. This should not need to look at the
-/// function body.
-fn type_for_fn<'db>(db: &'db dyn HirDatabase, def: FunctionId) -> EarlyBinder<'db, Ty<'db>> {
-    let interner = DbInterner::new_with(db, None, None);
-    EarlyBinder::bind(Ty::new_fn_def(
-        interner,
-        CallableDefId::FunctionId(def).into(),
-        GenericArgs::identity_for_item(interner, def.into()),
-    ))
-}
-
-/// Build the declared type of a const.
-fn type_for_const<'db>(db: &'db dyn HirDatabase, def: ConstId) -> EarlyBinder<'db, Ty<'db>> {
-    let resolver = def.resolver(db);
-    let data = db.const_signature(def);
-    let parent = def.loc(db).container;
-    let mut ctx = TyLoweringContext::new(
-        db,
-        &resolver,
-        &data.store,
-        def.into(),
-        LifetimeElisionKind::AnonymousReportError,
-    );
-    ctx.set_lifetime_elision(LifetimeElisionKind::for_const(ctx.interner, parent));
-    EarlyBinder::bind(ctx.lower_ty(data.type_ref))
-}
-
-/// Build the declared type of a static.
-fn type_for_static<'db>(db: &'db dyn HirDatabase, def: StaticId) -> EarlyBinder<'db, Ty<'db>> {
-    let resolver = def.resolver(db);
-    let module = resolver.module();
-    let interner = DbInterner::new_with(db, Some(module.krate()), module.containing_block());
-    let data = db.static_signature(def);
-    let parent = def.loc(db).container;
-    let mut ctx = TyLoweringContext::new(
-        db,
-        &resolver,
-        &data.store,
-        def.into(),
-        LifetimeElisionKind::AnonymousReportError,
-    );
-    ctx.set_lifetime_elision(LifetimeElisionKind::Elided(Region::new_static(ctx.interner)));
-    EarlyBinder::bind(ctx.lower_ty(data.type_ref))
-}
-
-/// Build the type of a tuple struct constructor.
-fn type_for_struct_constructor<'db>(
-    db: &'db dyn HirDatabase,
-    def: StructId,
-) -> Option<EarlyBinder<'db, Ty<'db>>> {
-    let struct_data = def.fields(db);
-    match struct_data.shape {
-        FieldsShape::Record => None,
-        FieldsShape::Unit => Some(type_for_adt(db, def.into())),
-        FieldsShape::Tuple => {
-            let interner = DbInterner::new_with(db, None, None);
-            Some(EarlyBinder::bind(Ty::new_fn_def(
-                interner,
-                CallableDefId::StructId(def).into(),
-                GenericArgs::identity_for_item(interner, def.into()),
-            )))
-        }
-    }
-}
-
-/// Build the type of a tuple enum variant constructor.
-fn type_for_enum_variant_constructor<'db>(
-    db: &'db dyn HirDatabase,
-    def: EnumVariantId,
-) -> Option<EarlyBinder<'db, Ty<'db>>> {
-    let struct_data = def.fields(db);
-    match struct_data.shape {
-        FieldsShape::Record => None,
-        FieldsShape::Unit => Some(type_for_adt(db, def.loc(db).parent.into())),
-        FieldsShape::Tuple => {
-            let interner = DbInterner::new_with(db, None, None);
-            Some(EarlyBinder::bind(Ty::new_fn_def(
-                interner,
-                CallableDefId::EnumVariantId(def).into(),
-                GenericArgs::identity_for_item(interner, def.loc(db).parent.into()),
-            )))
-        }
-    }
-}
-
-pub(crate) fn value_ty_query<'db>(
-    db: &'db dyn HirDatabase,
-    def: ValueTyDefId,
-) -> Option<EarlyBinder<'db, Ty<'db>>> {
-    match def {
-        ValueTyDefId::FunctionId(it) => Some(type_for_fn(db, it)),
-        ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it),
-        ValueTyDefId::UnionId(it) => Some(type_for_adt(db, it.into())),
-        ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it),
-        ValueTyDefId::ConstId(it) => Some(type_for_const(db, it)),
-        ValueTyDefId::StaticId(it) => Some(type_for_static(db, it)),
-    }
-}
-
-pub(crate) fn type_for_type_alias_with_diagnostics_query<'db>(
-    db: &'db dyn HirDatabase,
-    t: TypeAliasId,
-) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) {
-    let type_alias_data = db.type_alias_signature(t);
-    let mut diags = None;
-    let resolver = t.resolver(db);
-    let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
-    let inner = if type_alias_data.flags.contains(TypeAliasFlags::IS_EXTERN) {
-        EarlyBinder::bind(Ty::new_foreign(interner, t.into()))
-    } else {
-        let mut ctx = TyLoweringContext::new(
-            db,
-            &resolver,
-            &type_alias_data.store,
-            t.into(),
-            LifetimeElisionKind::AnonymousReportError,
-        )
-        .with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
-        let res = EarlyBinder::bind(
-            type_alias_data
-                .ty
-                .map(|type_ref| ctx.lower_ty(type_ref))
-                .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed)),
-        );
-        diags = create_diagnostics(ctx.diagnostics);
-        res
-    };
-    (inner, diags)
-}
-
-pub(crate) fn type_for_type_alias_with_diagnostics_cycle_result<'db>(
-    db: &'db dyn HirDatabase,
-    _adt: TypeAliasId,
-) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) {
-    (EarlyBinder::bind(Ty::new_error(DbInterner::new_with(db, None, None), ErrorGuaranteed)), None)
-}
-
-pub(crate) fn impl_self_ty_query<'db>(
-    db: &'db dyn HirDatabase,
-    impl_id: ImplId,
-) -> EarlyBinder<'db, Ty<'db>> {
-    db.impl_self_ty_with_diagnostics(impl_id).0
-}
-
-pub(crate) fn impl_self_ty_with_diagnostics_query<'db>(
-    db: &'db dyn HirDatabase,
-    impl_id: ImplId,
-) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) {
-    let resolver = impl_id.resolver(db);
-    let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
-
-    let impl_data = db.impl_signature(impl_id);
-    let mut ctx = TyLoweringContext::new(
-        db,
-        &resolver,
-        &impl_data.store,
-        impl_id.into(),
-        LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true },
-    );
-    let ty = ctx.lower_ty(impl_data.self_ty);
-    assert!(!ty.has_escaping_bound_vars());
-    (EarlyBinder::bind(ty), create_diagnostics(ctx.diagnostics))
-}
-
-pub(crate) fn impl_self_ty_with_diagnostics_cycle_result(
-    db: &dyn HirDatabase,
-    _impl_id: ImplId,
-) -> (EarlyBinder<'_, Ty<'_>>, Diagnostics) {
-    (EarlyBinder::bind(Ty::new_error(DbInterner::new_with(db, None, None), ErrorGuaranteed)), None)
-}
-
-pub(crate) fn const_param_ty_query<'db>(db: &'db dyn HirDatabase, def: ConstParamId) -> Ty<'db> {
-    db.const_param_ty_with_diagnostics(def).0
-}
-
-// returns None if def is a type arg
-pub(crate) fn const_param_ty_with_diagnostics_query<'db>(
-    db: &'db dyn HirDatabase,
-    def: ConstParamId,
-) -> (Ty<'db>, Diagnostics) {
-    let (parent_data, store) = db.generic_params_and_store(def.parent());
-    let data = &parent_data[def.local_id()];
-    let resolver = def.parent().resolver(db);
-    let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
-    let mut ctx = TyLoweringContext::new(
-        db,
-        &resolver,
-        &store,
-        def.parent(),
-        LifetimeElisionKind::AnonymousReportError,
-    );
-    let ty = match data {
-        TypeOrConstParamData::TypeParamData(_) => {
-            never!();
-            Ty::new_error(interner, ErrorGuaranteed)
-        }
-        TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(d.ty),
-    };
-    (ty, create_diagnostics(ctx.diagnostics))
-}
-
-pub(crate) fn const_param_ty_with_diagnostics_cycle_result<'db>(
-    db: &'db dyn HirDatabase,
-    _: crate::db::HirDatabaseData,
-    def: ConstParamId,
-) -> (Ty<'db>, Diagnostics) {
-    let resolver = def.parent().resolver(db);
-    let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
-    (Ty::new_error(interner, ErrorGuaranteed), None)
-}
-
-pub(crate) fn field_types_query<'db>(
-    db: &'db dyn HirDatabase,
-    variant_id: VariantId,
-) -> Arc<ArenaMap<LocalFieldId, EarlyBinder<'db, Ty<'db>>>> {
-    db.field_types_with_diagnostics(variant_id).0
-}
-
-/// Build the type of all specific fields of a struct or enum variant.
-pub(crate) fn field_types_with_diagnostics_query<'db>(
-    db: &'db dyn HirDatabase,
-    variant_id: VariantId,
-) -> (Arc<ArenaMap<LocalFieldId, EarlyBinder<'db, Ty<'db>>>>, Diagnostics) {
-    let var_data = variant_id.fields(db);
-    let fields = var_data.fields();
-    if fields.is_empty() {
-        return (Arc::new(ArenaMap::default()), None);
-    }
-
-    let (resolver, def): (_, GenericDefId) = match variant_id {
-        VariantId::StructId(it) => (it.resolver(db), it.into()),
-        VariantId::UnionId(it) => (it.resolver(db), it.into()),
-        VariantId::EnumVariantId(it) => (it.resolver(db), it.lookup(db).parent.into()),
-    };
-    let mut res = ArenaMap::default();
-    let mut ctx = TyLoweringContext::new(
-        db,
-        &resolver,
-        &var_data.store,
-        def,
-        LifetimeElisionKind::AnonymousReportError,
-    );
-    for (field_id, field_data) in var_data.fields().iter() {
-        res.insert(field_id, EarlyBinder::bind(ctx.lower_ty(field_data.type_ref)));
-    }
-    (Arc::new(res), create_diagnostics(ctx.diagnostics))
-}
-
-/// This query exists only to be used when resolving short-hand associated types
-/// like `T::Item`.
-///
-/// See the analogous query in rustc and its comment:
-/// <https://github.com/rust-lang/rust/blob/9150f844e2624eb013ec78ca08c1d416e6644026/src/librustc_typeck/astconv.rs#L46>
-/// This is a query mostly to handle cycles somewhat gracefully; e.g. the
-/// following bounds are disallowed: `T: Foo<U::Item>, U: Foo<T::Item>`, but
-/// these are fine: `T: Foo<U::Item>, U: Foo<()>`.
-#[tracing::instrument(skip(db), ret)]
-pub(crate) fn generic_predicates_for_param_query<'db>(
-    db: &'db dyn HirDatabase,
-    def: GenericDefId,
-    param_id: TypeOrConstParamId,
-    assoc_name: Option<Name>,
-) -> GenericPredicates<'db> {
-    let generics = generics(db, def);
-    let interner = DbInterner::new_with(db, None, None);
-    let resolver = def.resolver(db);
-    let mut ctx = TyLoweringContext::new(
-        db,
-        &resolver,
-        generics.store(),
-        def,
-        LifetimeElisionKind::AnonymousReportError,
-    );
-
-    // we have to filter out all other predicates *first*, before attempting to lower them
-    let predicate = |pred: &_, ctx: &mut TyLoweringContext<'_, '_>| match pred {
-        WherePredicate::ForLifetime { target, bound, .. }
-        | WherePredicate::TypeBound { target, bound, .. } => {
-            let invalid_target = { ctx.lower_ty_only_param(*target) != Some(param_id) };
-            if invalid_target {
-                // FIXME(sized-hierarchy): Revisit and adjust this properly once we have implemented
-                // sized-hierarchy correctly.
-                // If this is filtered out without lowering, `?Sized` or `PointeeSized` is not gathered into
-                // `ctx.unsized_types`
-                let lower = || -> bool {
-                    match bound {
-                        TypeBound::Path(_, TraitBoundModifier::Maybe) => true,
-                        TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
-                            let TypeRef::Path(path) = &ctx.store[path.type_ref()] else {
-                                return false;
-                            };
-                            let Some(pointee_sized) =
-                                LangItem::PointeeSized.resolve_trait(ctx.db, ctx.resolver.krate())
-                            else {
-                                return false;
-                            };
-                            // Lower the path directly with `Resolver` instead of PathLoweringContext`
-                            // to prevent diagnostics duplications.
-                            ctx.resolver.resolve_path_in_type_ns_fully(ctx.db, path).is_some_and(
-                                |it| matches!(it, TypeNs::TraitId(tr) if tr == pointee_sized),
-                            )
-                        }
-                        _ => false,
-                    }
-                }();
-                if lower {
-                    ctx.lower_where_predicate(pred, true, &generics, PredicateFilter::All)
-                        .for_each(drop);
-                }
-                return false;
-            }
-
-            match bound {
-                &TypeBound::ForLifetime(_, path) | &TypeBound::Path(path, _) => {
-                    // Only lower the bound if the trait could possibly define the associated
-                    // type we're looking for.
-                    let path = &ctx.store[path];
-
-                    let Some(assoc_name) = &assoc_name else { return true };
-                    let Some(TypeNs::TraitId(tr)) =
-                        resolver.resolve_path_in_type_ns_fully(db, path)
-                    else {
-                        return false;
-                    };
-
-                    rustc_type_ir::elaborate::supertrait_def_ids(interner, tr.into()).any(|tr| {
-                        tr.0.trait_items(db).items.iter().any(|(name, item)| {
-                            matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name
-                        })
-                    })
-                }
-                TypeBound::Use(_) | TypeBound::Lifetime(_) | TypeBound::Error => false,
-            }
-        }
-        WherePredicate::Lifetime { .. } => false,
-    };
-    let mut predicates = Vec::new();
-    for maybe_parent_generics in
-        std::iter::successors(Some(&generics), |generics| generics.parent_generics())
-    {
-        ctx.store = maybe_parent_generics.store();
-        for pred in maybe_parent_generics.where_predicates() {
-            if predicate(pred, &mut ctx) {
-                predicates.extend(ctx.lower_where_predicate(
-                    pred,
-                    true,
-                    maybe_parent_generics,
-                    PredicateFilter::All,
-                ));
-            }
-        }
-    }
-
-    let args = GenericArgs::identity_for_item(interner, def.into());
-    if !args.is_empty() {
-        let explicitly_unsized_tys = ctx.unsized_types;
-        if let Some(implicitly_sized_predicates) =
-            implicitly_sized_clauses(db, param_id.parent, &explicitly_unsized_tys, &args, &resolver)
-        {
-            predicates.extend(implicitly_sized_predicates);
-        };
-    }
-    GenericPredicates(predicates.is_empty().not().then(|| predicates.into()))
-}
-
-pub(crate) fn generic_predicates_for_param_cycle_result(
-    _db: &dyn HirDatabase,
-    _def: GenericDefId,
-    _param_id: TypeOrConstParamId,
-    _assoc_name: Option<Name>,
-) -> GenericPredicates<'_> {
-    GenericPredicates(None)
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct GenericPredicates<'db>(Option<Arc<[Clause<'db>]>>);
-
-impl<'db> GenericPredicates<'db> {
-    #[inline]
-    pub fn instantiate(
-        &self,
-        interner: DbInterner<'db>,
-        args: GenericArgs<'db>,
-    ) -> Option<impl Iterator<Item = Clause<'db>>> {
-        self.0
-            .as_ref()
-            .map(|it| EarlyBinder::bind(it.iter().copied()).iter_instantiated(interner, args))
-    }
-
-    #[inline]
-    pub fn instantiate_identity(&self) -> Option<impl Iterator<Item = Clause<'db>>> {
-        self.0.as_ref().map(|it| it.iter().copied())
-    }
-}
-
-impl<'db> ops::Deref for GenericPredicates<'db> {
-    type Target = [Clause<'db>];
-
-    fn deref(&self) -> &Self::Target {
-        self.0.as_deref().unwrap_or(&[])
-    }
-}
-
-pub(crate) fn trait_environment_for_body_query(
-    db: &dyn HirDatabase,
-    def: DefWithBodyId,
-) -> Arc<TraitEnvironment<'_>> {
-    let Some(def) = def.as_generic_def_id(db) else {
-        let krate = def.module(db).krate();
-        return TraitEnvironment::empty(krate);
-    };
-    db.trait_environment(def)
-}
-
-pub(crate) fn trait_environment_query<'db>(
-    db: &'db dyn HirDatabase,
-    def: GenericDefId,
-) -> Arc<TraitEnvironment<'db>> {
-    let generics = generics(db, def);
-    if generics.has_no_predicates() && generics.is_empty() {
-        return TraitEnvironment::empty(def.krate(db));
-    }
-
-    let interner = DbInterner::new_with(db, Some(def.krate(db)), None);
-    let resolver = def.resolver(db);
-    let mut ctx = TyLoweringContext::new(
-        db,
-        &resolver,
-        generics.store(),
-        def,
-        LifetimeElisionKind::AnonymousReportError,
-    );
-    let mut traits_in_scope = Vec::new();
-    let mut clauses = Vec::new();
-    for maybe_parent_generics in
-        std::iter::successors(Some(&generics), |generics| generics.parent_generics())
-    {
-        ctx.store = maybe_parent_generics.store();
-        for pred in maybe_parent_generics.where_predicates() {
-            for pred in ctx.lower_where_predicate(pred, false, &generics, PredicateFilter::All) {
-                if let rustc_type_ir::ClauseKind::Trait(tr) = pred.kind().skip_binder() {
-                    traits_in_scope.push((tr.self_ty(), tr.def_id().0));
-                }
-                clauses.push(pred);
-            }
-        }
-    }
-
-    if let Some(trait_id) = def.assoc_trait_container(db) {
-        // add `Self: Trait<T1, T2, ...>` to the environment in trait
-        // function default implementations (and speculative code
-        // inside consts or type aliases)
-        cov_mark::hit!(trait_self_implements_self);
-        let trait_ref = TraitRef::identity(ctx.interner, trait_id.into());
-        let clause = Clause(Predicate::new(
-            ctx.interner,
-            Binder::dummy(rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Trait(
-                TraitPredicate { trait_ref, polarity: rustc_type_ir::PredicatePolarity::Positive },
-            ))),
-        ));
-        clauses.push(clause);
-    }
-
-    let explicitly_unsized_tys = ctx.unsized_types;
-
-    let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate());
-    if let Some(sized_trait) = sized_trait {
-        let (mut generics, mut def_id) =
-            (crate::next_solver::generics::generics(db, def.into()), def);
-        loop {
-            let self_idx = trait_self_param_idx(db, def_id);
-            for (idx, p) in generics.own_params.iter().enumerate() {
-                if let Some(self_idx) = self_idx
-                    && p.index() as usize == self_idx
-                {
-                    continue;
-                }
-                let GenericParamId::TypeParamId(param_id) = p.id else {
-                    continue;
-                };
-                let idx = idx as u32 + generics.parent_count as u32;
-                let param_ty = Ty::new_param(ctx.interner, param_id, idx, p.name.clone());
-                if explicitly_unsized_tys.contains(&param_ty) {
-                    continue;
-                }
-                let trait_ref = TraitRef::new_from_args(
-                    ctx.interner,
-                    sized_trait.into(),
-                    GenericArgs::new_from_iter(ctx.interner, [param_ty.into()]),
-                );
-                let clause = Clause(Predicate::new(
-                    ctx.interner,
-                    Binder::dummy(rustc_type_ir::PredicateKind::Clause(
-                        rustc_type_ir::ClauseKind::Trait(TraitPredicate {
-                            trait_ref,
-                            polarity: rustc_type_ir::PredicatePolarity::Positive,
-                        }),
-                    )),
-                ));
-                clauses.push(clause);
-            }
-
-            if let Some(g) = generics.parent {
-                generics = crate::next_solver::generics::generics(db, g.into());
-                def_id = g;
-            } else {
-                break;
-            }
-        }
-    }
-
-    let clauses = rustc_type_ir::elaborate::elaborate(ctx.interner, clauses);
-    let clauses = Clauses::new_from_iter(ctx.interner, clauses);
-    let env = ParamEnv { clauses };
-
-    TraitEnvironment::new(resolver.krate(), None, traits_in_scope.into_boxed_slice(), env)
-}
-
-#[derive(Copy, Clone, Debug)]
-pub(crate) enum PredicateFilter {
-    SelfTrait,
-    All,
-}
-
-/// Resolve the where clause(s) of an item with generics.
-#[tracing::instrument(skip(db))]
-pub(crate) fn generic_predicates_query<'db>(
-    db: &'db dyn HirDatabase,
-    def: GenericDefId,
-) -> GenericPredicates<'db> {
-    generic_predicates_filtered_by(db, def, PredicateFilter::All, |_| true).0
-}
-
-pub(crate) fn generic_predicates_without_parent_query<'db>(
-    db: &'db dyn HirDatabase,
-    def: GenericDefId,
-) -> GenericPredicates<'db> {
-    generic_predicates_filtered_by(db, def, PredicateFilter::All, |d| d == def).0
-}
-
-/// Resolve the where clause(s) of an item with generics,
-/// except the ones inherited from the parent
-pub(crate) fn generic_predicates_without_parent_with_diagnostics_query<'db>(
-    db: &'db dyn HirDatabase,
-    def: GenericDefId,
-) -> (GenericPredicates<'db>, Diagnostics) {
-    generic_predicates_filtered_by(db, def, PredicateFilter::All, |d| d == def)
-}
-
-/// Resolve the where clause(s) of an item with generics,
-/// with a given filter
-#[tracing::instrument(skip(db, filter), ret)]
-pub(crate) fn generic_predicates_filtered_by<'db, F>(
-    db: &'db dyn HirDatabase,
-    def: GenericDefId,
-    predicate_filter: PredicateFilter,
-    filter: F,
-) -> (GenericPredicates<'db>, Diagnostics)
-where
-    F: Fn(GenericDefId) -> bool,
-{
-    let generics = generics(db, def);
-    let resolver = def.resolver(db);
-    let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
-    let mut ctx = TyLoweringContext::new(
-        db,
-        &resolver,
-        generics.store(),
-        def,
-        LifetimeElisionKind::AnonymousReportError,
-    );
-
-    let mut predicates = Vec::new();
-    for maybe_parent_generics in
-        std::iter::successors(Some(&generics), |generics| generics.parent_generics())
-    {
-        ctx.store = maybe_parent_generics.store();
-        for pred in maybe_parent_generics.where_predicates() {
-            tracing::debug!(?pred);
-            if filter(maybe_parent_generics.def()) {
-                // We deliberately use `generics` and not `maybe_parent_generics` here. This is not a mistake!
-                // If we use the parent generics
-                predicates.extend(ctx.lower_where_predicate(
-                    pred,
-                    false,
-                    maybe_parent_generics,
-                    predicate_filter,
-                ));
-            }
-        }
-    }
-
-    let explicitly_unsized_tys = ctx.unsized_types;
-
-    let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate());
-    if let Some(sized_trait) = sized_trait {
-        let (mut generics, mut def_id) =
-            (crate::next_solver::generics::generics(db, def.into()), def);
-        loop {
-            if filter(def_id) {
-                let self_idx = trait_self_param_idx(db, def_id);
-                for (idx, p) in generics.own_params.iter().enumerate() {
-                    if let Some(self_idx) = self_idx
-                        && p.index() as usize == self_idx
-                    {
-                        continue;
-                    }
-                    let GenericParamId::TypeParamId(param_id) = p.id else {
-                        continue;
-                    };
-                    let idx = idx as u32 + generics.parent_count as u32;
-                    let param_ty = Ty::new_param(interner, param_id, idx, p.name.clone());
-                    if explicitly_unsized_tys.contains(&param_ty) {
-                        continue;
-                    }
-                    let trait_ref = TraitRef::new_from_args(
-                        interner,
-                        sized_trait.into(),
-                        GenericArgs::new_from_iter(interner, [param_ty.into()]),
-                    );
-                    let clause = Clause(Predicate::new(
-                        interner,
-                        Binder::dummy(rustc_type_ir::PredicateKind::Clause(
-                            rustc_type_ir::ClauseKind::Trait(TraitPredicate {
-                                trait_ref,
-                                polarity: rustc_type_ir::PredicatePolarity::Positive,
-                            }),
-                        )),
-                    ));
-                    predicates.push(clause);
-                }
-            }
-
-            if let Some(g) = generics.parent {
-                generics = crate::next_solver::generics::generics(db, g.into());
-                def_id = g;
-            } else {
-                break;
-            }
-        }
-    }
-
-    // FIXME: rustc gathers more predicates by recursing through resulting trait predicates.
-    // See https://github.com/rust-lang/rust/blob/76c5ed2847cdb26ef2822a3a165d710f6b772217/compiler/rustc_hir_analysis/src/collect/predicates_of.rs#L689-L715
-
-    (
-        GenericPredicates(predicates.is_empty().not().then(|| predicates.into())),
-        create_diagnostics(ctx.diagnostics),
-    )
-}
-
-/// 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, 'db>(
-    db: &'db dyn HirDatabase,
-    def: GenericDefId,
-    explicitly_unsized_tys: &'a FxHashSet<Ty<'db>>,
-    args: &'subst GenericArgs<'db>,
-    resolver: &Resolver<'db>,
-) -> Option<impl Iterator<Item = Clause<'db>> + Captures<'a> + Captures<'subst>> {
-    let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
-    let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate())?;
-
-    let trait_self_idx = trait_self_param_idx(db, def);
-
-    Some(
-        args.iter()
-            .enumerate()
-            .filter_map(
-                move |(idx, generic_arg)| {
-                    if Some(idx) == trait_self_idx { None } else { Some(generic_arg) }
-                },
-            )
-            .filter_map(|generic_arg| generic_arg.as_type())
-            .filter(move |self_ty| !explicitly_unsized_tys.contains(self_ty))
-            .map(move |self_ty| {
-                let trait_ref = TraitRef::new_from_args(
-                    interner,
-                    sized_trait.into(),
-                    GenericArgs::new_from_iter(interner, [self_ty.into()]),
-                );
-                Clause(Predicate::new(
-                    interner,
-                    Binder::dummy(rustc_type_ir::PredicateKind::Clause(
-                        rustc_type_ir::ClauseKind::Trait(TraitPredicate {
-                            trait_ref,
-                            polarity: rustc_type_ir::PredicatePolarity::Positive,
-                        }),
-                    )),
-                ))
-            }),
-    )
-}
-
-pub(crate) fn make_binders<'db, T: rustc_type_ir::TypeVisitable<DbInterner<'db>>>(
-    interner: DbInterner<'db>,
-    generics: &Generics,
-    value: T,
-) -> Binder<'db, T> {
-    Binder::bind_with_vars(
-        value,
-        BoundVarKinds::new_from_iter(
-            interner,
-            generics.iter_id().map(|x| match x {
-                hir_def::GenericParamId::ConstParamId(_) => BoundVarKind::Const,
-                hir_def::GenericParamId::TypeParamId(_) => BoundVarKind::Ty(BoundTyKind::Anon),
-                hir_def::GenericParamId::LifetimeParamId(_) => {
-                    BoundVarKind::Region(BoundRegionKind::Anon)
-                }
-            }),
-        ),
-    )
-}
-
-/// Checks if the provided generic arg matches its expected kind, then lower them via
-/// provided closures. Use unknown if there was kind mismatch.
-///
-pub(crate) fn lower_generic_arg<'a, 'db, T>(
-    db: &'db dyn HirDatabase,
-    kind_id: GenericParamId,
-    arg: &'a GenericArg,
-    this: &mut T,
-    store: &ExpressionStore,
-    for_type: impl FnOnce(&mut T, TypeRefId) -> Ty<'db> + 'a,
-    for_const: impl FnOnce(&mut T, &ConstRef, Ty<'db>) -> Const<'db> + 'a,
-    for_const_ty_path_fallback: impl FnOnce(&mut T, &Path, Ty<'db>) -> Const<'db> + 'a,
-    for_lifetime: impl FnOnce(&mut T, &LifetimeRefId) -> Region<'db> + 'a,
-) -> crate::next_solver::GenericArg<'db> {
-    let interner = DbInterner::new_with(db, None, None);
-    let kind = match kind_id {
-        GenericParamId::TypeParamId(_) => ParamKind::Type,
-        GenericParamId::ConstParamId(id) => {
-            let ty = db.const_param_ty(id);
-            ParamKind::Const(ty)
-        }
-        GenericParamId::LifetimeParamId(_) => ParamKind::Lifetime,
-    };
-    match (arg, kind) {
-        (GenericArg::Type(type_ref), ParamKind::Type) => for_type(this, *type_ref).into(),
-        (GenericArg::Const(c), ParamKind::Const(c_ty)) => {
-            for_const(this, c, c_ty.to_nextsolver(interner)).into()
-        }
-        (GenericArg::Lifetime(lifetime_ref), ParamKind::Lifetime) => {
-            for_lifetime(this, lifetime_ref).into()
-        }
-        (GenericArg::Const(_), ParamKind::Type) => Ty::new_error(interner, ErrorGuaranteed).into(),
-        (GenericArg::Lifetime(_), ParamKind::Type) => {
-            Ty::new_error(interner, ErrorGuaranteed).into()
-        }
-        (GenericArg::Type(t), ParamKind::Const(c_ty)) => match &store[*t] {
-            TypeRef::Path(p) => {
-                for_const_ty_path_fallback(this, p, c_ty.to_nextsolver(interner)).into()
-            }
-            _ => unknown_const_as_generic(c_ty.to_nextsolver(interner)),
-        },
-        (GenericArg::Lifetime(_), ParamKind::Const(c_ty)) => {
-            unknown_const(c_ty.to_nextsolver(interner)).into()
-        }
-        (GenericArg::Type(_), ParamKind::Lifetime) => Region::error(interner).into(),
-        (GenericArg::Const(_), ParamKind::Lifetime) => Region::error(interner).into(),
-    }
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct GenericDefaults<'db>(
-    Option<Arc<[Option<EarlyBinder<'db, crate::next_solver::GenericArg<'db>>>]>>,
-);
-
-impl<'db> GenericDefaults<'db> {
-    #[inline]
-    pub fn get(&self, idx: usize) -> Option<EarlyBinder<'db, crate::next_solver::GenericArg<'db>>> {
-        self.0.as_ref()?[idx]
-    }
-}
-
-pub(crate) fn generic_defaults_query(
-    db: &dyn HirDatabase,
-    def: GenericDefId,
-) -> GenericDefaults<'_> {
-    db.generic_defaults_ns_with_diagnostics(def).0
-}
-
-/// Resolve the default type params from generics.
-///
-/// Diagnostics are only returned for this `GenericDefId` (returned defaults include parents).
-pub(crate) fn generic_defaults_with_diagnostics_query(
-    db: &dyn HirDatabase,
-    def: GenericDefId,
-) -> (GenericDefaults<'_>, Diagnostics) {
-    let generic_params = generics(db, def);
-    if generic_params.is_empty() {
-        return (GenericDefaults(None), None);
-    }
-    let resolver = def.resolver(db);
-
-    let mut ctx = TyLoweringContext::new(
-        db,
-        &resolver,
-        generic_params.store(),
-        def,
-        LifetimeElisionKind::AnonymousReportError,
-    )
-    .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed);
-    let mut idx = 0;
-    let mut has_any_default = false;
-    let mut defaults = generic_params
-        .iter_parents_with_store()
-        .map(|((id, p), store)| {
-            ctx.store = store;
-            let (result, has_default) = handle_generic_param(&mut ctx, idx, id, p, &generic_params);
-            has_any_default |= has_default;
-            idx += 1;
-            result
-        })
-        .collect::<Vec<_>>();
-    ctx.diagnostics.clear(); // Don't include diagnostics from the parent.
-    defaults.extend(generic_params.iter_self().map(|(id, p)| {
-        let (result, has_default) = handle_generic_param(&mut ctx, idx, id, p, &generic_params);
-        has_any_default |= has_default;
-        idx += 1;
-        result
-    }));
-    let diagnostics = create_diagnostics(mem::take(&mut ctx.diagnostics));
-    let defaults = if has_any_default {
-        GenericDefaults(Some(Arc::from_iter(defaults)))
-    } else {
-        GenericDefaults(None)
-    };
-    return (defaults, diagnostics);
-
-    fn handle_generic_param<'db>(
-        ctx: &mut TyLoweringContext<'db, '_>,
-        idx: usize,
-        id: GenericParamId,
-        p: GenericParamDataRef<'_>,
-        generic_params: &Generics,
-    ) -> (Option<EarlyBinder<'db, crate::next_solver::GenericArg<'db>>>, bool) {
-        // Each default can only refer to previous parameters.
-        // Type variable default referring to parameter coming
-        // after it is forbidden.
-        ctx.disallow_params_after(idx as u32);
-        match p {
-            GenericParamDataRef::TypeParamData(p) => {
-                let ty = p.default.map(|ty| ctx.lower_ty(ty));
-                (ty.map(|ty| EarlyBinder::bind(ty.into())), p.default.is_some())
-            }
-            GenericParamDataRef::ConstParamData(p) => {
-                let GenericParamId::ConstParamId(id) = id else {
-                    unreachable!("Unexpected lifetime or type argument")
-                };
-
-                let mut val = p.default.map(|c| {
-                    let param_ty = ctx.lower_ty(p.ty);
-                    let c = ctx.lower_const(c, param_ty);
-                    c.into()
-                });
-                (val.map(EarlyBinder::bind), p.default.is_some())
-            }
-            GenericParamDataRef::LifetimeParamData(_) => (None, false),
-        }
-    }
-}
-
-pub(crate) fn generic_defaults_with_diagnostics_cycle_result(
-    _db: &dyn HirDatabase,
-    _def: GenericDefId,
-) -> (GenericDefaults<'_>, Diagnostics) {
-    (GenericDefaults(None), None)
-}
-
-/// Build the signature of a callable item (function, struct or enum variant).
-pub(crate) fn callable_item_signature_query<'db>(
-    db: &'db dyn HirDatabase,
-    def: CallableDefId,
-) -> EarlyBinder<'db, PolyFnSig<'db>> {
-    match def {
-        CallableDefId::FunctionId(f) => fn_sig_for_fn(db, f),
-        CallableDefId::StructId(s) => fn_sig_for_struct_constructor(db, s),
-        CallableDefId::EnumVariantId(e) => fn_sig_for_enum_variant_constructor(db, e),
-    }
-}
-
-fn fn_sig_for_fn<'db>(
-    db: &'db dyn HirDatabase,
-    def: FunctionId,
-) -> EarlyBinder<'db, PolyFnSig<'db>> {
-    let data = db.function_signature(def);
-    let resolver = def.resolver(db);
-    let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
-    let mut ctx_params = TyLoweringContext::new(
-        db,
-        &resolver,
-        &data.store,
-        def.into(),
-        LifetimeElisionKind::for_fn_params(&data),
-    );
-    let params = data.params.iter().map(|&tr| ctx_params.lower_ty(tr));
-
-    let ret = match data.ret_type {
-        Some(ret_type) => {
-            let mut ctx_ret = TyLoweringContext::new(
-                db,
-                &resolver,
-                &data.store,
-                def.into(),
-                LifetimeElisionKind::for_fn_ret(interner),
-            )
-            .with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
-            ctx_ret.lower_ty(ret_type)
-        }
-        None => Ty::new_tup(interner, &[]),
-    };
-
-    let inputs_and_output = Tys::new_from_iter(interner, params.chain(Some(ret)));
-    // If/when we track late bound vars, we need to switch this to not be `dummy`
-    EarlyBinder::bind(rustc_type_ir::Binder::dummy(FnSig {
-        abi: data.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol),
-        c_variadic: data.is_varargs(),
-        safety: if data.is_unsafe() { Safety::Unsafe } else { Safety::Safe },
-        inputs_and_output,
-    }))
-}
-
-fn type_for_adt<'db>(db: &'db dyn HirDatabase, adt: AdtId) -> EarlyBinder<'db, Ty<'db>> {
-    let interner = DbInterner::new_with(db, None, None);
-    let args = GenericArgs::identity_for_item(interner, adt.into());
-    let ty = Ty::new_adt(interner, adt, args);
-    EarlyBinder::bind(ty)
-}
-
-fn fn_sig_for_struct_constructor<'db>(
-    db: &'db dyn HirDatabase,
-    def: StructId,
-) -> EarlyBinder<'db, PolyFnSig<'db>> {
-    let field_tys = db.field_types_ns(def.into());
-    let params = field_tys.iter().map(|(_, ty)| ty.skip_binder());
-    let ret = type_for_adt(db, def.into()).skip_binder();
-
-    let inputs_and_output =
-        Tys::new_from_iter(DbInterner::new_with(db, None, None), params.chain(Some(ret)));
-    EarlyBinder::bind(Binder::dummy(FnSig {
-        abi: FnAbi::RustCall,
-        c_variadic: false,
-        safety: Safety::Safe,
-        inputs_and_output,
-    }))
-}
-
-fn fn_sig_for_enum_variant_constructor<'db>(
-    db: &'db dyn HirDatabase,
-    def: EnumVariantId,
-) -> EarlyBinder<'db, PolyFnSig<'db>> {
-    let field_tys = db.field_types_ns(def.into());
-    let params = field_tys.iter().map(|(_, ty)| ty.skip_binder());
-    let parent = def.lookup(db).parent;
-    let ret = type_for_adt(db, parent.into()).skip_binder();
-
-    let inputs_and_output =
-        Tys::new_from_iter(DbInterner::new_with(db, None, None), params.chain(Some(ret)));
-    EarlyBinder::bind(Binder::dummy(FnSig {
-        abi: FnAbi::RustCall,
-        c_variadic: false,
-        safety: Safety::Safe,
-        inputs_and_output,
-    }))
-}
-
-// FIXME(next-solver): should merge this with `explicit_item_bounds` in some way
-pub(crate) fn associated_ty_item_bounds<'db>(
-    db: &'db dyn HirDatabase,
-    type_alias: TypeAliasId,
-) -> EarlyBinder<'db, BoundExistentialPredicates<'db>> {
-    let trait_ = match type_alias.lookup(db).container {
-        ItemContainerId::TraitId(t) => t,
-        _ => panic!("associated type not in trait"),
-    };
-
-    let type_alias_data = db.type_alias_signature(type_alias);
-    let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db);
-    let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
-    let mut ctx = TyLoweringContext::new(
-        db,
-        &resolver,
-        &type_alias_data.store,
-        type_alias.into(),
-        LifetimeElisionKind::AnonymousReportError,
-    );
-    // FIXME: we should never create non-existential predicates in the first place
-    // For now, use an error type so we don't run into dummy binder issues
-    let self_ty = Ty::new_error(interner, ErrorGuaranteed);
-
-    let mut bounds = Vec::new();
-    for bound in &type_alias_data.bounds {
-        ctx.lower_type_bound(bound, self_ty, false).for_each(|pred| {
-            if let Some(bound) = pred
-                .kind()
-                .map_bound(|c| match c {
-                    rustc_type_ir::ClauseKind::Trait(t) => {
-                        let id = t.def_id();
-                        let is_auto = db.trait_signature(id.0).flags.contains(TraitFlags::AUTO);
-                        if is_auto {
-                            Some(ExistentialPredicate::AutoTrait(t.def_id()))
-                        } else {
-                            Some(ExistentialPredicate::Trait(ExistentialTraitRef::new_from_args(
-                                interner,
-                                t.def_id(),
-                                GenericArgs::new_from_iter(
-                                    interner,
-                                    t.trait_ref.args.iter().skip(1),
-                                ),
-                            )))
-                        }
-                    }
-                    rustc_type_ir::ClauseKind::Projection(p) => Some(
-                        ExistentialPredicate::Projection(ExistentialProjection::new_from_args(
-                            interner,
-                            p.def_id(),
-                            GenericArgs::new_from_iter(
-                                interner,
-                                p.projection_term.args.iter().skip(1),
-                            ),
-                            p.term,
-                        )),
-                    ),
-                    rustc_type_ir::ClauseKind::TypeOutlives(outlives_predicate) => None,
-                    rustc_type_ir::ClauseKind::RegionOutlives(_)
-                    | rustc_type_ir::ClauseKind::ConstArgHasType(_, _)
-                    | rustc_type_ir::ClauseKind::WellFormed(_)
-                    | rustc_type_ir::ClauseKind::ConstEvaluatable(_)
-                    | rustc_type_ir::ClauseKind::HostEffect(_)
-                    | rustc_type_ir::ClauseKind::UnstableFeature(_) => unreachable!(),
-                })
-                .transpose()
-            {
-                bounds.push(bound);
-            }
-        });
-    }
-
-    if !ctx.unsized_types.contains(&self_ty) {
-        let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate());
-        let sized_clause = Binder::dummy(ExistentialPredicate::Trait(ExistentialTraitRef::new(
-            interner,
-            trait_.into(),
-            [] as [crate::next_solver::GenericArg<'_>; 0],
-        )));
-        bounds.push(sized_clause);
-        bounds.shrink_to_fit();
-    }
-
-    EarlyBinder::bind(BoundExistentialPredicates::new_from_iter(interner, bounds))
-}
-
-pub(crate) fn associated_type_by_name_including_super_traits<'db>(
-    db: &'db dyn HirDatabase,
-    trait_ref: TraitRef<'db>,
-    name: &Name,
-) -> Option<(TraitRef<'db>, TypeAliasId)> {
-    let interner = DbInterner::new_with(db, None, None);
-    rustc_type_ir::elaborate::supertraits(interner, Binder::dummy(trait_ref)).find_map(|t| {
-        let trait_id = t.as_ref().skip_binder().def_id.0;
-        let assoc_type = trait_id.trait_items(db).associated_type_by_name(name)?;
-        Some((t.skip_binder(), assoc_type))
-    })
-}
-
-pub fn associated_type_shorthand_candidates(
-    db: &dyn HirDatabase,
-    def: GenericDefId,
-    res: TypeNs,
-    mut cb: impl FnMut(&Name, TypeAliasId) -> bool,
-) -> Option<TypeAliasId> {
-    let interner = DbInterner::new_with(db, None, None);
-    named_associated_type_shorthand_candidates(interner, def, res, None, |name, _, id| {
-        cb(name, id).then_some(id)
-    })
-}
-
-#[tracing::instrument(skip(interner, check_alias))]
-fn named_associated_type_shorthand_candidates<'db, R>(
-    interner: DbInterner<'db>,
-    // If the type parameter is defined in an impl and we're in a method, there
-    // might be additional where clauses to consider
-    def: GenericDefId,
-    res: TypeNs,
-    assoc_name: Option<Name>,
-    mut check_alias: impl FnMut(&Name, TraitRef<'db>, TypeAliasId) -> Option<R>,
-) -> Option<R> {
-    let db = interner.db;
-    let mut search = |t: TraitRef<'db>| -> Option<R> {
-        let trait_id = t.def_id.0;
-        let mut checked_traits = FxHashSet::default();
-        let mut check_trait = |trait_ref: TraitRef<'db>| {
-            let trait_id = trait_ref.def_id.0;
-            let name = &db.trait_signature(trait_id).name;
-            tracing::debug!(?trait_id, ?name);
-            if !checked_traits.insert(trait_id) {
-                return None;
-            }
-            let data = trait_id.trait_items(db);
-
-            tracing::debug!(?data.items);
-            for (name, assoc_id) in &data.items {
-                if let &AssocItemId::TypeAliasId(alias) = assoc_id
-                    && let Some(ty) = check_alias(name, trait_ref, alias)
-                {
-                    return Some(ty);
-                }
-            }
-            None
-        };
-        let mut stack: SmallVec<[_; 4]> = smallvec![t];
-        while let Some(trait_ref) = stack.pop() {
-            if let Some(alias) = check_trait(trait_ref) {
-                return Some(alias);
-            }
-            for pred in generic_predicates_filtered_by(
-                db,
-                GenericDefId::TraitId(trait_ref.def_id.0),
-                PredicateFilter::SelfTrait,
-                // We are likely in the midst of lowering generic predicates of `def`.
-                // So, if we allow `pred == def` we might fall into an infinite recursion.
-                // Actually, we have already checked for the case `pred == def` above as we started
-                // with a stack including `trait_id`
-                |pred| pred != def && pred == GenericDefId::TraitId(trait_ref.def_id.0),
-            )
-            .0
-            .deref()
-            {
-                tracing::debug!(?pred);
-                let sup_trait_ref = match pred.kind().skip_binder() {
-                    rustc_type_ir::ClauseKind::Trait(pred) => pred.trait_ref,
-                    _ => continue,
-                };
-                let sup_trait_ref =
-                    EarlyBinder::bind(sup_trait_ref).instantiate(interner, trait_ref.args);
-                stack.push(sup_trait_ref);
-            }
-            tracing::debug!(?stack);
-        }
-
-        None
-    };
-
-    match res {
-        TypeNs::SelfType(impl_id) => {
-            let trait_ref = db.impl_trait(impl_id)?;
-
-            // FIXME(next-solver): same method in `lower` checks for impl or not
-            // Is that needed here?
-
-            // we're _in_ the impl -- the binders get added back later. Correct,
-            // but it would be nice to make this more explicit
-            search(trait_ref.skip_binder())
-        }
-        TypeNs::GenericParam(param_id) => {
-            // Handle `Self::Type` referring to own associated type in trait definitions
-            // This *must* be done first to avoid cycles with
-            // `generic_predicates_for_param`, but not sure that it's sufficient,
-            if let GenericDefId::TraitId(trait_id) = param_id.parent() {
-                let trait_name = &db.trait_signature(trait_id).name;
-                tracing::debug!(?trait_name);
-                let trait_generics = generics(db, trait_id.into());
-                tracing::debug!(?trait_generics);
-                if trait_generics[param_id.local_id()].is_trait_self() {
-                    let args = crate::next_solver::GenericArgs::identity_for_item(
-                        interner,
-                        trait_id.into(),
-                    );
-                    let trait_ref = TraitRef::new_from_args(interner, trait_id.into(), args);
-                    tracing::debug!(?args, ?trait_ref);
-                    return search(trait_ref);
-                }
-            }
-
-            let predicates =
-                db.generic_predicates_for_param_ns(def, param_id.into(), assoc_name.clone());
-            predicates
-                .iter()
-                .find_map(|pred| match (*pred).kind().skip_binder() {
-                    rustc_type_ir::ClauseKind::Trait(trait_predicate) => Some(trait_predicate),
-                    _ => None,
-                })
-                .and_then(|trait_predicate| {
-                    let trait_ref = trait_predicate.trait_ref;
-                    assert!(
-                        !trait_ref.has_escaping_bound_vars(),
-                        "FIXME unexpected higher-ranked trait bound"
-                    );
-                    search(trait_ref)
-                })
-        }
-        _ => None,
-    }
-}
diff --git a/crates/hir-ty/src/lower_nextsolver/path.rs b/crates/hir-ty/src/lower_nextsolver/path.rs
deleted file mode 100644
index ef2c392..0000000
--- a/crates/hir-ty/src/lower_nextsolver/path.rs
+++ /dev/null
@@ -1,1354 +0,0 @@
-//! A wrapper around [`TyLoweringContext`] specifically for lowering paths.
-
-use std::ops::Deref;
-
-use either::Either;
-use hir_def::{
-    AssocItemId, GenericDefId, GenericParamId, Lookup, TraitId, TypeAliasId,
-    builtin_type::BuiltinType,
-    expr_store::{
-        ExpressionStore, HygieneId,
-        path::{GenericArg, GenericArgs, GenericArgsParentheses, Path, PathSegment, PathSegments},
-    },
-    hir::generics::{
-        GenericParamDataRef, TypeOrConstParamData, TypeParamData, TypeParamProvenance,
-    },
-    resolver::{ResolveValueResult, TypeNs, ValueNs},
-    signatures::TraitFlags,
-    type_ref::{TypeRef, TypeRefId},
-};
-use hir_expand::name::Name;
-use intern::sym;
-use rustc_hash::FxHashSet;
-use rustc_type_ir::{
-    AliasTerm, AliasTy, AliasTyKind, TypeVisitableExt,
-    inherent::{GenericArgs as _, IntoKind, Region as _, SliceLike, Ty as _},
-};
-use smallvec::{SmallVec, smallvec};
-use stdx::never;
-
-use crate::{
-    GenericArgsProhibitedReason, IncorrectGenericsLenKind, PathGenericsSource,
-    PathLoweringDiagnostic, TyDefId, ValueTyDefId,
-    consteval::{unknown_const, unknown_const_as_generic},
-    db::HirDatabase,
-    generics::{Generics, generics},
-    lower::PathDiagnosticCallbackData,
-    lower_nextsolver::{
-        LifetimeElisionKind, PredicateFilter, generic_predicates_filtered_by,
-        named_associated_type_shorthand_candidates,
-    },
-    next_solver::{
-        AdtDef, Binder, Clause, Const, DbInterner, ErrorGuaranteed, Predicate, ProjectionPredicate,
-        Region, SolverDefId, TraitRef, Ty,
-        mapping::{ChalkToNextSolver, convert_binder_to_early_binder},
-    },
-    primitive,
-};
-
-use super::{
-    ImplTraitLoweringMode, TyLoweringContext, associated_type_by_name_including_super_traits,
-    const_param_ty_query, ty_query,
-};
-
-type CallbackData<'a, 'db> = Either<
-    PathDiagnosticCallbackData,
-    crate::infer::diagnostics::PathDiagnosticCallbackData<'a, 'db>,
->;
-
-// We cannot use `&mut dyn FnMut()` because of lifetime issues, and we don't want to use `Box<dyn FnMut()>`
-// because of the allocation, so we create a lifetime-less callback, tailored for our needs.
-pub(crate) struct PathDiagnosticCallback<'a, 'db> {
-    pub(crate) data: CallbackData<'a, 'db>,
-    pub(crate) callback:
-        fn(&CallbackData<'_, 'db>, &mut TyLoweringContext<'db, '_>, PathLoweringDiagnostic),
-}
-
-pub(crate) struct PathLoweringContext<'a, 'b, 'db> {
-    ctx: &'a mut TyLoweringContext<'db, 'b>,
-    on_diagnostic: PathDiagnosticCallback<'a, 'db>,
-    path: &'a Path,
-    segments: PathSegments<'a>,
-    current_segment_idx: usize,
-    /// Contains the previous segment if `current_segment_idx == segments.len()`
-    current_or_prev_segment: PathSegment<'a>,
-}
-
-impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
-    #[inline]
-    pub(crate) fn new(
-        ctx: &'a mut TyLoweringContext<'db, 'b>,
-        on_diagnostic: PathDiagnosticCallback<'a, 'db>,
-        path: &'a Path,
-    ) -> Self {
-        let segments = path.segments();
-        let first_segment = segments.first().unwrap_or(PathSegment::MISSING);
-        Self {
-            ctx,
-            on_diagnostic,
-            path,
-            segments,
-            current_segment_idx: 0,
-            current_or_prev_segment: first_segment,
-        }
-    }
-
-    #[inline]
-    #[cold]
-    fn on_diagnostic(&mut self, diag: PathLoweringDiagnostic) {
-        (self.on_diagnostic.callback)(&self.on_diagnostic.data, self.ctx, diag);
-    }
-
-    #[inline]
-    pub(crate) fn ty_ctx(&mut self) -> &mut TyLoweringContext<'db, 'b> {
-        self.ctx
-    }
-
-    #[inline]
-    fn current_segment_u32(&self) -> u32 {
-        self.current_segment_idx as u32
-    }
-
-    #[inline]
-    fn skip_resolved_segment(&mut self) {
-        if !matches!(self.path, Path::LangItem(..)) {
-            // In lang items, the resolved "segment" is not one of the segments. Perhaps we should've put it
-            // point at -1, but I don't feel this is clearer.
-            self.current_segment_idx += 1;
-        }
-        self.update_current_segment();
-    }
-
-    #[inline]
-    fn update_current_segment(&mut self) {
-        self.current_or_prev_segment =
-            self.segments.get(self.current_segment_idx).unwrap_or(self.current_or_prev_segment);
-    }
-
-    #[inline]
-    pub(crate) fn ignore_last_segment(&mut self) {
-        self.segments = self.segments.strip_last();
-    }
-
-    #[inline]
-    pub(crate) fn set_current_segment(&mut self, segment: usize) {
-        self.current_segment_idx = segment;
-        self.current_or_prev_segment = self
-            .segments
-            .get(segment)
-            .expect("invalid segment passed to PathLoweringContext::set_current_segment()");
-    }
-
-    #[inline]
-    fn with_lifetime_elision<T>(
-        &mut self,
-        lifetime_elision: LifetimeElisionKind<'db>,
-        f: impl FnOnce(&mut PathLoweringContext<'_, '_, 'db>) -> T,
-    ) -> T {
-        let old_lifetime_elision =
-            std::mem::replace(&mut self.ctx.lifetime_elision, lifetime_elision);
-        let result = f(self);
-        self.ctx.lifetime_elision = old_lifetime_elision;
-        result
-    }
-
-    pub(crate) fn lower_ty_relative_path(
-        &mut self,
-        ty: Ty<'db>,
-        // We need the original resolution to lower `Self::AssocTy` correctly
-        res: Option<TypeNs>,
-        infer_args: bool,
-    ) -> (Ty<'db>, Option<TypeNs>) {
-        let remaining_segments = self.segments.len() - self.current_segment_idx;
-        match remaining_segments {
-            0 => (ty, res),
-            1 => {
-                // resolve unselected assoc types
-                (self.select_associated_type(res, infer_args), None)
-            }
-            _ => {
-                // FIXME report error (ambiguous associated type)
-                (Ty::new_error(self.ctx.interner, ErrorGuaranteed), None)
-            }
-        }
-    }
-
-    fn prohibit_parenthesized_generic_args(&mut self) -> bool {
-        if let Some(generic_args) = self.current_or_prev_segment.args_and_bindings {
-            match generic_args.parenthesized {
-                GenericArgsParentheses::No => {}
-                GenericArgsParentheses::ReturnTypeNotation | GenericArgsParentheses::ParenSugar => {
-                    let segment = self.current_segment_u32();
-                    self.on_diagnostic(
-                        PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment },
-                    );
-                    return true;
-                }
-            }
-        }
-        false
-    }
-
-    // When calling this, the current segment is the resolved segment (we don't advance it yet).
-    pub(crate) fn lower_partly_resolved_path(
-        &mut self,
-        resolution: TypeNs,
-        infer_args: bool,
-    ) -> (Ty<'db>, Option<TypeNs>) {
-        let remaining_segments = self.segments.skip(self.current_segment_idx + 1);
-        tracing::debug!(?remaining_segments);
-        let rem_seg_len = remaining_segments.len();
-        tracing::debug!(?rem_seg_len);
-
-        let ty = match resolution {
-            TypeNs::TraitId(trait_) => {
-                let ty = match remaining_segments.len() {
-                    1 => {
-                        let trait_ref = self.lower_trait_ref_from_resolved_path(
-                            trait_,
-                            Ty::new_error(self.ctx.interner, ErrorGuaranteed),
-                            false,
-                        );
-                        tracing::debug!(?trait_ref);
-                        self.skip_resolved_segment();
-                        let segment = self.current_or_prev_segment;
-                        let trait_id = trait_ref.def_id.0;
-                        let found =
-                            trait_id.trait_items(self.ctx.db).associated_type_by_name(segment.name);
-
-                        tracing::debug!(?found);
-                        match found {
-                            Some(associated_ty) => {
-                                // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
-                                // generic params. It's inefficient to splice the `Substitution`s, so we may want
-                                // that method to optionally take parent `Substitution` as we already know them at
-                                // this point (`trait_ref.substitution`).
-                                let substitution = self.substs_from_path_segment(
-                                    associated_ty.into(),
-                                    false,
-                                    None,
-                                    true,
-                                );
-                                let args = crate::next_solver::GenericArgs::new_from_iter(
-                                    self.ctx.interner,
-                                    trait_ref
-                                        .args
-                                        .iter()
-                                        .chain(substitution.iter().skip(trait_ref.args.len())),
-                                );
-                                Ty::new_alias(
-                                    self.ctx.interner,
-                                    AliasTyKind::Projection,
-                                    AliasTy::new_from_args(
-                                        self.ctx.interner,
-                                        associated_ty.into(),
-                                        args,
-                                    ),
-                                )
-                            }
-                            None => {
-                                // FIXME: report error (associated type not found)
-                                Ty::new_error(self.ctx.interner, ErrorGuaranteed)
-                            }
-                        }
-                    }
-                    0 => {
-                        // Trait object type without dyn; this should be handled in upstream. See
-                        // `lower_path()`.
-                        stdx::never!("unexpected fully resolved trait path");
-                        Ty::new_error(self.ctx.interner, ErrorGuaranteed)
-                    }
-                    _ => {
-                        // FIXME report error (ambiguous associated type)
-                        Ty::new_error(self.ctx.interner, ErrorGuaranteed)
-                    }
-                };
-                return (ty, None);
-            }
-            TypeNs::GenericParam(param_id) => {
-                let generics = self.ctx.generics();
-                let idx = generics.type_or_const_param_idx(param_id.into());
-                match idx {
-                    None => {
-                        never!("no matching generics");
-                        Ty::new_error(self.ctx.interner, ErrorGuaranteed)
-                    }
-                    Some(idx) => {
-                        let (pidx, param) = generics.iter().nth(idx).unwrap();
-                        assert_eq!(pidx, param_id.into());
-                        let p = match param {
-                            GenericParamDataRef::TypeParamData(p) => p,
-                            _ => unreachable!(),
-                        };
-                        self.ctx.type_param(
-                            param_id,
-                            idx as u32,
-                            p.name
-                                .as_ref()
-                                .map_or_else(|| sym::MISSING_NAME.clone(), |p| p.symbol().clone()),
-                        )
-                    }
-                }
-            }
-            TypeNs::SelfType(impl_id) => self.ctx.db.impl_self_ty(impl_id).skip_binder(),
-            TypeNs::AdtSelfType(adt) => {
-                let args = crate::next_solver::GenericArgs::identity_for_item(
-                    self.ctx.interner,
-                    adt.into(),
-                );
-                Ty::new_adt(self.ctx.interner, adt, args)
-            }
-
-            TypeNs::AdtId(it) => self.lower_path_inner(it.into(), infer_args),
-            TypeNs::BuiltinType(it) => self.lower_path_inner(it.into(), infer_args),
-            TypeNs::TypeAliasId(it) => self.lower_path_inner(it.into(), infer_args),
-            // FIXME: report error
-            TypeNs::EnumVariantId(_) | TypeNs::ModuleId(_) => {
-                return (Ty::new_error(self.ctx.interner, ErrorGuaranteed), None);
-            }
-        };
-
-        tracing::debug!(?ty);
-
-        self.skip_resolved_segment();
-        self.lower_ty_relative_path(ty, Some(resolution), infer_args)
-    }
-
-    fn handle_type_ns_resolution(&mut self, resolution: &TypeNs) {
-        let mut prohibit_generics_on_resolved = |reason| {
-            if self.current_or_prev_segment.args_and_bindings.is_some() {
-                let segment = self.current_segment_u32();
-                self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
-                    segment,
-                    reason,
-                });
-            }
-        };
-
-        match resolution {
-            TypeNs::SelfType(_) => {
-                prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy)
-            }
-            TypeNs::GenericParam(_) => {
-                prohibit_generics_on_resolved(GenericArgsProhibitedReason::TyParam)
-            }
-            TypeNs::AdtSelfType(_) => {
-                prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy)
-            }
-            TypeNs::BuiltinType(_) => {
-                prohibit_generics_on_resolved(GenericArgsProhibitedReason::PrimitiveTy)
-            }
-            TypeNs::ModuleId(_) => {
-                prohibit_generics_on_resolved(GenericArgsProhibitedReason::Module)
-            }
-            TypeNs::AdtId(_)
-            | TypeNs::EnumVariantId(_)
-            | TypeNs::TypeAliasId(_)
-            | TypeNs::TraitId(_) => {}
-        }
-    }
-
-    pub(crate) fn resolve_path_in_type_ns_fully(&mut self) -> Option<TypeNs> {
-        let (res, unresolved) = self.resolve_path_in_type_ns()?;
-        if unresolved.is_some() {
-            return None;
-        }
-        Some(res)
-    }
-
-    #[tracing::instrument(skip(self), ret)]
-    pub(crate) fn resolve_path_in_type_ns(&mut self) -> Option<(TypeNs, Option<usize>)> {
-        let (resolution, remaining_index, _, prefix_info) =
-            self.ctx.resolver.resolve_path_in_type_ns_with_prefix_info(self.ctx.db, self.path)?;
-
-        let segments = self.segments;
-        if segments.is_empty() || matches!(self.path, Path::LangItem(..)) {
-            // `segments.is_empty()` can occur with `self`.
-            return Some((resolution, remaining_index));
-        }
-
-        let (module_segments, resolved_segment_idx, enum_segment) = match remaining_index {
-            None if prefix_info.enum_variant => {
-                (segments.strip_last_two(), segments.len() - 1, Some(segments.len() - 2))
-            }
-            None => (segments.strip_last(), segments.len() - 1, None),
-            Some(i) => (segments.take(i - 1), i - 1, None),
-        };
-
-        self.current_segment_idx = resolved_segment_idx;
-        self.current_or_prev_segment =
-            segments.get(resolved_segment_idx).expect("should have resolved segment");
-
-        if matches!(self.path, Path::BarePath(..)) {
-            // Bare paths cannot have generics, so skip them as an optimization.
-            return Some((resolution, remaining_index));
-        }
-
-        for (i, mod_segment) in module_segments.iter().enumerate() {
-            if mod_segment.args_and_bindings.is_some() {
-                self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
-                    segment: i as u32,
-                    reason: GenericArgsProhibitedReason::Module,
-                });
-            }
-        }
-
-        if let Some(enum_segment) = enum_segment
-            && segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some())
-            && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some())
-        {
-            self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
-                segment: (enum_segment + 1) as u32,
-                reason: GenericArgsProhibitedReason::EnumVariant,
-            });
-        }
-
-        self.handle_type_ns_resolution(&resolution);
-
-        Some((resolution, remaining_index))
-    }
-
-    pub(crate) fn resolve_path_in_value_ns(
-        &mut self,
-        hygiene_id: HygieneId,
-    ) -> Option<ResolveValueResult> {
-        let (res, prefix_info) = self.ctx.resolver.resolve_path_in_value_ns_with_prefix_info(
-            self.ctx.db,
-            self.path,
-            hygiene_id,
-        )?;
-
-        let segments = self.segments;
-        if segments.is_empty() || matches!(self.path, Path::LangItem(..)) {
-            // `segments.is_empty()` can occur with `self`.
-            return Some(res);
-        }
-
-        let (mod_segments, enum_segment, resolved_segment_idx) = match res {
-            ResolveValueResult::Partial(_, unresolved_segment, _) => {
-                (segments.take(unresolved_segment - 1), None, unresolved_segment - 1)
-            }
-            ResolveValueResult::ValueNs(ValueNs::EnumVariantId(_), _)
-                if prefix_info.enum_variant =>
-            {
-                (segments.strip_last_two(), segments.len().checked_sub(2), segments.len() - 1)
-            }
-            ResolveValueResult::ValueNs(..) => (segments.strip_last(), None, segments.len() - 1),
-        };
-
-        self.current_segment_idx = resolved_segment_idx;
-        self.current_or_prev_segment =
-            segments.get(resolved_segment_idx).expect("should have resolved segment");
-
-        for (i, mod_segment) in mod_segments.iter().enumerate() {
-            if mod_segment.args_and_bindings.is_some() {
-                self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
-                    segment: i as u32,
-                    reason: GenericArgsProhibitedReason::Module,
-                });
-            }
-        }
-
-        if let Some(enum_segment) = enum_segment
-            && segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some())
-            && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some())
-        {
-            self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
-                segment: (enum_segment + 1) as u32,
-                reason: GenericArgsProhibitedReason::EnumVariant,
-            });
-        }
-
-        match &res {
-            ResolveValueResult::ValueNs(resolution, _) => {
-                let resolved_segment_idx = self.current_segment_u32();
-                let resolved_segment = self.current_or_prev_segment;
-
-                let mut prohibit_generics_on_resolved = |reason| {
-                    if resolved_segment.args_and_bindings.is_some() {
-                        self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited {
-                            segment: resolved_segment_idx,
-                            reason,
-                        });
-                    }
-                };
-
-                match resolution {
-                    ValueNs::ImplSelf(_) => {
-                        prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy)
-                    }
-                    // FIXME: rustc generates E0107 (incorrect number of generic arguments) and not
-                    // E0109 (generic arguments provided for a type that doesn't accept them) for
-                    // consts and statics, presumably as a defense against future in which consts
-                    // and statics can be generic, or just because it was easier for rustc implementors.
-                    // That means we'll show the wrong error code. Because of us it's easier to do it
-                    // this way :)
-                    ValueNs::GenericParam(_) => {
-                        prohibit_generics_on_resolved(GenericArgsProhibitedReason::Const)
-                    }
-                    ValueNs::StaticId(_) => {
-                        prohibit_generics_on_resolved(GenericArgsProhibitedReason::Static)
-                    }
-                    ValueNs::LocalBinding(_) => {
-                        prohibit_generics_on_resolved(GenericArgsProhibitedReason::LocalVariable)
-                    }
-                    ValueNs::FunctionId(_)
-                    | ValueNs::StructId(_)
-                    | ValueNs::EnumVariantId(_)
-                    | ValueNs::ConstId(_) => {}
-                }
-            }
-            ResolveValueResult::Partial(resolution, _, _) => {
-                self.handle_type_ns_resolution(resolution);
-            }
-        };
-        Some(res)
-    }
-
-    #[tracing::instrument(skip(self), ret)]
-    fn select_associated_type(&mut self, res: Option<TypeNs>, infer_args: bool) -> Ty<'db> {
-        let interner = self.ctx.interner;
-        let Some(res) = res else {
-            return Ty::new_error(self.ctx.interner, ErrorGuaranteed);
-        };
-        let db = self.ctx.db;
-        let def = self.ctx.def;
-        let segment = self.current_or_prev_segment;
-        let assoc_name = segment.name;
-        let mut check_alias = |name: &Name, t: TraitRef<'db>, associated_ty: TypeAliasId| {
-            if name != assoc_name {
-                return None;
-            }
-
-            // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
-            // generic params. It's inefficient to splice the `Substitution`s, so we may want
-            // that method to optionally take parent `Substitution` as we already know them at
-            // this point (`t.substitution`).
-            let substs =
-                self.substs_from_path_segment(associated_ty.into(), infer_args, None, true);
-
-            let substs = crate::next_solver::GenericArgs::new_from_iter(
-                interner,
-                t.args.iter().chain(substs.iter().skip(t.args.len())),
-            );
-
-            Some(Ty::new_alias(
-                interner,
-                AliasTyKind::Projection,
-                AliasTy::new(interner, associated_ty.into(), substs),
-            ))
-        };
-        named_associated_type_shorthand_candidates(
-            interner,
-            def,
-            res,
-            Some(assoc_name.clone()),
-            check_alias,
-        )
-        .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed))
-    }
-
-    fn lower_path_inner(&mut self, typeable: TyDefId, infer_args: bool) -> Ty<'db> {
-        let generic_def = match typeable {
-            TyDefId::BuiltinType(builtinty) => {
-                return Ty::from_builtin_type(self.ctx.interner, builtinty);
-            }
-            TyDefId::AdtId(it) => it.into(),
-            TyDefId::TypeAliasId(it) => it.into(),
-        };
-        let args = self.substs_from_path_segment(generic_def, infer_args, None, false);
-        let ty = ty_query(self.ctx.db, typeable);
-        ty.instantiate(self.ctx.interner, args)
-    }
-
-    /// Collect generic arguments from a path into a `Substs`. See also
-    /// `create_substs_for_ast_path` and `def_to_ty` in rustc.
-    pub(crate) fn substs_from_path(
-        &mut self,
-        // Note that we don't call `db.value_type(resolved)` here,
-        // `ValueTyDefId` is just a convenient way to pass generics and
-        // special-case enum variants
-        resolved: ValueTyDefId,
-        infer_args: bool,
-        lowering_assoc_type_generics: bool,
-    ) -> crate::next_solver::GenericArgs<'db> {
-        let interner = self.ctx.interner;
-        let prev_current_segment_idx = self.current_segment_idx;
-        let prev_current_segment = self.current_or_prev_segment;
-
-        let generic_def = match resolved {
-            ValueTyDefId::FunctionId(it) => it.into(),
-            ValueTyDefId::StructId(it) => it.into(),
-            ValueTyDefId::UnionId(it) => it.into(),
-            ValueTyDefId::ConstId(it) => it.into(),
-            ValueTyDefId::StaticId(_) => {
-                return crate::next_solver::GenericArgs::new_from_iter(interner, []);
-            }
-            ValueTyDefId::EnumVariantId(var) => {
-                // the generic args for an enum variant may be either specified
-                // on the segment referring to the enum, or on the segment
-                // referring to the variant. So `Option::<T>::None` and
-                // `Option::None::<T>` are both allowed (though the former is
-                // FIXME: This isn't strictly correct, enum variants may be used not through the enum
-                // (via `use Enum::Variant`). The resolver returns whether they were, but we don't have its result
-                // available here. The worst that can happen is that we will show some confusing diagnostics to the user,
-                // if generics exist on the module and they don't match with the variant.
-                // preferred). See also `def_ids_for_path_segments` in rustc.
-                //
-                // `wrapping_sub(1)` will return a number which `get` will return None for if current_segment_idx<2.
-                // This simplifies the code a bit.
-                let penultimate_idx = self.current_segment_idx.wrapping_sub(1);
-                let penultimate = self.segments.get(penultimate_idx);
-                if let Some(penultimate) = penultimate
-                    && self.current_or_prev_segment.args_and_bindings.is_none()
-                    && penultimate.args_and_bindings.is_some()
-                {
-                    self.current_segment_idx = penultimate_idx;
-                    self.current_or_prev_segment = penultimate;
-                }
-                var.lookup(self.ctx.db).parent.into()
-            }
-        };
-        let result = self.substs_from_path_segment(
-            generic_def,
-            infer_args,
-            None,
-            lowering_assoc_type_generics,
-        );
-        self.current_segment_idx = prev_current_segment_idx;
-        self.current_or_prev_segment = prev_current_segment;
-        result
-    }
-
-    pub(crate) fn substs_from_path_segment(
-        &mut self,
-        def: GenericDefId,
-        infer_args: bool,
-        explicit_self_ty: Option<Ty<'db>>,
-        lowering_assoc_type_generics: bool,
-    ) -> crate::next_solver::GenericArgs<'db> {
-        let old_lifetime_elision = self.ctx.lifetime_elision.clone();
-
-        if let Some(args) = self.current_or_prev_segment.args_and_bindings
-            && args.parenthesized != GenericArgsParentheses::No
-        {
-            let prohibit_parens = match def {
-                GenericDefId::TraitId(trait_) => {
-                    // RTN is prohibited anyways if we got here.
-                    let is_rtn = args.parenthesized == GenericArgsParentheses::ReturnTypeNotation;
-                    let is_fn_trait = self
-                        .ctx
-                        .db
-                        .trait_signature(trait_)
-                        .flags
-                        .contains(TraitFlags::RUSTC_PAREN_SUGAR);
-                    is_rtn || !is_fn_trait
-                }
-                _ => true,
-            };
-
-            if prohibit_parens {
-                let segment = self.current_segment_u32();
-                self.on_diagnostic(
-                    PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment },
-                );
-
-                return unknown_subst(self.ctx.interner, def);
-            }
-
-            // `Fn()`-style generics are treated like functions for the purpose of lifetime elision.
-            self.ctx.lifetime_elision =
-                LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false };
-        }
-
-        let result = self.substs_from_args_and_bindings(
-            self.current_or_prev_segment.args_and_bindings,
-            def,
-            infer_args,
-            explicit_self_ty,
-            PathGenericsSource::Segment(self.current_segment_u32()),
-            lowering_assoc_type_generics,
-            self.ctx.lifetime_elision.clone(),
-        );
-        self.ctx.lifetime_elision = old_lifetime_elision;
-        result
-    }
-
-    pub(super) fn substs_from_args_and_bindings(
-        &mut self,
-        args_and_bindings: Option<&GenericArgs>,
-        def: GenericDefId,
-        infer_args: bool,
-        explicit_self_ty: Option<Ty<'db>>,
-        generics_source: PathGenericsSource,
-        lowering_assoc_type_generics: bool,
-        lifetime_elision: LifetimeElisionKind<'db>,
-    ) -> crate::next_solver::GenericArgs<'db> {
-        struct LowererCtx<'a, 'b, 'c, 'db> {
-            ctx: &'a mut PathLoweringContext<'b, 'c, 'db>,
-            generics_source: PathGenericsSource,
-        }
-
-        impl<'db> GenericArgsLowerer<'db> for LowererCtx<'_, '_, '_, 'db> {
-            fn report_len_mismatch(
-                &mut self,
-                def: GenericDefId,
-                provided_count: u32,
-                expected_count: u32,
-                kind: IncorrectGenericsLenKind,
-            ) {
-                self.ctx.on_diagnostic(PathLoweringDiagnostic::IncorrectGenericsLen {
-                    generics_source: self.generics_source,
-                    provided_count,
-                    expected_count,
-                    kind,
-                    def,
-                });
-            }
-
-            fn report_arg_mismatch(
-                &mut self,
-                param_id: GenericParamId,
-                arg_idx: u32,
-                has_self_arg: bool,
-            ) {
-                self.ctx.on_diagnostic(PathLoweringDiagnostic::IncorrectGenericsOrder {
-                    generics_source: self.generics_source,
-                    param_id,
-                    arg_idx,
-                    has_self_arg,
-                });
-            }
-
-            fn provided_kind(
-                &mut self,
-                param_id: GenericParamId,
-                param: GenericParamDataRef<'_>,
-                arg: &GenericArg,
-            ) -> crate::next_solver::GenericArg<'db> {
-                match (param, *arg) {
-                    (GenericParamDataRef::LifetimeParamData(_), GenericArg::Lifetime(lifetime)) => {
-                        self.ctx.ctx.lower_lifetime(lifetime).into()
-                    }
-                    (GenericParamDataRef::TypeParamData(_), GenericArg::Type(type_ref)) => {
-                        self.ctx.ctx.lower_ty(type_ref).into()
-                    }
-                    (GenericParamDataRef::ConstParamData(_), GenericArg::Const(konst)) => {
-                        let GenericParamId::ConstParamId(const_id) = param_id else {
-                            unreachable!("non-const param ID for const param");
-                        };
-                        self.ctx
-                            .ctx
-                            .lower_const(konst, const_param_ty_query(self.ctx.ctx.db, const_id))
-                            .into()
-                    }
-                    _ => unreachable!("unmatching param kinds were passed to `provided_kind()`"),
-                }
-            }
-
-            fn provided_type_like_const(
-                &mut self,
-                const_ty: Ty<'db>,
-                arg: TypeLikeConst<'_>,
-            ) -> crate::next_solver::Const<'db> {
-                match arg {
-                    TypeLikeConst::Path(path) => self.ctx.ctx.lower_path_as_const(path, const_ty),
-                    TypeLikeConst::Infer => unknown_const(const_ty),
-                }
-            }
-
-            fn inferred_kind(
-                &mut self,
-                def: GenericDefId,
-                param_id: GenericParamId,
-                param: GenericParamDataRef<'_>,
-                infer_args: bool,
-                preceding_args: &[crate::next_solver::GenericArg<'db>],
-            ) -> crate::next_solver::GenericArg<'db> {
-                let default = || {
-                    self.ctx.ctx.db.generic_defaults(def).get(preceding_args.len()).map(|default| {
-                        convert_binder_to_early_binder(
-                            self.ctx.ctx.interner,
-                            def,
-                            default.to_nextsolver(self.ctx.ctx.interner),
-                        )
-                        .instantiate(self.ctx.ctx.interner, preceding_args)
-                    })
-                };
-                match param {
-                    GenericParamDataRef::LifetimeParamData(_) => {
-                        Region::new(self.ctx.ctx.interner, rustc_type_ir::ReError(ErrorGuaranteed))
-                            .into()
-                    }
-                    GenericParamDataRef::TypeParamData(param) => {
-                        if !infer_args
-                            && param.default.is_some()
-                            && let Some(default) = default()
-                        {
-                            return default;
-                        }
-                        Ty::new_error(self.ctx.ctx.interner, ErrorGuaranteed).into()
-                    }
-                    GenericParamDataRef::ConstParamData(param) => {
-                        if !infer_args
-                            && param.default.is_some()
-                            && let Some(default) = default()
-                        {
-                            return default;
-                        }
-                        let GenericParamId::ConstParamId(const_id) = param_id else {
-                            unreachable!("non-const param ID for const param");
-                        };
-                        unknown_const_as_generic(const_param_ty_query(self.ctx.ctx.db, const_id))
-                    }
-                }
-            }
-
-            fn parent_arg(
-                &mut self,
-                param_id: GenericParamId,
-            ) -> crate::next_solver::GenericArg<'db> {
-                match param_id {
-                    GenericParamId::TypeParamId(_) => {
-                        Ty::new_error(self.ctx.ctx.interner, ErrorGuaranteed).into()
-                    }
-                    GenericParamId::ConstParamId(const_id) => {
-                        unknown_const_as_generic(const_param_ty_query(self.ctx.ctx.db, const_id))
-                    }
-                    GenericParamId::LifetimeParamId(_) => {
-                        Region::new(self.ctx.ctx.interner, rustc_type_ir::ReError(ErrorGuaranteed))
-                            .into()
-                    }
-                }
-            }
-
-            fn report_elided_lifetimes_in_path(
-                &mut self,
-                def: GenericDefId,
-                expected_count: u32,
-                hard_error: bool,
-            ) {
-                self.ctx.on_diagnostic(PathLoweringDiagnostic::ElidedLifetimesInPath {
-                    generics_source: self.generics_source,
-                    def,
-                    expected_count,
-                    hard_error,
-                });
-            }
-
-            fn report_elision_failure(&mut self, def: GenericDefId, expected_count: u32) {
-                self.ctx.on_diagnostic(PathLoweringDiagnostic::ElisionFailure {
-                    generics_source: self.generics_source,
-                    def,
-                    expected_count,
-                });
-            }
-
-            fn report_missing_lifetime(&mut self, def: GenericDefId, expected_count: u32) {
-                self.ctx.on_diagnostic(PathLoweringDiagnostic::MissingLifetime {
-                    generics_source: self.generics_source,
-                    def,
-                    expected_count,
-                });
-            }
-        }
-
-        substs_from_args_and_bindings(
-            self.ctx.db,
-            self.ctx.store,
-            args_and_bindings,
-            def,
-            infer_args,
-            lifetime_elision,
-            lowering_assoc_type_generics,
-            explicit_self_ty,
-            &mut LowererCtx { ctx: self, generics_source },
-        )
-    }
-
-    pub(crate) fn lower_trait_ref_from_resolved_path(
-        &mut self,
-        resolved: TraitId,
-        explicit_self_ty: Ty<'db>,
-        infer_args: bool,
-    ) -> TraitRef<'db> {
-        let args = self.trait_ref_substs_from_path(resolved, explicit_self_ty, infer_args);
-        TraitRef::new_from_args(self.ctx.interner, resolved.into(), args)
-    }
-
-    fn trait_ref_substs_from_path(
-        &mut self,
-        resolved: TraitId,
-        explicit_self_ty: Ty<'db>,
-        infer_args: bool,
-    ) -> crate::next_solver::GenericArgs<'db> {
-        self.substs_from_path_segment(resolved.into(), infer_args, Some(explicit_self_ty), false)
-    }
-
-    pub(super) fn assoc_type_bindings_from_type_bound<'c>(
-        mut self,
-        trait_ref: TraitRef<'db>,
-    ) -> Option<impl Iterator<Item = Clause<'db>> + use<'a, 'b, 'c, 'db>> {
-        let interner = self.ctx.interner;
-        self.current_or_prev_segment.args_and_bindings.map(|args_and_bindings| {
-            args_and_bindings.bindings.iter().enumerate().flat_map(move |(binding_idx, binding)| {
-                let found = associated_type_by_name_including_super_traits(
-                    self.ctx.db,
-                    trait_ref,
-                    &binding.name,
-                );
-                let (super_trait_ref, associated_ty) = match found {
-                    None => return SmallVec::new(),
-                    Some(t) => t,
-                };
-                let args =
-                    self.with_lifetime_elision(LifetimeElisionKind::AnonymousReportError, |this| {
-                        // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
-                        // generic params. It's inefficient to splice the `Substitution`s, so we may want
-                        // that method to optionally take parent `Substitution` as we already know them at
-                        // this point (`super_trait_ref.substitution`).
-                        this.substs_from_args_and_bindings(
-                            binding.args.as_ref(),
-                            associated_ty.into(),
-                            false, // this is not relevant
-                            Some(super_trait_ref.self_ty()),
-                            PathGenericsSource::AssocType {
-                                segment: this.current_segment_u32(),
-                                assoc_type: binding_idx as u32,
-                            },
-                            false,
-                            this.ctx.lifetime_elision.clone(),
-                        )
-                    });
-                let args = crate::next_solver::GenericArgs::new_from_iter(
-                    interner,
-                    super_trait_ref.args.iter().chain(args.iter().skip(super_trait_ref.args.len())),
-                );
-                let projection_term =
-                    AliasTerm::new_from_args(interner, associated_ty.into(), args);
-                let mut predicates: SmallVec<[_; 1]> = SmallVec::with_capacity(
-                    binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
-                );
-                if let Some(type_ref) = binding.type_ref {
-                    let lifetime_elision =
-                        if args_and_bindings.parenthesized == GenericArgsParentheses::ParenSugar {
-                            // `Fn()`-style generics are elided like functions. This is `Output` (we lower to it in hir-def).
-                            LifetimeElisionKind::for_fn_ret(self.ctx.interner)
-                        } else {
-                            self.ctx.lifetime_elision.clone()
-                        };
-                    self.with_lifetime_elision(lifetime_elision, |this| {
-                        match (&this.ctx.store[type_ref], this.ctx.impl_trait_mode.mode) {
-                            (TypeRef::ImplTrait(_), ImplTraitLoweringMode::Disallowed) => (),
-                            (
-                                _,
-                                ImplTraitLoweringMode::Disallowed | ImplTraitLoweringMode::Opaque,
-                            ) => {
-                                let ty = this.ctx.lower_ty(type_ref);
-                                let pred = Clause(Predicate::new(
-                                    interner,
-                                    Binder::dummy(rustc_type_ir::PredicateKind::Clause(
-                                        rustc_type_ir::ClauseKind::Projection(
-                                            ProjectionPredicate {
-                                                projection_term,
-                                                term: ty.into(),
-                                            },
-                                        ),
-                                    )),
-                                ));
-                                predicates.push(pred);
-                            }
-                        }
-                    })
-                }
-                for bound in binding.bounds.iter() {
-                    predicates.extend(self.ctx.lower_type_bound(
-                        bound,
-                        Ty::new_alias(
-                            self.ctx.interner,
-                            AliasTyKind::Projection,
-                            AliasTy::new_from_args(self.ctx.interner, associated_ty.into(), args),
-                        ),
-                        false,
-                    ));
-                }
-                predicates
-            })
-        })
-    }
-}
-
-/// A const that were parsed like a type.
-pub(crate) enum TypeLikeConst<'a> {
-    Infer,
-    Path(&'a Path),
-}
-
-pub(crate) trait GenericArgsLowerer<'db> {
-    fn report_elided_lifetimes_in_path(
-        &mut self,
-        def: GenericDefId,
-        expected_count: u32,
-        hard_error: bool,
-    );
-
-    fn report_elision_failure(&mut self, def: GenericDefId, expected_count: u32);
-
-    fn report_missing_lifetime(&mut self, def: GenericDefId, expected_count: u32);
-
-    fn report_len_mismatch(
-        &mut self,
-        def: GenericDefId,
-        provided_count: u32,
-        expected_count: u32,
-        kind: IncorrectGenericsLenKind,
-    );
-
-    fn report_arg_mismatch(&mut self, param_id: GenericParamId, arg_idx: u32, has_self_arg: bool);
-
-    fn provided_kind(
-        &mut self,
-        param_id: GenericParamId,
-        param: GenericParamDataRef<'_>,
-        arg: &GenericArg,
-    ) -> crate::next_solver::GenericArg<'db>;
-
-    fn provided_type_like_const(&mut self, const_ty: Ty<'db>, arg: TypeLikeConst<'_>)
-    -> Const<'db>;
-
-    fn inferred_kind(
-        &mut self,
-        def: GenericDefId,
-        param_id: GenericParamId,
-        param: GenericParamDataRef<'_>,
-        infer_args: bool,
-        preceding_args: &[crate::next_solver::GenericArg<'db>],
-    ) -> crate::next_solver::GenericArg<'db>;
-
-    fn parent_arg(&mut self, param_id: GenericParamId) -> crate::next_solver::GenericArg<'db>;
-}
-
-/// Returns true if there was an error.
-fn check_generic_args_len<'db>(
-    args_and_bindings: Option<&GenericArgs>,
-    def: GenericDefId,
-    def_generics: &Generics,
-    infer_args: bool,
-    lifetime_elision: &LifetimeElisionKind<'db>,
-    lowering_assoc_type_generics: bool,
-    ctx: &mut impl GenericArgsLowerer<'db>,
-) -> bool {
-    let mut had_error = false;
-
-    let (mut provided_lifetimes_count, mut provided_types_and_consts_count) = (0usize, 0usize);
-    if let Some(args_and_bindings) = args_and_bindings {
-        let args_no_self = &args_and_bindings.args[usize::from(args_and_bindings.has_self_type)..];
-        for arg in args_no_self {
-            match arg {
-                GenericArg::Lifetime(_) => provided_lifetimes_count += 1,
-                GenericArg::Type(_) | GenericArg::Const(_) => provided_types_and_consts_count += 1,
-            }
-        }
-    }
-
-    let lifetime_args_len = def_generics.len_lifetimes_self();
-    if provided_lifetimes_count == 0
-        && lifetime_args_len > 0
-        && (!lowering_assoc_type_generics || infer_args)
-    {
-        // In generic associated types, we never allow inferring the lifetimes, but only in type context, that is
-        // when `infer_args == false`. In expression/pattern context we always allow inferring them, even for GATs.
-        match lifetime_elision {
-            &LifetimeElisionKind::AnonymousCreateParameter { report_in_path } => {
-                ctx.report_elided_lifetimes_in_path(def, lifetime_args_len as u32, report_in_path);
-                had_error |= report_in_path;
-            }
-            LifetimeElisionKind::AnonymousReportError => {
-                ctx.report_missing_lifetime(def, lifetime_args_len as u32);
-                had_error = true
-            }
-            LifetimeElisionKind::ElisionFailure => {
-                ctx.report_elision_failure(def, lifetime_args_len as u32);
-                had_error = true;
-            }
-            LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: _ } => {
-                // FIXME: Check there are other lifetimes in scope, and error/lint.
-            }
-            LifetimeElisionKind::Elided(_) => {
-                ctx.report_elided_lifetimes_in_path(def, lifetime_args_len as u32, false);
-            }
-            LifetimeElisionKind::Infer => {
-                // Allow eliding lifetimes.
-            }
-        }
-    } else if lifetime_args_len != provided_lifetimes_count {
-        ctx.report_len_mismatch(
-            def,
-            provided_lifetimes_count as u32,
-            lifetime_args_len as u32,
-            IncorrectGenericsLenKind::Lifetimes,
-        );
-        had_error = true;
-    }
-
-    let defaults_count =
-        def_generics.iter_self_type_or_consts().filter(|(_, param)| param.has_default()).count();
-    let named_type_and_const_params_count = def_generics
-        .iter_self_type_or_consts()
-        .filter(|(_, param)| match param {
-            TypeOrConstParamData::TypeParamData(param) => {
-                param.provenance == TypeParamProvenance::TypeParamList
-            }
-            TypeOrConstParamData::ConstParamData(_) => true,
-        })
-        .count();
-    let expected_max = named_type_and_const_params_count;
-    let expected_min =
-        if infer_args { 0 } else { named_type_and_const_params_count - defaults_count };
-    if provided_types_and_consts_count < expected_min
-        || expected_max < provided_types_and_consts_count
-    {
-        ctx.report_len_mismatch(
-            def,
-            provided_types_and_consts_count as u32,
-            named_type_and_const_params_count as u32,
-            IncorrectGenericsLenKind::TypesAndConsts,
-        );
-        had_error = true;
-    }
-
-    had_error
-}
-
-pub(crate) fn substs_from_args_and_bindings<'db>(
-    db: &'db dyn HirDatabase,
-    store: &ExpressionStore,
-    args_and_bindings: Option<&GenericArgs>,
-    def: GenericDefId,
-    mut infer_args: bool,
-    lifetime_elision: LifetimeElisionKind<'db>,
-    lowering_assoc_type_generics: bool,
-    explicit_self_ty: Option<Ty<'db>>,
-    ctx: &mut impl GenericArgsLowerer<'db>,
-) -> crate::next_solver::GenericArgs<'db> {
-    let interner = DbInterner::new_with(db, None, None);
-
-    tracing::debug!(?args_and_bindings);
-
-    // Order is
-    // - Parent parameters
-    // - Optional Self parameter
-    // - Lifetime parameters
-    // - Type or Const parameters
-    let def_generics = generics(db, def);
-    let args_slice = args_and_bindings.map(|it| &*it.args).unwrap_or_default();
-
-    // We do not allow inference if there are specified args, i.e. we do not allow partial inference.
-    let has_non_lifetime_args =
-        args_slice.iter().any(|arg| !matches!(arg, GenericArg::Lifetime(_)));
-    infer_args &= !has_non_lifetime_args;
-
-    let had_count_error = check_generic_args_len(
-        args_and_bindings,
-        def,
-        &def_generics,
-        infer_args,
-        &lifetime_elision,
-        lowering_assoc_type_generics,
-        ctx,
-    );
-
-    let mut substs = Vec::with_capacity(def_generics.len());
-
-    substs.extend(def_generics.iter_parent_id().map(|id| ctx.parent_arg(id)));
-
-    let mut args = args_slice.iter().enumerate().peekable();
-    let mut params = def_generics.iter_self().peekable();
-
-    // If we encounter a type or const when we expect a lifetime, we infer the lifetimes.
-    // If we later encounter a lifetime, we know that the arguments were provided in the
-    // wrong order. `force_infer_lt` records the type or const that forced lifetimes to be
-    // inferred, so we can use it for diagnostics later.
-    let mut force_infer_lt = None;
-
-    let has_self_arg = args_and_bindings.is_some_and(|it| it.has_self_type);
-    // First, handle `Self` parameter. Consume it from the args if provided, otherwise from `explicit_self_ty`,
-    // and lastly infer it.
-    if let Some(&(
-        self_param_id,
-        self_param @ GenericParamDataRef::TypeParamData(TypeParamData {
-            provenance: TypeParamProvenance::TraitSelf,
-            ..
-        }),
-    )) = params.peek()
-    {
-        let self_ty = if has_self_arg {
-            let (_, self_ty) = args.next().expect("has_self_type=true, should have Self type");
-            ctx.provided_kind(self_param_id, self_param, self_ty)
-        } else {
-            explicit_self_ty.map(|it| it.into()).unwrap_or_else(|| {
-                ctx.inferred_kind(def, self_param_id, self_param, infer_args, &substs)
-            })
-        };
-        params.next();
-        substs.push(self_ty);
-    }
-
-    loop {
-        // We're going to iterate through the generic arguments that the user
-        // provided, matching them with the generic parameters we expect.
-        // Mismatches can occur as a result of elided lifetimes, or for malformed
-        // input. We try to handle both sensibly.
-        match (args.peek(), params.peek()) {
-            (Some(&(arg_idx, arg)), Some(&(param_id, param))) => match (arg, param) {
-                (GenericArg::Type(_), GenericParamDataRef::TypeParamData(type_param))
-                    if type_param.provenance == TypeParamProvenance::ArgumentImplTrait =>
-                {
-                    // Do not allow specifying `impl Trait` explicitly. We already err at that, but if we won't handle it here
-                    // we will handle it as if it was specified, instead of inferring it.
-                    substs.push(ctx.inferred_kind(def, param_id, param, infer_args, &substs));
-                    params.next();
-                }
-                (GenericArg::Lifetime(_), GenericParamDataRef::LifetimeParamData(_))
-                | (GenericArg::Type(_), GenericParamDataRef::TypeParamData(_))
-                | (GenericArg::Const(_), GenericParamDataRef::ConstParamData(_)) => {
-                    substs.push(ctx.provided_kind(param_id, param, arg));
-                    args.next();
-                    params.next();
-                }
-                (
-                    GenericArg::Type(_) | GenericArg::Const(_),
-                    GenericParamDataRef::LifetimeParamData(_),
-                ) => {
-                    // We expected a lifetime argument, but got a type or const
-                    // argument. That means we're inferring the lifetime.
-                    substs.push(ctx.inferred_kind(def, param_id, param, infer_args, &substs));
-                    params.next();
-                    force_infer_lt = Some((arg_idx as u32, param_id));
-                }
-                (GenericArg::Type(type_ref), GenericParamDataRef::ConstParamData(_)) => {
-                    if let Some(konst) = type_looks_like_const(store, *type_ref) {
-                        let GenericParamId::ConstParamId(param_id) = param_id else {
-                            panic!("unmatching param kinds");
-                        };
-                        let const_ty = const_param_ty_query(db, param_id);
-                        substs.push(ctx.provided_type_like_const(const_ty, konst).into());
-                        args.next();
-                        params.next();
-                    } else {
-                        // See the `_ => { ... }` branch.
-                        if !had_count_error {
-                            ctx.report_arg_mismatch(param_id, arg_idx as u32, has_self_arg);
-                        }
-                        while args.next().is_some() {}
-                    }
-                }
-                _ => {
-                    // We expected one kind of parameter, but the user provided
-                    // another. This is an error. However, if we already know that
-                    // the arguments don't match up with the parameters, we won't issue
-                    // an additional error, as the user already knows what's wrong.
-                    if !had_count_error {
-                        ctx.report_arg_mismatch(param_id, arg_idx as u32, has_self_arg);
-                    }
-
-                    // We've reported the error, but we want to make sure that this
-                    // problem doesn't bubble down and create additional, irrelevant
-                    // errors. In this case, we're simply going to ignore the argument
-                    // and any following arguments. The rest of the parameters will be
-                    // inferred.
-                    while args.next().is_some() {}
-                }
-            },
-
-            (Some(&(_, arg)), None) => {
-                // We should never be able to reach this point with well-formed input.
-                // There are two situations in which we can encounter this issue.
-                //
-                //  1. The number of arguments is incorrect. In this case, an error
-                //     will already have been emitted, and we can ignore it.
-                //  2. We've inferred some lifetimes, which have been provided later (i.e.
-                //     after a type or const). We want to throw an error in this case.
-                if !had_count_error {
-                    assert!(
-                        matches!(arg, GenericArg::Lifetime(_)),
-                        "the only possible situation here is incorrect lifetime order"
-                    );
-                    let (provided_arg_idx, param_id) =
-                        force_infer_lt.expect("lifetimes ought to have been inferred");
-                    ctx.report_arg_mismatch(param_id, provided_arg_idx, has_self_arg);
-                }
-
-                break;
-            }
-
-            (None, Some(&(param_id, param))) => {
-                // If there are fewer arguments than parameters, it means we're inferring the remaining arguments.
-                let param = if let GenericParamId::LifetimeParamId(_) = param_id {
-                    match &lifetime_elision {
-                        LifetimeElisionKind::ElisionFailure
-                        | LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }
-                        | LifetimeElisionKind::AnonymousReportError => {
-                            assert!(had_count_error);
-                            ctx.inferred_kind(def, param_id, param, infer_args, &substs)
-                        }
-                        LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: _ } => {
-                            Region::new_static(interner).into()
-                        }
-                        LifetimeElisionKind::Elided(lifetime) => (*lifetime).into(),
-                        LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false }
-                        | LifetimeElisionKind::Infer => {
-                            // FIXME: With `AnonymousCreateParameter`, we need to create a new lifetime parameter here
-                            // (but this will probably be done in hir-def lowering instead).
-                            ctx.inferred_kind(def, param_id, param, infer_args, &substs)
-                        }
-                    }
-                } else {
-                    ctx.inferred_kind(def, param_id, param, infer_args, &substs)
-                };
-                substs.push(param);
-                params.next();
-            }
-
-            (None, None) => break,
-        }
-    }
-
-    crate::next_solver::GenericArgs::new_from_iter(interner, substs)
-}
-
-fn type_looks_like_const(
-    store: &ExpressionStore,
-    type_ref: TypeRefId,
-) -> Option<TypeLikeConst<'_>> {
-    // A path/`_` const will be parsed as a type, instead of a const, because when parsing/lowering
-    // in hir-def we don't yet know the expected argument kind. rustc does this a bit differently,
-    // when lowering to HIR it resolves the path, and if it doesn't resolve to the type namespace
-    // it is lowered as a const. Our behavior could deviate from rustc when the value is resolvable
-    // in both the type and value namespaces, but I believe we only allow more code.
-    let type_ref = &store[type_ref];
-    match type_ref {
-        TypeRef::Path(path) => Some(TypeLikeConst::Path(path)),
-        TypeRef::Placeholder => Some(TypeLikeConst::Infer),
-        _ => None,
-    }
-}
-
-fn unknown_subst<'db>(
-    interner: DbInterner<'db>,
-    def: impl Into<GenericDefId>,
-) -> crate::next_solver::GenericArgs<'db> {
-    let params = generics(interner.db(), def.into());
-    crate::next_solver::GenericArgs::new_from_iter(
-        interner,
-        params.iter_id().map(|id| match id {
-            GenericParamId::TypeParamId(_) => Ty::new_error(interner, ErrorGuaranteed).into(),
-            GenericParamId::ConstParamId(id) => {
-                unknown_const_as_generic(const_param_ty_query(interner.db(), id))
-            }
-            GenericParamId::LifetimeParamId(_) => {
-                crate::next_solver::Region::error(interner).into()
-            }
-        }),
-    )
-}
diff --git a/crates/hir-ty/src/mapping.rs b/crates/hir-ty/src/mapping.rs
deleted file mode 100644
index 5125a38..0000000
--- a/crates/hir-ty/src/mapping.rs
+++ /dev/null
@@ -1,169 +0,0 @@
-//! This module contains the implementations of the `ToChalk` trait, which
-//! handles conversion between our data types and their corresponding types in
-//! Chalk (in both directions); plus some helper functions for more specialized
-//! conversions.
-
-use hir_def::{LifetimeParamId, TraitId, TypeAliasId, TypeOrConstParamId};
-use salsa::{
-    Id,
-    plumbing::{AsId, FromId},
-};
-
-use crate::{
-    AssocTypeId, CallableDefId, ChalkTraitId, FnDefId, ForeignDefId, Interner, OpaqueTyId,
-    PlaceholderIndex, chalk_db,
-    db::{HirDatabase, InternedLifetimeParamId, InternedTypeOrConstParamId},
-};
-
-pub trait ToChalk {
-    type Chalk;
-    fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk;
-    fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self;
-}
-
-pub(crate) fn from_chalk<T, ChalkT>(db: &dyn HirDatabase, chalk: ChalkT) -> T
-where
-    T: ToChalk<Chalk = ChalkT>,
-{
-    T::from_chalk(db, chalk)
-}
-
-impl ToChalk for hir_def::ImplId {
-    type Chalk = chalk_db::ImplId;
-
-    fn to_chalk(self, _db: &dyn HirDatabase) -> chalk_db::ImplId {
-        chalk_ir::ImplId(self.as_id())
-    }
-
-    fn from_chalk(_db: &dyn HirDatabase, impl_id: chalk_db::ImplId) -> hir_def::ImplId {
-        FromId::from_id(impl_id.0.as_id())
-    }
-}
-
-impl ToChalk for CallableDefId {
-    type Chalk = FnDefId;
-
-    fn to_chalk(self, _db: &dyn HirDatabase) -> FnDefId {
-        chalk_ir::FnDefId(salsa::plumbing::AsId::as_id(&self))
-    }
-
-    fn from_chalk(db: &dyn HirDatabase, fn_def_id: FnDefId) -> CallableDefId {
-        salsa::plumbing::FromIdWithDb::from_id(fn_def_id.0, db.zalsa())
-    }
-}
-
-impl From<OpaqueTyId> for crate::db::InternedOpaqueTyId {
-    fn from(id: OpaqueTyId) -> Self {
-        FromId::from_id(id.0)
-    }
-}
-
-impl From<crate::db::InternedOpaqueTyId> for OpaqueTyId {
-    fn from(id: crate::db::InternedOpaqueTyId) -> Self {
-        chalk_ir::OpaqueTyId(id.as_id())
-    }
-}
-
-impl From<chalk_ir::ClosureId<Interner>> for crate::db::InternedClosureId {
-    fn from(id: chalk_ir::ClosureId<Interner>) -> Self {
-        FromId::from_id(id.0)
-    }
-}
-
-impl From<crate::db::InternedClosureId> for chalk_ir::ClosureId<Interner> {
-    fn from(id: crate::db::InternedClosureId) -> Self {
-        chalk_ir::ClosureId(id.as_id())
-    }
-}
-
-impl From<chalk_ir::CoroutineId<Interner>> for crate::db::InternedCoroutineId {
-    fn from(id: chalk_ir::CoroutineId<Interner>) -> Self {
-        Self::from_id(id.0)
-    }
-}
-
-impl From<crate::db::InternedCoroutineId> for chalk_ir::CoroutineId<Interner> {
-    fn from(id: crate::db::InternedCoroutineId) -> Self {
-        chalk_ir::CoroutineId(id.as_id())
-    }
-}
-
-pub fn to_foreign_def_id(id: TypeAliasId) -> ForeignDefId {
-    chalk_ir::ForeignDefId(id.as_id())
-}
-
-pub fn from_foreign_def_id(id: ForeignDefId) -> TypeAliasId {
-    FromId::from_id(id.0)
-}
-
-pub fn to_assoc_type_id(id: TypeAliasId) -> AssocTypeId {
-    chalk_ir::AssocTypeId(id.as_id())
-}
-
-pub fn from_assoc_type_id(id: AssocTypeId) -> TypeAliasId {
-    FromId::from_id(id.0)
-}
-
-pub fn from_placeholder_idx(
-    db: &dyn HirDatabase,
-    idx: PlaceholderIndex,
-) -> (TypeOrConstParamId, u32) {
-    assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT);
-    // SAFETY: We cannot really encapsulate this unfortunately, so just hope this is sound.
-    let interned_id =
-        InternedTypeOrConstParamId::from_id(unsafe { Id::from_index(idx.idx.try_into().unwrap()) });
-    interned_id.loc(db)
-}
-
-pub fn to_placeholder_idx(
-    db: &dyn HirDatabase,
-    id: TypeOrConstParamId,
-    idx: u32,
-) -> PlaceholderIndex {
-    let interned_id = InternedTypeOrConstParamId::new(db, (id, idx));
-    PlaceholderIndex {
-        ui: chalk_ir::UniverseIndex::ROOT,
-        idx: interned_id.as_id().index() as usize,
-    }
-}
-
-pub fn to_placeholder_idx_no_index(
-    db: &dyn HirDatabase,
-    id: TypeOrConstParamId,
-) -> PlaceholderIndex {
-    let index = crate::generics::generics(db, id.parent)
-        .type_or_const_param_idx(id)
-        .expect("param not found");
-    to_placeholder_idx(db, id, index as u32)
-}
-
-pub fn lt_from_placeholder_idx(
-    db: &dyn HirDatabase,
-    idx: PlaceholderIndex,
-) -> (LifetimeParamId, u32) {
-    assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT);
-    // SAFETY: We cannot really encapsulate this unfortunately, so just hope this is sound.
-    let interned_id =
-        InternedLifetimeParamId::from_id(unsafe { Id::from_index(idx.idx.try_into().unwrap()) });
-    interned_id.loc(db)
-}
-
-pub fn lt_to_placeholder_idx(
-    db: &dyn HirDatabase,
-    id: LifetimeParamId,
-    idx: u32,
-) -> PlaceholderIndex {
-    let interned_id = InternedLifetimeParamId::new(db, (id, idx));
-    PlaceholderIndex {
-        ui: chalk_ir::UniverseIndex::ROOT,
-        idx: interned_id.as_id().index() as usize,
-    }
-}
-
-pub fn to_chalk_trait_id(id: TraitId) -> ChalkTraitId {
-    chalk_ir::TraitId(id.as_id())
-}
-
-pub fn from_chalk_trait_id(id: ChalkTraitId) -> TraitId {
-    FromId::from_id(id.0)
-}
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index 06c7cdd..cec6356 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -25,10 +25,8 @@
 use stdx::never;
 use triomphe::Arc;
 
-use crate::next_solver::infer::InferCtxt;
-use crate::next_solver::infer::select::ImplSource;
 use crate::{
-    TraitEnvironment, TyBuilder,
+    TraitEnvironment,
     autoderef::{self, AutoderefKind},
     db::HirDatabase,
     infer::{Adjust, Adjustment, OverloadedDeref, PointerCast, unify::InferenceTable},
@@ -37,7 +35,8 @@
         Canonical, DbInterner, ErrorGuaranteed, GenericArgs, Goal, Predicate, Region, SolverDefId,
         TraitRef, Ty, TyKind, TypingMode,
         infer::{
-            DbInternerInferExt, DefineOpaqueTypes,
+            DbInternerInferExt, InferCtxt,
+            select::ImplSource,
             traits::{Obligation, ObligationCause, PredicateObligation},
         },
         obligation_ctxt::ObligationCtxt,
@@ -1597,9 +1596,9 @@
                 return IsValidCandidate::NotVisible;
             }
             let self_ty_matches = table.run_in_snapshot(|table| {
-                let expected_self_ty = TyBuilder::impl_self_ty(db, impl_id)
-                    .fill_with_inference_vars(table)
-                    .build(table.interner());
+                let impl_args = table.fresh_args_for_item(impl_id.into());
+                let expected_self_ty =
+                    db.impl_self_ty(impl_id).instantiate(table.interner(), impl_args);
                 table.unify(expected_self_ty, self_ty)
             });
             if !self_ty_matches {
@@ -1654,7 +1653,7 @@
                     let res = table
                         .infer_ctxt
                         .at(&ObligationCause::dummy(), table.trait_env.env)
-                        .relate(DefineOpaqueTypes::No, expected_receiver, variance, receiver_ty);
+                        .relate(expected_receiver, variance, receiver_ty);
                     let Ok(infer_ok) = res else {
                         return IsValidCandidate::No;
                     };
@@ -1727,7 +1726,7 @@
 
         // We need to consider the bounds on the impl to distinguish functions of the same name
         // for a type.
-        let predicates = db.generic_predicates_ns(impl_id.into());
+        let predicates = db.generic_predicates(impl_id.into());
         let Some(predicates) = predicates.instantiate(table.interner(), impl_subst) else {
             return IsValidCandidate::Yes;
         };
diff --git a/crates/hir-ty/src/mir.rs b/crates/hir-ty/src/mir.rs
index 936895f..7aebe17 100644
--- a/crates/hir-ty/src/mir.rs
+++ b/crates/hir-ty/src/mir.rs
@@ -196,7 +196,7 @@
             },
             ProjectionElem::Field(Either::Left(f)) => match base.kind() {
                 TyKind::Adt(_, subst) => {
-                    db.field_types_ns(f.parent)[f.local_id].instantiate(interner, subst)
+                    db.field_types(f.parent)[f.local_id].instantiate(interner, subst)
                 }
                 ty => {
                     never!("Only adt has field, found {:?}", ty);
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index 444336c..6e62bcb 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -1696,7 +1696,7 @@
         if let TyKind::Adt(adt_ef, subst) = kind
             && let AdtId::StructId(struct_id) = adt_ef.def_id().0
         {
-            let field_types = self.db.field_types_ns(struct_id.into());
+            let field_types = self.db.field_types(struct_id.into());
             if let Some(ty) =
                 field_types.iter().last().map(|it| it.1.instantiate(self.interner(), subst))
             {
@@ -1775,9 +1775,9 @@
                     else {
                         not_supported!("unsizing struct without field");
                     };
-                    let target_last_field = self.db.field_types_ns(id.into())[last_field]
+                    let target_last_field = self.db.field_types(id.into())[last_field]
                         .instantiate(self.interner(), target_subst);
-                    let current_last_field = self.db.field_types_ns(id.into())[last_field]
+                    let current_last_field = self.db.field_types(id.into())[last_field]
                         .instantiate(self.interner(), current_subst);
                     return self.unsizing_ptr_from_addr(
                         target_last_field,
@@ -2268,7 +2268,7 @@
                     AdtId::StructId(s) => {
                         let data = s.fields(this.db);
                         let layout = this.layout(ty)?;
-                        let field_types = this.db.field_types_ns(s.into());
+                        let field_types = this.db.field_types(s.into());
                         for (f, _) in data.fields().iter() {
                             let offset = layout
                                 .fields
@@ -2296,7 +2296,7 @@
                             e,
                         ) {
                             let data = v.fields(this.db);
-                            let field_types = this.db.field_types_ns(v.into());
+                            let field_types = this.db.field_types(v.into());
                             for (f, _) in data.fields().iter() {
                                 let offset =
                                     l.fields.offset(u32::from(f.into_raw()) as usize).bytes_usize();
@@ -2373,7 +2373,7 @@
             }
             TyKind::Adt(id, args) => match id.def_id().0 {
                 AdtId::StructId(s) => {
-                    for (i, (_, ty)) in self.db.field_types_ns(s.into()).iter().enumerate() {
+                    for (i, (_, ty)) in self.db.field_types(s.into()).iter().enumerate() {
                         let offset = layout.fields.offset(i).bytes_usize();
                         let ty = ty.instantiate(self.interner(), args);
                         self.patch_addresses(
@@ -2394,7 +2394,7 @@
                         self.read_memory(addr, layout.size.bytes_usize())?,
                         e,
                     ) {
-                        for (i, (_, ty)) in self.db.field_types_ns(ev.into()).iter().enumerate() {
+                        for (i, (_, ty)) in self.db.field_types(ev.into()).iter().enumerate() {
                             let offset = layout.fields.offset(i).bytes_usize();
                             let ty = ty.instantiate(self.interner(), args);
                             self.patch_addresses(
@@ -2895,7 +2895,7 @@
                         let variant_fields = s.fields(self.db);
                         match variant_fields.shape {
                             FieldsShape::Record | FieldsShape::Tuple => {
-                                let field_types = self.db.field_types_ns(s.into());
+                                let field_types = self.db.field_types(s.into());
                                 for (field, _) in variant_fields.fields().iter() {
                                     let offset = layout
                                         .fields
diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs
index c45ae9d..4b1adec 100644
--- a/crates/hir-ty/src/mir/eval/shim.rs
+++ b/crates/hir-ty/src/mir/eval/shim.rs
@@ -1383,7 +1383,7 @@
                     AdtId::StructId(s) => s,
                     _ => not_supported!("unsized enum or union"),
                 };
-                let field_types = self.db.field_types_ns(id.into());
+                let field_types = self.db.field_types(id.into());
                 let last_field_ty =
                     field_types.iter().next_back().unwrap().1.instantiate(self.interner(), subst);
                 let sized_part_size =
diff --git a/crates/hir-ty/src/mir/eval/shim/simd.rs b/crates/hir-ty/src/mir/eval/shim/simd.rs
index ade94b9..4c64a70 100644
--- a/crates/hir-ty/src/mir/eval/shim/simd.rs
+++ b/crates/hir-ty/src/mir/eval/shim/simd.rs
@@ -34,7 +34,7 @@
                             let Some((first_field, _)) = fields.iter().next() else {
                                 not_supported!("simd type with no field");
                             };
-                            let field_ty = self.db.field_types_ns(id.into())[first_field]
+                            let field_ty = self.db.field_types(id.into())[first_field]
                                 .instantiate(self.interner(), subst);
                             return Ok((fields.len(), field_ty));
                         }
diff --git a/crates/hir-ty/src/mir/eval/tests.rs b/crates/hir-ty/src/mir/eval/tests.rs
index 4eb4aa9..f242115 100644
--- a/crates/hir-ty/src/mir/eval/tests.rs
+++ b/crates/hir-ty/src/mir/eval/tests.rs
@@ -636,16 +636,13 @@
     );
 }
 
-#[ignore = "
-FIXME(next-solver):
-This does not work currently because I replaced homemade selection with selection by the trait solver;
-This will work once we implement `Interner::impl_specializes()` properly.
-"]
 #[test]
 fn specialization_array_clone() {
     check_pass(
         r#"
 //- minicore: copy, derive, slice, index, coerce_unsized, panic
+#![feature(min_specialization)]
+
 impl<T: Clone, const N: usize> Clone for [T; N] {
     #[inline]
     fn clone(&self) -> Self {
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index 92f9cd4..1439c43 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -43,7 +43,6 @@
     next_solver::{
         Const, DbInterner, ParamConst, Region, TyKind, TypingMode, UnevaluatedConst,
         infer::{DbInternerInferExt, InferCtxt},
-        mapping::NextSolverToChalk,
     },
     traits::FnTrait,
 };
@@ -303,6 +302,7 @@
         let resolver = owner.resolver(db);
         let env = db.trait_environment_for_body(owner);
         let interner = DbInterner::new_with(db, Some(env.krate), env.block);
+        // FIXME(next-solver): Is `non_body_analysis()` correct here? Don't we want to reveal opaque types defined by this body?
         let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis());
 
         MirLowerCtx {
@@ -1766,8 +1766,8 @@
 
     fn is_uninhabited(&self, expr_id: ExprId) -> bool {
         is_ty_uninhabited_from(
-            self.db,
-            &self.infer[expr_id].to_chalk(self.interner()),
+            &self.infcx,
+            self.infer[expr_id],
             self.owner.module(self.db),
             self.env.clone(),
         )
diff --git a/crates/hir-ty/src/mir/pretty.rs b/crates/hir-ty/src/mir/pretty.rs
index e46edb8..0c5a649 100644
--- a/crates/hir-ty/src/mir/pretty.rs
+++ b/crates/hir-ty/src/mir/pretty.rs
@@ -118,10 +118,10 @@
     Binding(Name, LocalId<'db>),
 }
 
-impl<'db> HirDisplay for LocalName<'db> {
+impl<'db> HirDisplay<'db> for LocalName<'db> {
     fn hir_fmt(
         &self,
-        f: &mut crate::display::HirFormatter<'_>,
+        f: &mut crate::display::HirFormatter<'_, 'db>,
     ) -> Result<(), crate::display::HirDisplayError> {
         match self {
             LocalName::Unknown(l) => write!(f, "_{}", u32::from(l.into_raw())),
@@ -489,7 +489,7 @@
         }
     }
 
-    fn hir_display<'b, T: HirDisplay>(&self, ty: &'b T) -> impl Display + use<'a, 'b, 'db, T>
+    fn hir_display<'b, T: HirDisplay<'db>>(&self, ty: &'b T) -> impl Display + use<'a, 'b, 'db, T>
     where
         'db: 'b,
     {
diff --git a/crates/hir-ty/src/next_solver.rs b/crates/hir-ty/src/next_solver.rs
index 776e0d9..8c52a84 100644
--- a/crates/hir-ty/src/next_solver.rs
+++ b/crates/hir-ty/src/next_solver.rs
@@ -1,5 +1,4 @@
 //! Things relevant to the next trait solver.
-#![allow(unused, unreachable_pub)]
 
 pub mod abi;
 mod consts;
@@ -12,7 +11,6 @@
 pub(crate) mod inspect;
 pub mod interner;
 mod ir_print;
-pub mod mapping;
 pub mod normalize;
 pub mod obligation_ctxt;
 mod opaques;
@@ -33,7 +31,7 @@
 pub use solver::*;
 pub use ty::*;
 
-pub use crate::lower_nextsolver::ImplTraitIdx;
+pub use crate::lower::ImplTraitIdx;
 pub use rustc_ast_ir::Mutability;
 
 pub type Binder<'db, T> = rustc_type_ir::Binder<DbInterner<'db>, T>;
diff --git a/crates/hir-ty/src/next_solver/consts.rs b/crates/hir-ty/src/next_solver/consts.rs
index 2fc1fc4..926dbdc 100644
--- a/crates/hir-ty/src/next_solver/consts.rs
+++ b/crates/hir-ty/src/next_solver/consts.rs
@@ -2,21 +2,20 @@
 
 use std::hash::Hash;
 
-use hir_def::{ConstParamId, TypeOrConstParamId};
-use intern::{Interned, Symbol};
+use hir_def::ConstParamId;
 use macros::{TypeFoldable, TypeVisitable};
-use rustc_ast_ir::{try_visit, visit::VisitorResult};
+use rustc_ast_ir::visit::VisitorResult;
 use rustc_type_ir::{
-    BoundVar, DebruijnIndex, FlagComputation, Flags, TypeFoldable, TypeSuperFoldable,
-    TypeSuperVisitable, TypeVisitable, TypeVisitableExt, WithCachedTypeInfo,
+    BoundVar, BoundVarIndexKind, ConstVid, DebruijnIndex, FlagComputation, Flags, InferConst,
+    TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
+    WithCachedTypeInfo,
     inherent::{IntoKind, ParamEnv as _, PlaceholderLike, SliceLike},
     relate::Relate,
 };
 
 use crate::{
-    ConstScalar, MemoryMap,
-    interner::InternedWrapperNoDebug,
-    next_solver::{ClauseKind, ParamEnv},
+    MemoryMap,
+    next_solver::{ClauseKind, ParamEnv, interner::InternedWrapperNoDebug},
 };
 
 use super::{BoundVarKind, DbInterner, ErrorGuaranteed, GenericArgs, Placeholder, Ty};
@@ -51,11 +50,11 @@
     }
 
     pub fn error(interner: DbInterner<'db>) -> Self {
-        Const::new(interner, rustc_type_ir::ConstKind::Error(ErrorGuaranteed))
+        Const::new(interner, ConstKind::Error(ErrorGuaranteed))
     }
 
     pub fn new_param(interner: DbInterner<'db>, param: ParamConst) -> Self {
-        Const::new(interner, rustc_type_ir::ConstKind::Param(param))
+        Const::new(interner, ConstKind::Param(param))
     }
 
     pub fn new_placeholder(interner: DbInterner<'db>, placeholder: PlaceholderConst) -> Self {
@@ -63,7 +62,7 @@
     }
 
     pub fn new_bound(interner: DbInterner<'db>, index: DebruijnIndex, bound: BoundConst) -> Self {
-        Const::new(interner, ConstKind::Bound(index, bound))
+        Const::new(interner, ConstKind::Bound(BoundVarIndexKind::Bound(index), bound))
     }
 
     pub fn new_valtree(
@@ -82,7 +81,11 @@
     }
 
     pub fn is_ct_infer(&self) -> bool {
-        matches!(&self.inner().internee, ConstKind::Infer(_))
+        matches!(self.kind(), ConstKind::Infer(_))
+    }
+
+    pub fn is_error(&self) -> bool {
+        matches!(self.kind(), ConstKind::Error(_))
     }
 
     pub fn is_trivially_wf(self) -> bool {
@@ -338,28 +341,34 @@
 }
 
 impl<'db> rustc_type_ir::inherent::Const<DbInterner<'db>> for Const<'db> {
-    fn new_infer(interner: DbInterner<'db>, var: rustc_type_ir::InferConst) -> Self {
+    fn new_infer(interner: DbInterner<'db>, var: InferConst) -> Self {
         Const::new(interner, ConstKind::Infer(var))
     }
 
-    fn new_var(interner: DbInterner<'db>, var: rustc_type_ir::ConstVid) -> Self {
-        Const::new(interner, ConstKind::Infer(rustc_type_ir::InferConst::Var(var)))
+    fn new_var(interner: DbInterner<'db>, var: ConstVid) -> Self {
+        Const::new(interner, ConstKind::Infer(InferConst::Var(var)))
     }
 
-    fn new_bound(
-        interner: DbInterner<'db>,
-        debruijn: rustc_type_ir::DebruijnIndex,
-        var: BoundConst,
-    ) -> Self {
-        Const::new(interner, ConstKind::Bound(debruijn, var))
+    fn new_bound(interner: DbInterner<'db>, debruijn: DebruijnIndex, var: BoundConst) -> Self {
+        Const::new(interner, ConstKind::Bound(BoundVarIndexKind::Bound(debruijn), var))
     }
 
-    fn new_anon_bound(
+    fn new_anon_bound(interner: DbInterner<'db>, debruijn: DebruijnIndex, var: BoundVar) -> Self {
+        Const::new(
+            interner,
+            ConstKind::Bound(BoundVarIndexKind::Bound(debruijn), BoundConst { var }),
+        )
+    }
+
+    fn new_canonical_bound(interner: DbInterner<'db>, var: BoundVar) -> Self {
+        Const::new(interner, ConstKind::Bound(BoundVarIndexKind::Canonical, BoundConst { var }))
+    }
+
+    fn new_placeholder(
         interner: DbInterner<'db>,
-        debruijn: rustc_type_ir::DebruijnIndex,
-        var: rustc_type_ir::BoundVar,
+        param: <DbInterner<'db> as rustc_type_ir::Interner>::PlaceholderConst,
     ) -> Self {
-        Const::new(interner, ConstKind::Bound(debruijn, BoundConst { var }))
+        Const::new(interner, ConstKind::Placeholder(param))
     }
 
     fn new_unevaluated(
@@ -376,13 +385,6 @@
     fn new_error(interner: DbInterner<'db>, guar: ErrorGuaranteed) -> Self {
         Const::new(interner, ConstKind::Error(guar))
     }
-
-    fn new_placeholder(
-        interner: DbInterner<'db>,
-        param: <DbInterner<'db> as rustc_type_ir::Interner>::PlaceholderConst,
-    ) -> Self {
-        Const::new(interner, ConstKind::Placeholder(param))
-    }
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
@@ -425,7 +427,7 @@
 
 impl<'db> Relate<DbInterner<'db>> for ExprConst {
     fn relate<R: rustc_type_ir::relate::TypeRelation<DbInterner<'db>>>(
-        relation: &mut R,
+        _relation: &mut R,
         a: Self,
         b: Self,
     ) -> rustc_type_ir::relate::RelateResult<DbInterner<'db>, Self> {
diff --git a/crates/hir-ty/src/next_solver/def_id.rs b/crates/hir-ty/src/next_solver/def_id.rs
index 789be3b..0ff0b08 100644
--- a/crates/hir-ty/src/next_solver/def_id.rs
+++ b/crates/hir-ty/src/next_solver/def_id.rs
@@ -1,8 +1,8 @@
 //! Definition of `SolverDefId`
 
 use hir_def::{
-    AdtId, CallableDefId, ConstId, EnumId, EnumVariantId, FunctionId, GeneralConstId, GenericDefId,
-    ImplId, StaticId, StructId, TraitId, TypeAliasId, UnionId,
+    AdtId, CallableDefId, ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId,
+    GeneralConstId, GenericDefId, ImplId, StaticId, StructId, TraitId, TypeAliasId, UnionId,
 };
 use rustc_type_ir::inherent;
 use stdx::impl_from;
@@ -29,6 +29,8 @@
     InternedClosureId(InternedClosureId),
     InternedCoroutineId(InternedCoroutineId),
     InternedOpaqueTyId(InternedOpaqueTyId),
+    EnumVariantId(EnumVariantId),
+    // FIXME(next-solver): Do we need the separation of `Ctor`? It duplicates some variants.
     Ctor(Ctor),
 }
 
@@ -73,6 +75,16 @@
             SolverDefId::InternedOpaqueTyId(id) => {
                 f.debug_tuple("InternedOpaqueTyId").field(&id).finish()
             }
+            SolverDefId::EnumVariantId(id) => {
+                let parent_enum = id.loc(db).parent;
+                f.debug_tuple("EnumVariantId")
+                    .field(&format_args!(
+                        "\"{}::{}\"",
+                        db.enum_signature(parent_enum).name.as_str(),
+                        parent_enum.enum_variants(db).variant_name_by_id(id).unwrap().as_str()
+                    ))
+                    .finish()
+            }
             SolverDefId::Ctor(Ctor::Struct(id)) => {
                 f.debug_tuple("Ctor").field(&db.struct_signature(id).name.as_str()).finish()
             }
@@ -101,6 +113,7 @@
     InternedClosureId,
     InternedCoroutineId,
     InternedOpaqueTyId,
+    EnumVariantId,
     Ctor
     for SolverDefId
 );
@@ -129,8 +142,20 @@
     }
 }
 
+impl From<DefWithBodyId> for SolverDefId {
+    #[inline]
+    fn from(value: DefWithBodyId) -> Self {
+        match value {
+            DefWithBodyId::FunctionId(id) => id.into(),
+            DefWithBodyId::StaticId(id) => id.into(),
+            DefWithBodyId::ConstId(id) => id.into(),
+            DefWithBodyId::VariantId(id) => id.into(),
+        }
+    }
+}
+
 impl TryFrom<SolverDefId> for GenericDefId {
-    type Error = SolverDefId;
+    type Error = ();
 
     fn try_from(value: SolverDefId) -> Result<Self, Self::Error> {
         Ok(match value {
@@ -141,10 +166,11 @@
             SolverDefId::StaticId(static_id) => GenericDefId::StaticId(static_id),
             SolverDefId::TraitId(trait_id) => GenericDefId::TraitId(trait_id),
             SolverDefId::TypeAliasId(type_alias_id) => GenericDefId::TypeAliasId(type_alias_id),
-            SolverDefId::InternedClosureId(_) => return Err(value),
-            SolverDefId::InternedCoroutineId(_) => return Err(value),
-            SolverDefId::InternedOpaqueTyId(_) => return Err(value),
-            SolverDefId::Ctor(_) => return Err(value),
+            SolverDefId::InternedClosureId(_)
+            | SolverDefId::InternedCoroutineId(_)
+            | SolverDefId::InternedOpaqueTyId(_)
+            | SolverDefId::EnumVariantId(_)
+            | SolverDefId::Ctor(_) => return Err(()),
         })
     }
 }
@@ -185,7 +211,7 @@
 
         impl std::fmt::Debug for $name {
             fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-                std::fmt::Debug::fmt(&self.0, f)
+                std::fmt::Debug::fmt(&SolverDefId::from(self.0), f)
             }
         }
 
diff --git a/crates/hir-ty/src/next_solver/fold.rs b/crates/hir-ty/src/next_solver/fold.rs
index a42fdb0..f776b6e 100644
--- a/crates/hir-ty/src/next_solver/fold.rs
+++ b/crates/hir-ty/src/next_solver/fold.rs
@@ -1,9 +1,8 @@
 //! Fold impls for the next-trait-solver.
 
 use rustc_type_ir::{
-    BoundVar, DebruijnIndex, RegionKind, TypeFoldable, TypeFolder, TypeSuperFoldable,
-    TypeVisitableExt,
-    inherent::{IntoKind, Region as _},
+    BoundVarIndexKind, DebruijnIndex, RegionKind, TypeFoldable, TypeFolder, TypeSuperFoldable,
+    TypeVisitableExt, inherent::IntoKind,
 };
 
 use crate::next_solver::BoundConst;
@@ -55,7 +54,7 @@
 }
 
 impl<'db, D: BoundVarReplacerDelegate<'db>> BoundVarReplacer<'db, D> {
-    pub fn new(tcx: DbInterner<'db>, delegate: D) -> Self {
+    pub(crate) fn new(tcx: DbInterner<'db>, delegate: D) -> Self {
         BoundVarReplacer { interner: tcx, current_index: DebruijnIndex::ZERO, delegate }
     }
 }
@@ -80,7 +79,9 @@
 
     fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> {
         match t.kind() {
-            TyKind::Bound(debruijn, bound_ty) if debruijn == self.current_index => {
+            TyKind::Bound(BoundVarIndexKind::Bound(debruijn), bound_ty)
+                if debruijn == self.current_index =>
+            {
                 let ty = self.delegate.replace_ty(bound_ty);
                 debug_assert!(!ty.has_vars_bound_above(DebruijnIndex::ZERO));
                 rustc_type_ir::shift_vars(self.interner, ty, self.current_index.as_u32())
@@ -97,9 +98,12 @@
 
     fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
         match r.kind() {
-            RegionKind::ReBound(debruijn, br) if debruijn == self.current_index => {
+            RegionKind::ReBound(BoundVarIndexKind::Bound(debruijn), br)
+                if debruijn == self.current_index =>
+            {
                 let region = self.delegate.replace_region(br);
-                if let RegionKind::ReBound(debruijn1, br) = region.kind() {
+                if let RegionKind::ReBound(BoundVarIndexKind::Bound(debruijn1), br) = region.kind()
+                {
                     // If the callback returns a bound region,
                     // that region should always use the INNERMOST
                     // debruijn index. Then we adjust it to the
@@ -116,7 +120,9 @@
 
     fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> {
         match ct.kind() {
-            ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => {
+            ConstKind::Bound(BoundVarIndexKind::Bound(debruijn), bound_const)
+                if debruijn == self.current_index =>
+            {
                 let ct = self.delegate.replace_const(bound_const);
                 debug_assert!(!ct.has_vars_bound_above(DebruijnIndex::ZERO));
                 rustc_type_ir::shift_vars(self.interner, ct, self.current_index.as_u32())
diff --git a/crates/hir-ty/src/next_solver/fulfill.rs b/crates/hir-ty/src/next_solver/fulfill.rs
index 262da85..7783075 100644
--- a/crates/hir-ty/src/next_solver/fulfill.rs
+++ b/crates/hir-ty/src/next_solver/fulfill.rs
@@ -2,7 +2,7 @@
 
 mod errors;
 
-use std::{marker::PhantomData, mem, ops::ControlFlow, vec::ExtractIf};
+use std::{mem, ops::ControlFlow};
 
 use rustc_hash::FxHashSet;
 use rustc_next_trait_solver::{
@@ -46,6 +46,7 @@
     /// outside of this snapshot leads to subtle bugs if the snapshot
     /// gets rolled back. Because of this we explicitly check that we only
     /// use the context in exactly this snapshot.
+    #[expect(unused)]
     usable_in_snapshot: usize,
 }
 
@@ -69,10 +70,6 @@
         self.pending.push((obligation, stalled_on));
     }
 
-    fn has_pending_obligations(&self) -> bool {
-        !self.pending.is_empty() || !self.overflowed.is_empty()
-    }
-
     fn clone_pending(&self) -> PredicateObligations<'db> {
         let mut obligations: PredicateObligations<'db> =
             self.pending.iter().map(|(o, _)| o.clone()).collect();
@@ -125,10 +122,10 @@
 }
 
 impl<'db> FulfillmentCtxt<'db> {
-    #[tracing::instrument(level = "trace", skip(self, infcx))]
+    #[tracing::instrument(level = "trace", skip(self, _infcx))]
     pub(crate) fn register_predicate_obligation(
         &mut self,
-        infcx: &InferCtxt<'db>,
+        _infcx: &InferCtxt<'db>,
         obligation: PredicateObligation<'db>,
     ) {
         // FIXME: See the comment in `try_evaluate_obligations()`.
@@ -138,7 +135,7 @@
 
     pub(crate) fn register_predicate_obligations(
         &mut self,
-        infcx: &InferCtxt<'db>,
+        _infcx: &InferCtxt<'db>,
         obligations: impl IntoIterator<Item = PredicateObligation<'db>>,
     ) {
         // FIXME: See the comment in `try_evaluate_obligations()`.
@@ -148,7 +145,7 @@
 
     pub(crate) fn collect_remaining_errors(
         &mut self,
-        infcx: &InferCtxt<'db>,
+        _infcx: &InferCtxt<'db>,
     ) -> Vec<NextSolverError<'db>> {
         self.obligations
             .pending
@@ -235,10 +232,6 @@
         self.collect_remaining_errors(infcx)
     }
 
-    fn has_pending_obligations(&self) -> bool {
-        self.obligations.has_pending_obligations()
-    }
-
     pub(crate) fn pending_obligations(&self) -> PredicateObligations<'db> {
         self.obligations.clone_pending()
     }
diff --git a/crates/hir-ty/src/next_solver/fulfill/errors.rs b/crates/hir-ty/src/next_solver/fulfill/errors.rs
index ab4a229..82dbf94 100644
--- a/crates/hir-ty/src/next_solver/fulfill/errors.rs
+++ b/crates/hir-ty/src/next_solver/fulfill/errors.rs
@@ -9,15 +9,15 @@
 use rustc_type_ir::{
     AliasRelationDirection, AliasTermKind, HostEffectPredicate, Interner, PredicatePolarity,
     error::ExpectedFound,
-    inherent::{IntoKind, PlaceholderConst, SliceLike, Span as _},
+    inherent::{IntoKind, SliceLike, Span as _},
     lang_items::SolverTraitLangItem,
-    solve::{CandidateSource, Certainty, GoalSource, MaybeCause, NoSolution},
+    solve::{Certainty, GoalSource, MaybeCause, NoSolution},
 };
 use tracing::{instrument, trace};
 
 use crate::next_solver::{
     AliasTerm, Binder, ClauseKind, Const, ConstKind, DbInterner, PolyTraitPredicate, PredicateKind,
-    SolverContext, SolverDefId, Span, Term, TraitPredicate, Ty, TyKind, TypeError,
+    SolverContext, Span, Term, TraitPredicate, Ty, TyKind, TypeError,
     fulfill::NextSolverError,
     infer::{
         InferCtxt,
@@ -529,7 +529,6 @@
             }
         }
 
-        let mut impl_where_bound_count = 0;
         for nested_goal in nested_goals {
             trace!(nested_goal = ?(nested_goal.goal(), nested_goal.source(), nested_goal.result()));
 
@@ -542,34 +541,27 @@
                 recursion_depth: self.obligation.recursion_depth + 1,
             };
 
-            let obligation;
-            match (child_mode, nested_goal.source()) {
+            let obligation = match (child_mode, nested_goal.source()) {
                 (
                     ChildMode::Trait(_) | ChildMode::Host(_),
                     GoalSource::Misc | GoalSource::TypeRelating | GoalSource::NormalizeGoal(_),
                 ) => {
                     continue;
                 }
-                (ChildMode::Trait(parent_trait_pred), GoalSource::ImplWhereBound) => {
-                    obligation = make_obligation();
-                    impl_where_bound_count += 1;
+                (ChildMode::Trait(_parent_trait_pred), GoalSource::ImplWhereBound) => {
+                    make_obligation()
                 }
                 (
-                    ChildMode::Host(parent_host_pred),
+                    ChildMode::Host(_parent_host_pred),
                     GoalSource::ImplWhereBound | GoalSource::AliasBoundConstCondition,
-                ) => {
-                    obligation = make_obligation();
-                    impl_where_bound_count += 1;
-                }
+                ) => make_obligation(),
                 // Skip over a higher-ranked predicate.
-                (_, GoalSource::InstantiateHigherRanked) => {
-                    obligation = self.obligation.clone();
-                }
+                (_, GoalSource::InstantiateHigherRanked) => self.obligation.clone(),
                 (ChildMode::PassThrough, _)
                 | (_, GoalSource::AliasWellFormed | GoalSource::AliasBoundConstCondition) => {
-                    obligation = make_obligation();
+                    make_obligation()
                 }
-            }
+            };
 
             self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?;
         }
@@ -628,35 +620,29 @@
 }
 
 mod wf {
-    use std::iter;
-
     use hir_def::ItemContainerId;
     use rustc_type_ir::inherent::{
-        AdtDef, BoundExistentialPredicates, GenericArg, GenericArgs as _, IntoKind, SliceLike,
-        Term as _, Ty as _,
+        AdtDef, BoundExistentialPredicates, GenericArgs as _, IntoKind, SliceLike, Term as _,
+        Ty as _,
     };
     use rustc_type_ir::lang_items::SolverTraitLangItem;
     use rustc_type_ir::{
-        Interner, PredicatePolarity, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
-        TypeVisitor,
+        Interner, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
     };
-    use tracing::{debug, instrument, trace};
+    use tracing::{debug, instrument};
 
     use crate::next_solver::infer::InferCtxt;
-    use crate::next_solver::infer::traits::{
-        Obligation, ObligationCause, PredicateObligation, PredicateObligations,
-    };
+    use crate::next_solver::infer::traits::{Obligation, ObligationCause, PredicateObligations};
     use crate::next_solver::{
-        AliasTerm, Binder, ClauseKind, Const, ConstKind, Ctor, DbInterner, ExistentialPredicate,
-        GenericArgs, ParamEnv, Predicate, PredicateKind, Region, SolverDefId, Term, TraitPredicate,
-        TraitRef, Ty, TyKind,
+        Binder, ClauseKind, Const, ConstKind, Ctor, DbInterner, ExistentialPredicate, GenericArgs,
+        ParamEnv, Predicate, PredicateKind, Region, SolverDefId, Term, TraitRef, Ty, TyKind,
     };
 
     /// Compute the predicates that are required for a type to be well-formed.
     ///
     /// This is only intended to be used in the new solver, since it does not
     /// take into account recursion depth or proper error-reporting spans.
-    pub fn unnormalized_obligations<'db>(
+    pub(crate) fn unnormalized_obligations<'db>(
         infcx: &InferCtxt<'db>,
         param_env: ParamEnv<'db>,
         term: Term<'db>,
@@ -683,158 +669,11 @@
         recursion_depth: usize,
     }
 
-    /// Controls whether we "elaborate" supertraits and so forth on the WF
-    /// predicates. This is a kind of hack to address #43784. The
-    /// underlying problem in that issue was a trait structure like:
-    ///
-    /// ```ignore (illustrative)
-    /// trait Foo: Copy { }
-    /// trait Bar: Foo { }
-    /// impl<T: Bar> Foo for T { }
-    /// impl<T> Bar for T { }
-    /// ```
-    ///
-    /// Here, in the `Foo` impl, we will check that `T: Copy` holds -- but
-    /// we decide that this is true because `T: Bar` is in the
-    /// where-clauses (and we can elaborate that to include `T:
-    /// Copy`). This wouldn't be a problem, except that when we check the
-    /// `Bar` impl, we decide that `T: Foo` must hold because of the `Foo`
-    /// impl. And so nowhere did we check that `T: Copy` holds!
-    ///
-    /// To resolve this, we elaborate the WF requirements that must be
-    /// proven when checking impls. This means that (e.g.) the `impl Bar
-    /// for T` will be forced to prove not only that `T: Foo` but also `T:
-    /// Copy` (which it won't be able to do, because there is no `Copy`
-    /// impl for `T`).
-    #[derive(Debug, PartialEq, Eq, Copy, Clone)]
-    enum Elaborate {
-        All,
-        None,
-    }
-
     impl<'a, 'db> WfPredicates<'a, 'db> {
         fn interner(&self) -> DbInterner<'db> {
             self.infcx.interner
         }
 
-        /// Pushes the obligations required for `trait_ref` to be WF into `self.out`.
-        fn add_wf_preds_for_trait_pred(
-            &mut self,
-            trait_pred: TraitPredicate<'db>,
-            elaborate: Elaborate,
-        ) {
-            let tcx = self.interner();
-            let trait_ref = trait_pred.trait_ref;
-
-            // Negative trait predicates don't require supertraits to hold, just
-            // that their args are WF.
-            if trait_pred.polarity == PredicatePolarity::Negative {
-                self.add_wf_preds_for_negative_trait_pred(trait_ref);
-                return;
-            }
-
-            // if the trait predicate is not const, the wf obligations should not be const as well.
-            let obligations = self.nominal_obligations(trait_ref.def_id.0.into(), trait_ref.args);
-
-            debug!("compute_trait_pred obligations {:?}", obligations);
-            let param_env = self.param_env;
-            let depth = self.recursion_depth;
-
-            let extend = |PredicateObligation { predicate, mut cause, .. }| {
-                Obligation::with_depth(tcx, cause, depth, param_env, predicate)
-            };
-
-            if let Elaborate::All = elaborate {
-                let implied_obligations = rustc_type_ir::elaborate::elaborate(tcx, obligations);
-                let implied_obligations = implied_obligations.map(extend);
-                self.out.extend(implied_obligations);
-            } else {
-                self.out.extend(obligations);
-            }
-
-            self.out.extend(
-                trait_ref
-                    .args
-                    .iter()
-                    .enumerate()
-                    .filter_map(|(i, arg)| arg.as_term().map(|t| (i, t)))
-                    .filter(|(_, term)| !term.has_escaping_bound_vars())
-                    .map(|(i, term)| {
-                        let mut cause = ObligationCause::misc();
-                        // The first arg is the self ty - use the correct span for it.
-                        Obligation::with_depth(
-                            tcx,
-                            cause,
-                            depth,
-                            param_env,
-                            ClauseKind::WellFormed(term),
-                        )
-                    }),
-            );
-        }
-
-        // Compute the obligations that are required for `trait_ref` to be WF,
-        // given that it is a *negative* trait predicate.
-        fn add_wf_preds_for_negative_trait_pred(&mut self, trait_ref: TraitRef<'db>) {
-            for arg in trait_ref.args {
-                if let Some(term) = arg.as_term() {
-                    self.add_wf_preds_for_term(term);
-                }
-            }
-        }
-
-        /// Pushes the obligations required for an alias (except inherent) to be WF
-        /// into `self.out`.
-        fn add_wf_preds_for_alias_term(&mut self, data: AliasTerm<'db>) {
-            // A projection is well-formed if
-            //
-            // (a) its predicates hold (*)
-            // (b) its args are wf
-            //
-            // (*) The predicates of an associated type include the predicates of
-            //     the trait that it's contained in. For example, given
-            //
-            // trait A<T>: Clone {
-            //     type X where T: Copy;
-            // }
-            //
-            // The predicates of `<() as A<i32>>::X` are:
-            // [
-            //     `(): Sized`
-            //     `(): Clone`
-            //     `(): A<i32>`
-            //     `i32: Sized`
-            //     `i32: Clone`
-            //     `i32: Copy`
-            // ]
-            let obligations = self.nominal_obligations(data.def_id, data.args);
-            self.out.extend(obligations);
-
-            self.add_wf_preds_for_projection_args(data.args);
-        }
-
-        fn add_wf_preds_for_projection_args(&mut self, args: GenericArgs<'db>) {
-            let tcx = self.interner();
-            let cause = ObligationCause::new();
-            let param_env = self.param_env;
-            let depth = self.recursion_depth;
-
-            self.out.extend(
-                args.iter()
-                    .filter_map(|arg| arg.as_term())
-                    .filter(|term| !term.has_escaping_bound_vars())
-                    .map(|term| {
-                        Obligation::with_depth(
-                            tcx,
-                            cause.clone(),
-                            depth,
-                            param_env,
-                            ClauseKind::WellFormed(term),
-                        )
-                    }),
-            );
-        }
-
         fn require_sized(&mut self, subty: Ty<'db>) {
             if !subty.has_escaping_bound_vars() {
                 let cause = ObligationCause::new();
@@ -895,7 +734,7 @@
 
         fn add_wf_preds_for_dyn_ty(
             &mut self,
-            ty: Ty<'db>,
+            _ty: Ty<'db>,
             data: &[Binder<'db, ExistentialPredicate<'db>>],
             region: Region<'db>,
         ) {
@@ -1013,7 +852,7 @@
                     ));
                 }
 
-                TyKind::Pat(base_ty, pat) => {
+                TyKind::Pat(base_ty, _pat) => {
                     self.require_sized(base_ty);
                 }
 
@@ -1036,7 +875,7 @@
                     let obligations = self.nominal_obligations(data.def_id, data.args);
                     self.out.extend(obligations);
                 }
-                TyKind::Alias(rustc_type_ir::Inherent, data) => {
+                TyKind::Alias(rustc_type_ir::Inherent, _data) => {
                     return;
                 }
 
@@ -1148,7 +987,7 @@
                     // Let the visitor iterate into the argument/return
                     // types appearing in the fn signature.
                 }
-                TyKind::UnsafeBinder(ty) => {}
+                TyKind::UnsafeBinder(_ty) => {}
 
                 TyKind::Dynamic(data, r) => {
                     // WfObject
@@ -1291,7 +1130,7 @@
     ///
     /// Requires that trait definitions have been processed so that we can
     /// elaborate predicates and walk supertraits.
-    pub fn object_region_bounds<'db>(
+    pub(crate) fn object_region_bounds<'db>(
         interner: DbInterner<'db>,
         existential_predicates: &[Binder<'db, ExistentialPredicate<'db>>],
     ) -> Vec<Region<'db>> {
diff --git a/crates/hir-ty/src/next_solver/generic_arg.rs b/crates/hir-ty/src/next_solver/generic_arg.rs
index 38293c4..90bd44a 100644
--- a/crates/hir-ty/src/next_solver/generic_arg.rs
+++ b/crates/hir-ty/src/next_solver/generic_arg.rs
@@ -1,27 +1,20 @@
 //! Things related to generic args in the next-trait-solver.
 
 use hir_def::{GenericDefId, GenericParamId};
-use intern::{Interned, Symbol};
 use macros::{TypeFoldable, TypeVisitable};
-use rustc_type_ir::inherent::Const as _;
 use rustc_type_ir::{
-    ClosureArgs, CollectAndApply, ConstVid, CoroutineArgs, CoroutineClosureArgs, FnSig, FnSigTys,
-    GenericArgKind, IntTy, Interner, TermKind, TyKind, TyVid, TypeFoldable, TypeVisitable,
-    Variance,
-    inherent::{
-        GenericArg as _, GenericArgs as _, GenericsOf, IntoKind, SliceLike, Term as _, Ty as _,
-    },
+    ClosureArgs, CollectAndApply, ConstVid, CoroutineArgs, CoroutineClosureArgs, FnSigTys,
+    GenericArgKind, Interner, TermKind, TyKind, TyVid, Variance,
+    inherent::{GenericArg as _, GenericsOf, IntoKind, SliceLike, Term as _, Ty as _},
     relate::{Relate, VarianceDiagInfo},
 };
 use smallvec::SmallVec;
 
-use crate::db::HirDatabase;
-use crate::next_solver::{Binder, PolyFnSig};
+use crate::next_solver::{PolyFnSig, interned_vec_db};
 
 use super::{
     Const, DbInterner, EarlyParamRegion, ErrorGuaranteed, ParamConst, Region, SolverDefId, Ty, Tys,
-    generics::{GenericParamDef, Generics},
-    interned_vec_db,
+    generics::Generics,
 };
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)]
@@ -191,7 +184,7 @@
         mut mk_kind: F,
     ) -> GenericArgs<'db>
     where
-        F: FnMut(&Symbol, u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
+        F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
     {
         let defs = interner.generics_of(def_id);
         let count = defs.count();
@@ -202,9 +195,7 @@
 
     /// Creates an all-error `GenericArgs`.
     pub fn error_for_item(interner: DbInterner<'db>, def_id: SolverDefId) -> GenericArgs<'db> {
-        GenericArgs::for_item(interner, def_id, |_, _, id, _| {
-            GenericArg::error_from_id(interner, id)
-        })
+        GenericArgs::for_item(interner, def_id, |_, id, _| GenericArg::error_from_id(interner, id))
     }
 
     /// Like `for_item`, but prefers the default of a parameter if it has any.
@@ -214,14 +205,12 @@
         mut fallback: F,
     ) -> GenericArgs<'db>
     where
-        F: FnMut(&Symbol, u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
+        F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
     {
-        let defaults = interner.db.generic_defaults_ns(def_id);
-        Self::for_item(interner, def_id.into(), |name, idx, id, prev| {
-            match defaults.get(idx as usize) {
-                Some(default) => default.instantiate(interner, prev),
-                None => fallback(name, idx, id, prev),
-            }
+        let defaults = interner.db.generic_defaults(def_id);
+        Self::for_item(interner, def_id.into(), |idx, id, prev| match defaults.get(idx as usize) {
+            Some(default) => default.instantiate(interner, prev),
+            None => fallback(idx, id, prev),
         })
     }
 
@@ -233,11 +222,11 @@
         mut fallback: F,
     ) -> GenericArgs<'db>
     where
-        F: FnMut(&Symbol, u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
+        F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
     {
         let mut iter = first.into_iter();
-        Self::for_item(interner, def_id, |name, idx, id, prev| {
-            iter.next().unwrap_or_else(|| fallback(name, idx, id, prev))
+        Self::for_item(interner, def_id, |idx, id, prev| {
+            iter.next().unwrap_or_else(|| fallback(idx, id, prev))
         })
     }
 
@@ -249,14 +238,14 @@
         mut fallback: F,
     ) -> GenericArgs<'db>
     where
-        F: FnMut(&Symbol, u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
+        F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
     {
-        let defaults = interner.db.generic_defaults_ns(def_id);
-        Self::fill_rest(interner, def_id.into(), first, |name, idx, id, prev| {
+        let defaults = interner.db.generic_defaults(def_id);
+        Self::fill_rest(interner, def_id.into(), first, |idx, id, prev| {
             defaults
                 .get(idx as usize)
                 .map(|default| default.instantiate(interner, prev))
-                .unwrap_or_else(|| fallback(name, idx, id, prev))
+                .unwrap_or_else(|| fallback(idx, id, prev))
         })
     }
 
@@ -266,9 +255,8 @@
         defs: Generics,
         mk_kind: &mut F,
     ) where
-        F: FnMut(&Symbol, u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
+        F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
     {
-        let self_len = defs.own_params.len() as u32;
         if let Some(def_id) = defs.parent {
             let parent_defs = interner.generics_of(def_id.into());
             Self::fill_item(args, interner, parent_defs, mk_kind);
@@ -278,12 +266,11 @@
 
     fn fill_single<F>(args: &mut SmallVec<[GenericArg<'db>; 8]>, defs: &Generics, mk_kind: &mut F)
     where
-        F: FnMut(&Symbol, u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
+        F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
     {
-        let start_len = args.len();
         args.reserve(defs.own_params.len());
         for param in &defs.own_params {
-            let kind = mk_kind(&param.name, args.len() as u32, param.id, args);
+            let kind = mk_kind(args.len() as u32, param.id, args);
             args.push(kind);
         }
     }
@@ -374,9 +361,7 @@
         interner: DbInterner<'db>,
         def_id: <DbInterner<'db> as rustc_type_ir::Interner>::DefId,
     ) -> <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs {
-        Self::for_item(interner, def_id, |name, index, kind, _| {
-            mk_param(interner, index, name, kind)
-        })
+        Self::for_item(interner, def_id, |index, kind, _| mk_param(interner, index, kind))
     }
 
     fn extend_with_error(
@@ -384,7 +369,7 @@
         def_id: <DbInterner<'db> as rustc_type_ir::Interner>::DefId,
         original_args: &[<DbInterner<'db> as rustc_type_ir::Interner>::GenericArg],
     ) -> <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs {
-        Self::for_item(interner, def_id, |name, index, kind, _| {
+        Self::for_item(interner, def_id, |index, kind, _| {
             if let Some(arg) = original_args.get(index as usize) {
                 *arg
             } else {
@@ -461,7 +446,6 @@
                 signature_parts_ty,
                 tupled_upvars_ty,
                 coroutine_captures_by_ref_ty,
-                coroutine_witness_ty,
             ] => rustc_type_ir::CoroutineClosureArgsParts {
                 parent_args: GenericArgs::new_from_iter(
                     DbInterner::conjure(),
@@ -494,18 +478,12 @@
     }
 }
 
-pub fn mk_param<'db>(
-    interner: DbInterner<'db>,
-    index: u32,
-    name: &Symbol,
-    id: GenericParamId,
-) -> GenericArg<'db> {
-    let name = name.clone();
+pub fn mk_param<'db>(interner: DbInterner<'db>, index: u32, id: GenericParamId) -> GenericArg<'db> {
     match id {
         GenericParamId::LifetimeParamId(id) => {
             Region::new_early_param(interner, EarlyParamRegion { index, id }).into()
         }
-        GenericParamId::TypeParamId(id) => Ty::new_param(interner, id, index, name).into(),
+        GenericParamId::TypeParamId(id) => Ty::new_param(interner, id, index).into(),
         GenericParamId::ConstParamId(id) => {
             Const::new_param(interner, ParamConst { index, id }).into()
         }
@@ -596,13 +574,4 @@
     {
         T::collect_and_apply(iter, |xs| self.mk_args(xs))
     }
-
-    pub(super) fn check_args_compatible(self, def_id: SolverDefId, args: GenericArgs<'db>) -> bool {
-        // TODO
-        true
-    }
-
-    pub(super) fn debug_assert_args_compatible(self, def_id: SolverDefId, args: GenericArgs<'db>) {
-        // TODO
-    }
 }
diff --git a/crates/hir-ty/src/next_solver/generics.rs b/crates/hir-ty/src/next_solver/generics.rs
index 5ec9a18..4d164a7 100644
--- a/crates/hir-ty/src/next_solver/generics.rs
+++ b/crates/hir-ty/src/next_solver/generics.rs
@@ -1,36 +1,22 @@
 //! Things related to generics in the next-trait-solver.
 
 use hir_def::{
-    ConstParamId, GenericDefId, GenericParamId, ItemContainerId, LifetimeParamId, Lookup,
-    TypeOrConstParamId, TypeParamId,
-    db::DefDatabase,
-    expr_store::ExpressionStore,
-    hir::generics::{
-        GenericParamDataRef, GenericParams, LifetimeParamData, LocalLifetimeParamId,
-        LocalTypeOrConstParamId, TypeOrConstParamData, TypeParamData, TypeParamProvenance,
-        WherePredicate,
-    },
+    ConstParamId, GenericDefId, GenericParamId, LifetimeParamId, TypeOrConstParamId, TypeParamId,
+    hir::generics::{GenericParams, TypeOrConstParamData},
 };
-use hir_expand::name::Name;
-use intern::{Symbol, sym};
-use la_arena::Arena;
-use rustc_type_ir::inherent::Ty as _;
-use triomphe::Arc;
 
-use crate::{db::HirDatabase, generics::parent_generic_def, next_solver::Ty};
+use crate::{db::HirDatabase, generics::parent_generic_def};
 
-use super::{Const, EarlyParamRegion, ErrorGuaranteed, ParamConst, Region, SolverDefId};
+use super::SolverDefId;
 
-use super::{DbInterner, GenericArg};
+use super::DbInterner;
 
 pub(crate) fn generics(db: &dyn HirDatabase, def: SolverDefId) -> Generics {
-    let mk_lt = |parent, index, local_id, lt: &LifetimeParamData| {
-        let name = lt.name.symbol().clone();
+    let mk_lt = |parent, index, local_id| {
         let id = GenericParamId::LifetimeParamId(LifetimeParamId { parent, local_id });
-        GenericParamDef { name, index, id }
+        GenericParamDef { index, id }
     };
     let mk_ty = |parent, index, local_id, p: &TypeOrConstParamData| {
-        let name = p.name().map(|n| n.symbol().clone()).unwrap_or_else(|| sym::MISSING_NAME);
         let id = TypeOrConstParamId { parent, local_id };
         let id = match p {
             TypeOrConstParamData::TypeParamData(_) => {
@@ -40,7 +26,7 @@
                 GenericParamId::ConstParamId(ConstParamId::from_unchecked(id))
             }
         };
-        GenericParamDef { name, index, id }
+        GenericParamDef { index, id }
     };
     let own_params_for_generic_params = |parent, params: &GenericParams| {
         let mut result = Vec::with_capacity(params.len());
@@ -51,8 +37,8 @@
             type_and_consts.next();
             index += 1;
         }
-        result.extend(params.iter_lt().map(|(local_id, data)| {
-            let lt = mk_lt(parent, index, local_id, data);
+        result.extend(params.iter_lt().map(|(local_id, _data)| {
+            let lt = mk_lt(parent, index, local_id);
             index += 1;
             lt
         }));
@@ -78,27 +64,6 @@
                 crate::ImplTraitId::TypeAliasImplTrait(type_alias_id, _) => {
                     (Some(type_alias_id.into()), Vec::new())
                 }
-                crate::ImplTraitId::AsyncBlockTypeImplTrait(def, _) => {
-                    let param = TypeOrConstParamData::TypeParamData(TypeParamData {
-                        name: None,
-                        default: None,
-                        provenance: TypeParamProvenance::TypeParamList,
-                    });
-                    // Yes, there is a parent but we don't include it in the generics
-                    // FIXME: It seems utterly sensitive to fake a generic param here.
-                    // Also, what a horrible mess!
-                    (
-                        None,
-                        vec![mk_ty(
-                            GenericDefId::FunctionId(salsa::plumbing::FromId::from_id(unsafe {
-                                salsa::Id::from_index(salsa::Id::MAX_U32 - 1)
-                            })),
-                            0,
-                            LocalTypeOrConstParamId::from_raw(la_arena::RawIdx::from_u32(0)),
-                            &param,
-                        )],
-                    )
-                }
             }
         }
         _ => panic!("No generics for {def:?}"),
@@ -121,8 +86,6 @@
 
 #[derive(Debug)]
 pub struct GenericParamDef {
-    pub(crate) name: Symbol,
-    //def_id: GenericDefId,
     index: u32,
     pub(crate) id: GenericParamId,
 }
diff --git a/crates/hir-ty/src/next_solver/infer/at.rs b/crates/hir-ty/src/next_solver/infer/at.rs
index 8dfffe0..70b6594 100644
--- a/crates/hir-ty/src/next_solver/infer/at.rs
+++ b/crates/hir-ty/src/next_solver/infer/at.rs
@@ -36,7 +36,7 @@
     AliasTerm, AliasTy, Binder, Const, DbInterner, GenericArg, Goal, ParamEnv,
     PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, Predicate, Region, Span, Term,
     TraitRef, Ty,
-    fulfill::{FulfillmentCtxt, NextSolverError},
+    fulfill::NextSolverError,
     infer::relate::lattice::{LatticeOp, LatticeOpKind},
 };
 
@@ -45,16 +45,6 @@
     traits::{Obligation, ObligationCause},
 };
 
-/// Whether we should define opaque types or just treat them opaquely.
-///
-/// Currently only used to prevent predicate matching from matching anything
-/// against opaque types.
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-pub enum DefineOpaqueTypes {
-    Yes,
-    No,
-}
-
 #[derive(Clone, Copy)]
 pub struct At<'a, 'db> {
     pub infcx: &'a InferCtxt<'db>,
@@ -107,12 +97,7 @@
     /// call like `foo(x)`, where `foo: fn(i32)`, you might have
     /// `sup(i32, x)`, since the "expected" type is the type that
     /// appears in the signature.
-    pub fn sup<T>(
-        self,
-        define_opaque_types: DefineOpaqueTypes,
-        expected: T,
-        actual: T,
-    ) -> InferResult<'db, ()>
+    pub fn sup<T>(self, expected: T, actual: T) -> InferResult<'db, ()>
     where
         T: ToTrace<'db>,
     {
@@ -128,12 +113,7 @@
     }
 
     /// Makes `expected <: actual`.
-    pub fn sub<T>(
-        self,
-        define_opaque_types: DefineOpaqueTypes,
-        expected: T,
-        actual: T,
-    ) -> InferResult<'db, ()>
+    pub fn sub<T>(self, expected: T, actual: T) -> InferResult<'db, ()>
     where
         T: ToTrace<'db>,
     {
@@ -149,31 +129,7 @@
     }
 
     /// Makes `expected == actual`.
-    pub fn eq<T>(
-        self,
-        define_opaque_types: DefineOpaqueTypes,
-        expected: T,
-        actual: T,
-    ) -> InferResult<'db, ()>
-    where
-        T: ToTrace<'db>,
-    {
-        self.eq_trace(
-            define_opaque_types,
-            ToTrace::to_trace(self.cause, expected, actual),
-            expected,
-            actual,
-        )
-    }
-
-    /// Makes `expected == actual`.
-    pub fn eq_trace<T>(
-        self,
-        define_opaque_types: DefineOpaqueTypes,
-        trace: TypeTrace<'db>,
-        expected: T,
-        actual: T,
-    ) -> InferResult<'db, ()>
+    pub fn eq<T>(self, expected: T, actual: T) -> InferResult<'db, ()>
     where
         T: Relate<DbInterner<'db>>,
     {
@@ -188,20 +144,14 @@
         .map(|goals| self.goals_to_obligations(goals))
     }
 
-    pub fn relate<T>(
-        self,
-        define_opaque_types: DefineOpaqueTypes,
-        expected: T,
-        variance: Variance,
-        actual: T,
-    ) -> InferResult<'db, ()>
+    pub fn relate<T>(self, expected: T, variance: Variance, actual: T) -> InferResult<'db, ()>
     where
         T: ToTrace<'db>,
     {
         match variance {
-            Variance::Covariant => self.sub(define_opaque_types, expected, actual),
-            Variance::Invariant => self.eq(define_opaque_types, expected, actual),
-            Variance::Contravariant => self.sup(define_opaque_types, expected, actual),
+            Variance::Covariant => self.sub(expected, actual),
+            Variance::Invariant => self.eq(expected, actual),
+            Variance::Contravariant => self.sup(expected, actual),
 
             // We could make this make sense but it's not readily
             // exposed and I don't feel like dealing with it. Note
diff --git a/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs b/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs
index beaac11..7995545 100644
--- a/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs
+++ b/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs
@@ -10,17 +10,16 @@
 use rustc_type_ir::InferTy::{self, FloatVar, IntVar, TyVar};
 use rustc_type_ir::inherent::{Const as _, IntoKind as _, Region as _, SliceLike, Ty as _};
 use rustc_type_ir::{
-    BoundVar, CanonicalQueryInput, DebruijnIndex, Flags, InferConst, RegionKind, TyVid, TypeFlags,
-    TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, UniverseIndex,
+    BoundVar, BoundVarIndexKind, CanonicalQueryInput, DebruijnIndex, Flags, InferConst, RegionKind,
+    TyVid, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, UniverseIndex,
 };
 use smallvec::SmallVec;
 use tracing::debug;
 
 use crate::next_solver::infer::InferCtxt;
 use crate::next_solver::{
-    Binder, BoundConst, BoundRegion, BoundRegionKind, BoundTy, Canonical, CanonicalVarKind,
-    CanonicalVars, Const, ConstKind, DbInterner, GenericArg, ParamEnvAnd, Placeholder, Region, Ty,
-    TyKind,
+    Binder, Canonical, CanonicalVarKind, CanonicalVars, Const, ConstKind, DbInterner, GenericArg,
+    ParamEnvAnd, Placeholder, Region, Ty, TyKind,
 };
 
 /// When we canonicalize a value to form a query, we wind up replacing
@@ -345,12 +344,9 @@
 
     fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
         match r.kind() {
-            RegionKind::ReBound(index, ..) => {
-                if index >= self.binder_index {
-                    panic!("escaping late-bound region during canonicalization");
-                } else {
-                    r
-                }
+            RegionKind::ReBound(BoundVarIndexKind::Bound(..), ..) => r,
+            RegionKind::ReBound(BoundVarIndexKind::Canonical, ..) => {
+                panic!("canonicalized bound var found during canonicalization");
             }
 
             RegionKind::ReStatic
@@ -427,12 +423,9 @@
                 self.canonicalize_ty_var(CanonicalVarKind::PlaceholderTy(placeholder), t)
             }
 
-            TyKind::Bound(debruijn, _) => {
-                if debruijn >= self.binder_index {
-                    panic!("escaping bound type during canonicalization")
-                } else {
-                    t
-                }
+            TyKind::Bound(BoundVarIndexKind::Bound(..), _) => t,
+            TyKind::Bound(BoundVarIndexKind::Canonical, ..) => {
+                panic!("canonicalized bound var found during canonicalization");
             }
 
             TyKind::Closure(..)
@@ -503,12 +496,11 @@
             ConstKind::Infer(InferConst::Fresh(_)) => {
                 panic!("encountered a fresh const during canonicalization")
             }
-            ConstKind::Bound(debruijn, _) => {
-                if debruijn >= self.binder_index {
-                    panic!("escaping bound const during canonicalization")
-                } else {
-                    return ct;
-                }
+            ConstKind::Bound(BoundVarIndexKind::Bound(..), _) => {
+                return ct;
+            }
+            ConstKind::Bound(BoundVarIndexKind::Canonical, ..) => {
+                panic!("canonicalized bound var found during canonicalization");
             }
             ConstKind::Placeholder(placeholder) => {
                 return self
@@ -758,8 +750,7 @@
         r: Region<'db>,
     ) -> Region<'db> {
         let var = self.canonical_var(info, r.into());
-        let br = BoundRegion { var, kind: BoundRegionKind::Anon };
-        Region::new_bound(self.cx(), self.binder_index, br)
+        Region::new_canonical_bound(self.cx(), var)
     }
 
     /// Given a type variable `ty_var` of the given kind, first check
@@ -769,11 +760,7 @@
     fn canonicalize_ty_var(&mut self, info: CanonicalVarKind<'db>, ty_var: Ty<'db>) -> Ty<'db> {
         debug_assert_eq!(ty_var, self.infcx.shallow_resolve(ty_var));
         let var = self.canonical_var(info, ty_var.into());
-        Ty::new_bound(
-            self.tcx,
-            self.binder_index,
-            BoundTy { kind: crate::next_solver::BoundTyKind::Anon, var },
-        )
+        Ty::new_canonical_bound(self.cx(), var)
     }
 
     /// Given a type variable `const_var` of the given kind, first check
@@ -787,6 +774,6 @@
     ) -> Const<'db> {
         debug_assert_eq!(const_var, self.infcx.shallow_resolve_const(const_var));
         let var = self.canonical_var(info, const_var.into());
-        Const::new_bound(self.tcx, self.binder_index, BoundConst { var })
+        Const::new_canonical_bound(self.cx(), var)
     }
 }
diff --git a/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs b/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs
index 6c7a87e..6360291 100644
--- a/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs
+++ b/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs
@@ -6,24 +6,15 @@
 //!
 //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
 
-use crate::next_solver::BoundConst;
 use crate::next_solver::{
-    AliasTy, Binder, BoundRegion, BoundTy, Canonical, CanonicalVarValues, Const, DbInterner, Goal,
-    ParamEnv, Predicate, PredicateKind, Region, Ty, TyKind,
-    fold::FnMutDelegate,
-    infer::{
-        DefineOpaqueTypes, InferCtxt, TypeTrace,
-        traits::{Obligation, PredicateObligations},
-    },
+    BoundConst, BoundRegion, BoundTy, Canonical, CanonicalVarValues, Clauses, Const, ConstKind,
+    DbInterner, GenericArg, Predicate, Region, RegionKind, Ty, TyKind, fold::FnMutDelegate,
 };
+use rustc_hash::FxHashMap;
 use rustc_type_ir::{
-    AliasRelationDirection, AliasTyKind, BoundVar, GenericArgKind, InferTy, TypeFoldable, Upcast,
-    Variance,
-    inherent::{IntoKind, SliceLike},
-    relate::{
-        Relate, TypeRelation, VarianceDiagInfo,
-        combine::{super_combine_consts, super_combine_tys},
-    },
+    BoundVarIndexKind, GenericArgKind, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable,
+    TypeVisitableExt,
+    inherent::{GenericArg as _, IntoKind, SliceLike},
 };
 
 pub trait CanonicalExt<'db, V> {
@@ -102,6 +93,79 @@
             },
         };
 
-        tcx.replace_escaping_bound_vars_uncached(value, delegate)
+        let value = tcx.replace_escaping_bound_vars_uncached(value, delegate);
+        value.fold_with(&mut CanonicalInstantiator {
+            tcx,
+            var_values: var_values.var_values.as_slice(),
+            cache: Default::default(),
+        })
+    }
+}
+
+/// Replaces the bound vars in a canonical binder with var values.
+struct CanonicalInstantiator<'db, 'a> {
+    tcx: DbInterner<'db>,
+
+    // The values that the bound vars are being instantiated with.
+    var_values: &'a [GenericArg<'db>],
+
+    // Because we use `BoundVarIndexKind::Canonical`, we can cache
+    // based only on the entire ty, not worrying about a `DebruijnIndex`
+    cache: FxHashMap<Ty<'db>, Ty<'db>>,
+}
+
+impl<'db, 'a> TypeFolder<DbInterner<'db>> for CanonicalInstantiator<'db, 'a> {
+    fn cx(&self) -> DbInterner<'db> {
+        self.tcx
+    }
+
+    fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> {
+        match t.kind() {
+            TyKind::Bound(BoundVarIndexKind::Canonical, bound_ty) => {
+                self.var_values[bound_ty.var.as_usize()].expect_ty()
+            }
+            _ => {
+                if !t.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) {
+                    t
+                } else if let Some(&t) = self.cache.get(&t) {
+                    t
+                } else {
+                    let res = t.super_fold_with(self);
+                    assert!(self.cache.insert(t, res).is_none());
+                    res
+                }
+            }
+        }
+    }
+
+    fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
+        match r.kind() {
+            RegionKind::ReBound(BoundVarIndexKind::Canonical, br) => {
+                self.var_values[br.var.as_usize()].expect_region()
+            }
+            _ => r,
+        }
+    }
+
+    fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> {
+        match ct.kind() {
+            ConstKind::Bound(BoundVarIndexKind::Canonical, bound_const) => {
+                self.var_values[bound_const.var.as_usize()].expect_const()
+            }
+            _ => ct.super_fold_with(self),
+        }
+    }
+
+    fn fold_predicate(&mut self, p: Predicate<'db>) -> Predicate<'db> {
+        if p.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) { p.super_fold_with(self) } else { p }
+    }
+
+    fn fold_clauses(&mut self, c: Clauses<'db>) -> Clauses<'db> {
+        if !c.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) {
+            return c;
+        }
+
+        // FIXME: We might need cache here for perf like rustc
+        c.super_fold_with(self)
     }
 }
diff --git a/crates/hir-ty/src/next_solver/infer/canonical/mod.rs b/crates/hir-ty/src/next_solver/infer/canonical/mod.rs
index d0669f5..b3bd0a4 100644
--- a/crates/hir-ty/src/next_solver/infer/canonical/mod.rs
+++ b/crates/hir-ty/src/next_solver/infer/canonical/mod.rs
@@ -22,26 +22,13 @@
 //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
 
 use crate::next_solver::{
-    AliasTy, Binder, Canonical, CanonicalVarValues, CanonicalVars, Const, DbInterner, GenericArg,
-    Goal, ParamEnv, PlaceholderConst, PlaceholderRegion, PlaceholderTy, Predicate, PredicateKind,
-    Region, Ty, TyKind,
-    infer::{
-        DefineOpaqueTypes, InferCtxt, TypeTrace,
-        traits::{Obligation, PredicateObligations},
-    },
+    Canonical, CanonicalVarValues, Const, DbInterner, GenericArg, PlaceholderConst,
+    PlaceholderRegion, PlaceholderTy, Region, Ty, TyKind, infer::InferCtxt,
 };
 use instantiate::CanonicalExt;
 use rustc_index::IndexVec;
 use rustc_type_ir::inherent::IntoKind;
-use rustc_type_ir::{
-    AliasRelationDirection, AliasTyKind, CanonicalVarKind, InferTy, TypeFoldable, UniverseIndex,
-    Upcast, Variance,
-    inherent::{SliceLike, Ty as _},
-    relate::{
-        Relate, TypeRelation, VarianceDiagInfo,
-        combine::{super_combine_consts, super_combine_tys},
-    },
-};
+use rustc_type_ir::{CanonicalVarKind, InferTy, TypeFoldable, UniverseIndex, inherent::Ty as _};
 
 pub mod canonicalizer;
 pub mod instantiate;
diff --git a/crates/hir-ty/src/next_solver/infer/context.rs b/crates/hir-ty/src/next_solver/infer/context.rs
index 5aa5ad1..397986e 100644
--- a/crates/hir-ty/src/next_solver/infer/context.rs
+++ b/crates/hir-ty/src/next_solver/infer/context.rs
@@ -1,19 +1,19 @@
 //! Definition of `InferCtxtLike` from the librarified type layer.
 
 use rustc_type_ir::{
-    ConstVid, FloatVarValue, FloatVid, GenericArgKind, InferConst, InferTy, IntTy, IntVarValue,
-    IntVid, RegionVid, TyVid, TypeFoldable, TypingMode, UniverseIndex,
-    inherent::{Const as _, IntoKind, Span as _, Ty as _},
+    ConstVid, FloatVarValue, FloatVid, GenericArgKind, InferConst, InferTy, IntVarValue, IntVid,
+    RegionVid, TyVid, TypeFoldable, TypingMode, UniverseIndex,
+    inherent::{Const as _, IntoKind, Ty as _},
     relate::combine::PredicateEmittingRelation,
 };
 
 use crate::next_solver::{
-    Binder, Const, ConstKind, DbInterner, ErrorGuaranteed, GenericArgs, OpaqueTypeKey, ParamEnv,
-    Region, SolverDefId, Span, Ty, TyKind,
+    Binder, Const, ConstKind, DbInterner, ErrorGuaranteed, GenericArgs, OpaqueTypeKey, Region,
+    SolverDefId, Span, Ty, TyKind,
     infer::opaque_types::{OpaqueHiddenType, table::OpaqueTypeStorageEntries},
 };
 
-use super::{BoundRegionConversionTime, InferCtxt, relate::RelateResult, traits::ObligationCause};
+use super::{BoundRegionConversionTime, InferCtxt, relate::RelateResult};
 
 impl<'db> rustc_type_ir::InferCtxtLike for InferCtxt<'db> {
     type Interner = DbInterner<'db>;
@@ -250,16 +250,16 @@
         self.probe(|_| probe())
     }
 
-    fn sub_regions(&self, sub: Region<'db>, sup: Region<'db>, span: Span) {
+    fn sub_regions(&self, sub: Region<'db>, sup: Region<'db>, _span: Span) {
         self.inner.borrow_mut().unwrap_region_constraints().make_subregion(sub, sup);
     }
 
-    fn equate_regions(&self, a: Region<'db>, b: Region<'db>, span: Span) {
+    fn equate_regions(&self, a: Region<'db>, b: Region<'db>, _span: Span) {
         self.inner.borrow_mut().unwrap_region_constraints().make_eqregion(a, b);
     }
 
-    fn register_ty_outlives(&self, ty: Ty<'db>, r: Region<'db>, span: Span) {
-        //self.register_region_obligation_with_cause(ty, r, &ObligationCause::dummy_with_span(Span::dummy()));
+    fn register_ty_outlives(&self, _ty: Ty<'db>, _r: Region<'db>, _span: Span) {
+        // self.register_type_outlives_constraint(ty, r, &ObligationCause::dummy());
     }
 
     type OpaqueTypeStorageEntries = OpaqueTypeStorageEntries;
diff --git a/crates/hir-ty/src/next_solver/infer/mod.rs b/crates/hir-ty/src/next_solver/infer/mod.rs
index e1a46fa..36c6c48 100644
--- a/crates/hir-ty/src/next_solver/infer/mod.rs
+++ b/crates/hir-ty/src/next_solver/infer/mod.rs
@@ -6,32 +6,23 @@
 use std::sync::Arc;
 
 pub use BoundRegionConversionTime::*;
-pub use at::DefineOpaqueTypes;
-use ena::undo_log::UndoLogs;
 use ena::unify as ut;
 use hir_def::GenericParamId;
 use hir_def::lang_item::LangItem;
-use intern::Symbol;
 use opaque_types::{OpaqueHiddenType, OpaqueTypeStorage};
-use region_constraints::{
-    GenericKind, RegionConstraintCollector, RegionConstraintStorage, UndoLog, VarInfos, VerifyBound,
-};
-pub use relate::StructurallyRelateAliases;
-pub use relate::combine::PredicateEmittingRelation;
-use rustc_hash::{FxHashMap, FxHashSet};
+use region_constraints::{RegionConstraintCollector, RegionConstraintStorage};
 use rustc_next_trait_solver::solve::SolverDelegateEvalExt;
 use rustc_pattern_analysis::Captures;
+use rustc_type_ir::TypeFoldable;
 use rustc_type_ir::error::{ExpectedFound, TypeError};
 use rustc_type_ir::inherent::{
-    Const as _, GenericArg as _, GenericArgs as _, IntoKind, ParamEnv as _, SliceLike, Term as _,
-    Ty as _,
+    Const as _, GenericArg as _, GenericArgs as _, IntoKind, SliceLike, Term as _, Ty as _,
 };
 use rustc_type_ir::{
-    BoundVar, ClosureKind, ConstVid, FloatTy, FloatVarValue, FloatVid, GenericArgKind, InferConst,
-    InferTy, IntTy, IntVarValue, IntVid, OutlivesPredicate, RegionVid, TyVid, UniverseIndex,
+    ClosureKind, ConstVid, FloatVarValue, FloatVid, GenericArgKind, InferConst, InferTy,
+    IntVarValue, IntVid, OutlivesPredicate, RegionVid, TyVid, UniverseIndex,
 };
 use rustc_type_ir::{TermKind, TypeVisitableExt};
-use rustc_type_ir::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use snapshot::undo_log::InferCtxtUndoLogs;
 use tracing::{debug, instrument};
 use traits::{ObligationCause, PredicateObligations};
@@ -39,19 +30,17 @@
 use unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey};
 
 use crate::next_solver::fold::BoundVarReplacerDelegate;
-use crate::next_solver::infer::opaque_types::table::OpaqueTypeStorageEntries;
 use crate::next_solver::infer::select::EvaluationResult;
 use crate::next_solver::infer::traits::PredicateObligation;
 use crate::next_solver::obligation_ctxt::ObligationCtxt;
 use crate::next_solver::{BoundConst, BoundRegion, BoundTy, BoundVarKind, Goal, SolverContext};
 
-use super::generics::GenericParamDef;
 use super::{
-    AliasTerm, Binder, BoundRegionKind, CanonicalQueryInput, CanonicalVarValues, Const, ConstKind,
-    DbInterner, ErrorGuaranteed, FxIndexMap, GenericArg, GenericArgs, OpaqueTypeKey, ParamEnv,
-    PlaceholderRegion, PolyCoercePredicate, PolyExistentialProjection, PolyExistentialTraitRef,
-    PolyFnSig, PolyRegionOutlivesPredicate, PolySubtypePredicate, Predicate, Region, SolverDefId,
-    SubtypePredicate, Term, TraitPredicate, TraitRef, Ty, TyKind, TypingMode,
+    AliasTerm, Binder, CanonicalQueryInput, CanonicalVarValues, Const, ConstKind, DbInterner,
+    ErrorGuaranteed, GenericArg, GenericArgs, OpaqueTypeKey, ParamEnv, PolyCoercePredicate,
+    PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyRegionOutlivesPredicate,
+    PolySubtypePredicate, Region, SolverDefId, SubtypePredicate, Term, TraitRef, Ty, TyKind,
+    TypingMode,
 };
 
 pub mod at;
@@ -82,8 +71,6 @@
 }
 pub type InferResult<'db, T> = Result<InferOk<'db, T>, TypeError<DbInterner<'db>>>;
 
-pub(crate) type FixupResult<T> = Result<T, FixupError>; // "fixup result"
-
 pub(crate) type UnificationTable<'a, 'db, T> = ut::UnificationTable<
     ut::InPlace<T, &'a mut ut::UnificationStorage<T>, &'a mut InferCtxtUndoLogs<'db>>,
 >;
@@ -440,6 +427,7 @@
     ///     check::<&'_ T>();
     /// }
     /// ```
+    #[expect(dead_code, reason = "this is used in rustc")]
     fn predicate_must_hold_considering_regions(
         &self,
         obligation: &PredicateObligation<'db>,
@@ -452,14 +440,13 @@
     /// not entirely accurate if inference variables are involved.
     ///
     /// This version ignores all outlives constraints.
+    #[expect(dead_code, reason = "this is used in rustc")]
     fn predicate_must_hold_modulo_regions(&self, obligation: &PredicateObligation<'db>) -> bool {
         self.evaluate_obligation(obligation).must_apply_modulo_regions()
     }
 
     /// Evaluate a given predicate, capturing overflow and propagating it back.
     fn evaluate_obligation(&self, obligation: &PredicateObligation<'db>) -> EvaluationResult {
-        let param_env = obligation.param_env;
-
         self.probe(|snapshot| {
             let mut ocx = ObligationCtxt::new(self);
             ocx.register_obligation(obligation.clone());
@@ -583,16 +570,16 @@
 
         self.enter_forall(predicate, |SubtypePredicate { a_is_expected, a, b }| {
             if a_is_expected {
-                Ok(self.at(cause, param_env).sub(DefineOpaqueTypes::Yes, a, b))
+                Ok(self.at(cause, param_env).sub(a, b))
             } else {
-                Ok(self.at(cause, param_env).sup(DefineOpaqueTypes::Yes, b, a))
+                Ok(self.at(cause, param_env).sup(b, a))
             }
         })
     }
 
     pub fn region_outlives_predicate(
         &self,
-        cause: &traits::ObligationCause,
+        _cause: &traits::ObligationCause,
         predicate: PolyRegionOutlivesPredicate<'db>,
     ) {
         self.enter_forall(predicate, |OutlivesPredicate(r_a, r_b)| {
@@ -632,7 +619,7 @@
     }
 
     pub fn next_const_var(&self) -> Const<'db> {
-        self.next_const_var_with_origin(ConstVariableOrigin { param_def_id: None })
+        self.next_const_var_with_origin(ConstVariableOrigin {})
     }
 
     pub fn next_const_vid(&self) -> ConstVid {
@@ -640,7 +627,7 @@
             .borrow_mut()
             .const_unification_table()
             .new_key(ConstVariableValue::Unknown {
-                origin: ConstVariableOrigin { param_def_id: None },
+                origin: ConstVariableOrigin {},
                 universe: self.universe(),
             })
             .vid
@@ -657,7 +644,7 @@
     }
 
     pub fn next_const_var_in_universe(&self, universe: UniverseIndex) -> Const<'db> {
-        let origin = ConstVariableOrigin { param_def_id: None };
+        let origin = ConstVariableOrigin {};
         let vid = self
             .inner
             .borrow_mut()
@@ -738,7 +725,7 @@
         self.next_region_var_in_universe(universe)
     }
 
-    fn var_for_def(&self, id: GenericParamId, name: &Symbol) -> GenericArg<'db> {
+    fn var_for_def(&self, id: GenericParamId) -> GenericArg<'db> {
         match id {
             GenericParamId::LifetimeParamId(_) => {
                 // Create a region inference variable for the given
@@ -763,7 +750,7 @@
                 Ty::new_var(self.interner, ty_var_id).into()
             }
             GenericParamId::ConstParamId(_) => {
-                let origin = ConstVariableOrigin { param_def_id: None };
+                let origin = ConstVariableOrigin {};
                 let const_var_id = self
                     .inner
                     .borrow_mut()
@@ -778,9 +765,7 @@
     /// Given a set of generics defined on a type or impl, returns the generic parameters mapping
     /// each type/region parameter to a fresh inference variable.
     pub fn fresh_args_for_item(&self, def_id: SolverDefId) -> GenericArgs<'db> {
-        GenericArgs::for_item(self.interner, def_id, |name, index, kind, _| {
-            self.var_for_def(kind, name)
-        })
+        GenericArgs::for_item(self.interner, def_id, |_index, kind, _| self.var_for_def(kind))
     }
 
     /// Like `fresh_args_for_item()`, but first uses the args from `first`.
@@ -789,8 +774,8 @@
         def_id: SolverDefId,
         first: impl IntoIterator<Item = GenericArg<'db>>,
     ) -> GenericArgs<'db> {
-        GenericArgs::fill_rest(self.interner, def_id, first, |name, index, kind, _| {
-            self.var_for_def(kind, name)
+        GenericArgs::fill_rest(self.interner, def_id, first, |_index, kind, _| {
+            self.var_for_def(kind)
         })
     }
 
@@ -828,8 +813,8 @@
                 defining_opaque_types_and_generators.contains(&id.into())
             }
             TypingMode::Coherence | TypingMode::PostAnalysis => false,
-            TypingMode::Borrowck { defining_opaque_types } => unimplemented!(),
-            TypingMode::PostBorrowckAnalysis { defined_opaque_types } => unimplemented!(),
+            TypingMode::Borrowck { defining_opaque_types: _ } => unimplemented!(),
+            TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ } => unimplemented!(),
         }
     }
 
@@ -998,7 +983,7 @@
     // use [`InferCtxt::enter_forall`] instead.
     pub fn instantiate_binder_with_fresh_vars<T>(
         &self,
-        lbrct: BoundRegionConversionTime,
+        _lbrct: BoundRegionConversionTime,
         value: Binder<'db, T>,
     ) -> T
     where
@@ -1014,7 +999,7 @@
         for bound_var_kind in bound_vars {
             let arg: GenericArg<'db> = match bound_var_kind {
                 BoundVarKind::Ty(_) => self.next_ty_var().into(),
-                BoundVarKind::Region(br) => self.next_region_var().into(),
+                BoundVarKind::Region(_) => self.next_region_var().into(),
                 BoundVarKind::Const => self.next_const_var().into(),
             };
             args.push(arg);
@@ -1070,7 +1055,7 @@
     #[inline]
     pub fn is_ty_infer_var_definitely_unchanged<'a>(
         &'a self,
-    ) -> (impl Fn(TyOrConstInferVar) -> bool + Captures<'db> + 'a) {
+    ) -> impl Fn(TyOrConstInferVar) -> bool + Captures<'db> + 'a {
         // This hoists the borrow/release out of the loop body.
         let inner = self.inner.try_borrow();
 
diff --git a/crates/hir-ty/src/next_solver/infer/opaque_types/mod.rs b/crates/hir-ty/src/next_solver/infer/opaque_types/mod.rs
index 0f68ec8..06d9984 100644
--- a/crates/hir-ty/src/next_solver/infer/opaque_types/mod.rs
+++ b/crates/hir-ty/src/next_solver/infer/opaque_types/mod.rs
@@ -1,40 +1,10 @@
 //! Things related to the infer context of the next-trait-solver.
 
-use std::sync::Arc;
-
-use tracing::{debug, instrument};
-
-use crate::next_solver::{
-    Clause, ClauseKind, FxIndexMap, GenericArgs, OpaqueTypeKey, ProjectionPredicate, SolverDefId,
-    TypingMode, util::BottomUpFolder,
-};
-
 pub(crate) mod table;
 
 pub(crate) use table::{OpaqueTypeStorage, OpaqueTypeTable};
 
-use crate::next_solver::{
-    AliasTy, Binder, BoundRegion, BoundTy, Canonical, CanonicalVarValues, Const, DbInterner, Goal,
-    ParamEnv, Predicate, PredicateKind, Region, Ty, TyKind,
-    fold::FnMutDelegate,
-    infer::{
-        DefineOpaqueTypes, InferCtxt, TypeTrace,
-        traits::{Obligation, PredicateObligations},
-    },
-};
-use rustc_type_ir::{
-    AliasRelationDirection, AliasTyKind, BoundConstness, BoundVar, Flags, GenericArgKind, InferTy,
-    Interner, RegionKind, TypeFlags, TypeFoldable, TypeSuperVisitable, TypeVisitable,
-    TypeVisitableExt, TypeVisitor, Upcast, Variance,
-    error::{ExpectedFound, TypeError},
-    inherent::{DefId, GenericArgs as _, IntoKind, SliceLike},
-    relate::{
-        Relate, TypeRelation, VarianceDiagInfo,
-        combine::{super_combine_consts, super_combine_tys},
-    },
-};
-
-use super::{InferOk, traits::ObligationCause};
+use crate::next_solver::{OpaqueTypeKey, Ty, infer::InferCtxt};
 
 #[derive(Copy, Clone, Debug)]
 pub struct OpaqueHiddenType<'db> {
diff --git a/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs b/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs
index 8ab409d..0f8b238 100644
--- a/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs
+++ b/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs
@@ -54,7 +54,7 @@
         assert!(entry.is_some());
     }
 
-    pub fn is_empty(&self) -> bool {
+    pub(crate) fn is_empty(&self) -> bool {
         let OpaqueTypeStorage { opaque_types, duplicate_entries } = self;
         opaque_types.is_empty() && duplicate_entries.is_empty()
     }
@@ -66,14 +66,14 @@
         std::mem::take(opaque_types).into_iter().chain(std::mem::take(duplicate_entries))
     }
 
-    pub fn num_entries(&self) -> OpaqueTypeStorageEntries {
+    pub(crate) fn num_entries(&self) -> OpaqueTypeStorageEntries {
         OpaqueTypeStorageEntries {
             opaque_types: self.opaque_types.len(),
             duplicate_entries: self.duplicate_entries.len(),
         }
     }
 
-    pub fn opaque_types_added_since(
+    pub(crate) fn opaque_types_added_since(
         &self,
         prev_entries: OpaqueTypeStorageEntries,
     ) -> impl Iterator<Item = (OpaqueTypeKey<'db>, OpaqueHiddenType<'db>)> {
@@ -89,7 +89,7 @@
     ///
     /// Outside of canonicalization one should generally use `iter_opaque_types`
     /// to also consider duplicate entries.
-    pub fn iter_lookup_table(
+    pub(crate) fn iter_lookup_table(
         &self,
     ) -> impl Iterator<Item = (OpaqueTypeKey<'db>, OpaqueHiddenType<'db>)> {
         self.opaque_types.iter().map(|(k, v)| (*k, *v))
@@ -100,13 +100,13 @@
     /// These have to considered when checking all opaque type uses but are e.g.
     /// irrelevant for canonical inputs as nested queries never meaningfully
     /// accesses them.
-    pub fn iter_duplicate_entries(
+    pub(crate) fn iter_duplicate_entries(
         &self,
     ) -> impl Iterator<Item = (OpaqueTypeKey<'db>, OpaqueHiddenType<'db>)> {
         self.duplicate_entries.iter().copied()
     }
 
-    pub fn iter_opaque_types(
+    pub(crate) fn iter_opaque_types(
         &self,
     ) -> impl Iterator<Item = (OpaqueTypeKey<'db>, OpaqueHiddenType<'db>)> {
         let OpaqueTypeStorage { opaque_types, duplicate_entries } = self;
@@ -144,7 +144,7 @@
 
 impl<'a, 'db> OpaqueTypeTable<'a, 'db> {
     #[instrument(skip(self), level = "debug")]
-    pub fn register(
+    pub(crate) fn register(
         &mut self,
         key: OpaqueTypeKey<'db>,
         hidden_type: OpaqueHiddenType<'db>,
@@ -159,7 +159,11 @@
         None
     }
 
-    pub fn add_duplicate(&mut self, key: OpaqueTypeKey<'db>, hidden_type: OpaqueHiddenType<'db>) {
+    pub(crate) fn add_duplicate(
+        &mut self,
+        key: OpaqueTypeKey<'db>,
+        hidden_type: OpaqueHiddenType<'db>,
+    ) {
         self.storage.duplicate_entries.push((key, hidden_type));
         self.undo_log.push(UndoLog::DuplicateOpaqueType);
     }
diff --git a/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs b/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs
index 7f15a46..ae5930d 100644
--- a/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs
+++ b/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs
@@ -1,7 +1,6 @@
 //! See `README.md`.
 
 use std::ops::Range;
-use std::sync::Arc;
 use std::{cmp, fmt, mem};
 
 use ena::undo_log::{Rollback, UndoLogs};
@@ -18,9 +17,7 @@
 use super::unify_key::RegionVidKey;
 use crate::next_solver::infer::snapshot::undo_log::{InferCtxtUndoLogs, Snapshot};
 use crate::next_solver::infer::unify_key::RegionVariableValue;
-use crate::next_solver::{
-    AliasTy, Binder, DbInterner, OpaqueTypeKey, ParamTy, PlaceholderTy, Region, Ty,
-};
+use crate::next_solver::{AliasTy, Binder, DbInterner, ParamTy, PlaceholderTy, Region, Ty};
 
 #[derive(Debug, Clone, Default)]
 pub struct RegionConstraintStorage<'db> {
@@ -254,6 +251,7 @@
     AddConstraint(usize),
 
     /// We added the given `verify`.
+    #[expect(dead_code, reason = "this is used in rustc")]
     AddVerify(usize),
 
     /// We added a GLB/LUB "combination variable".
diff --git a/crates/hir-ty/src/next_solver/infer/relate/generalize.rs b/crates/hir-ty/src/next_solver/infer/relate/generalize.rs
index 7e2735d..d06984c 100644
--- a/crates/hir-ty/src/next_solver/infer/relate/generalize.rs
+++ b/crates/hir-ty/src/next_solver/infer/relate/generalize.rs
@@ -7,8 +7,8 @@
 use rustc_type_ir::inherent::{Const as _, IntoKind, Ty as _};
 use rustc_type_ir::relate::VarianceDiagInfo;
 use rustc_type_ir::{
-    AliasRelationDirection, AliasTyKind, ConstVid, InferConst, InferCtxtLike, InferTy, RegionKind,
-    TermKind, TyVid, UniverseIndex, Variance,
+    AliasRelationDirection, ConstVid, InferConst, InferCtxtLike, InferTy, RegionKind, TermKind,
+    TyVid, UniverseIndex, Variance,
 };
 use rustc_type_ir::{Interner, TypeVisitable, TypeVisitableExt};
 use tracing::{debug, instrument, warn};
@@ -21,9 +21,8 @@
 use crate::next_solver::infer::{InferCtxt, relate};
 use crate::next_solver::util::MaxUniverse;
 use crate::next_solver::{
-    AliasTy, Binder, ClauseKind, Const, ConstKind, DbInterner, GenericArgs, PredicateKind,
-    ProjectionPredicate, Region, SolverDefId, Term, TermVid, Ty, TyKind, TypingMode,
-    UnevaluatedConst,
+    AliasTy, Binder, ClauseKind, Const, ConstKind, DbInterner, GenericArgs, PredicateKind, Region,
+    SolverDefId, Term, TermVid, Ty, TyKind, TypingMode, UnevaluatedConst,
 };
 
 impl<'db> InferCtxt<'db> {
diff --git a/crates/hir-ty/src/next_solver/infer/relate/higher_ranked.rs b/crates/hir-ty/src/next_solver/infer/relate/higher_ranked.rs
index 62028e0..c523751 100644
--- a/crates/hir-ty/src/next_solver/infer/relate/higher_ranked.rs
+++ b/crates/hir-ty/src/next_solver/infer/relate/higher_ranked.rs
@@ -2,13 +2,10 @@
 //! the end of the file for details.
 
 use rustc_type_ir::TypeFoldable;
-use rustc_type_ir::{BoundVar, UniverseIndex};
 use tracing::{debug, instrument};
 
-use super::RelateResult;
 use crate::next_solver::fold::FnMutDelegate;
 use crate::next_solver::infer::InferCtxt;
-use crate::next_solver::infer::snapshot::CombinedSnapshot;
 use crate::next_solver::{
     Binder, BoundConst, BoundRegion, BoundTy, Const, DbInterner, PlaceholderConst,
     PlaceholderRegion, PlaceholderTy, Region, Ty,
diff --git a/crates/hir-ty/src/next_solver/infer/relate/lattice.rs b/crates/hir-ty/src/next_solver/infer/relate/lattice.rs
index c7f771f..374895c 100644
--- a/crates/hir-ty/src/next_solver/infer/relate/lattice.rs
+++ b/crates/hir-ty/src/next_solver/infer/relate/lattice.rs
@@ -30,7 +30,7 @@
     AliasTy, Binder, Const, DbInterner, Goal, ParamEnv, Predicate, PredicateKind, Region, Span, Ty,
     TyKind,
     infer::{
-        DefineOpaqueTypes, InferCtxt, TypeTrace,
+        InferCtxt, TypeTrace,
         relate::RelateResult,
         traits::{Obligation, PredicateObligations},
     },
@@ -92,10 +92,7 @@
         match variance {
             Variance::Invariant => {
                 self.obligations.extend(
-                    self.infcx
-                        .at(&self.trace.cause, self.param_env)
-                        .eq_trace(DefineOpaqueTypes::Yes, self.trace.clone(), a, b)?
-                        .into_obligations(),
+                    self.infcx.at(&self.trace.cause, self.param_env).eq(a, b)?.into_obligations(),
                 );
                 Ok(a)
             }
@@ -213,12 +210,12 @@
         let at = self.infcx.at(&self.trace.cause, self.param_env);
         match self.kind {
             LatticeOpKind::Glb => {
-                self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, v, a)?.into_obligations());
-                self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, v, b)?.into_obligations());
+                self.obligations.extend(at.sub(v, a)?.into_obligations());
+                self.obligations.extend(at.sub(v, b)?.into_obligations());
             }
             LatticeOpKind::Lub => {
-                self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, a, v)?.into_obligations());
-                self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, b, v)?.into_obligations());
+                self.obligations.extend(at.sub(a, v)?.into_obligations());
+                self.obligations.extend(at.sub(b, v)?.into_obligations());
             }
         }
         Ok(())
diff --git a/crates/hir-ty/src/next_solver/infer/resolve.rs b/crates/hir-ty/src/next_solver/infer/resolve.rs
index 4bd3fbd..b6e5225 100644
--- a/crates/hir-ty/src/next_solver/infer/resolve.rs
+++ b/crates/hir-ty/src/next_solver/infer/resolve.rs
@@ -1,15 +1,14 @@
 //! Things for resolving vars in the infer context of the next-trait-solver.
 
 use rustc_type_ir::{
-    ConstKind, FallibleTypeFolder, InferConst, InferTy, RegionKind, TyKind, TypeFoldable,
     TypeFolder, TypeSuperFoldable, TypeVisitableExt,
     data_structures::DelayedMap,
-    inherent::{Const as _, IntoKind, Ty as _},
+    inherent::{Const as _, Ty as _},
 };
 
 use crate::next_solver::{Const, DbInterner, ErrorGuaranteed, Region, Ty};
 
-use super::{FixupError, FixupResult, InferCtxt};
+use super::InferCtxt;
 
 ///////////////////////////////////////////////////////////////////////////
 // OPPORTUNISTIC VAR RESOLVER
diff --git a/crates/hir-ty/src/next_solver/infer/select.rs b/crates/hir-ty/src/next_solver/infer/select.rs
index 79b0a29..52ad410 100644
--- a/crates/hir-ty/src/next_solver/infer/select.rs
+++ b/crates/hir-ty/src/next_solver/infer/select.rs
@@ -1,3 +1,5 @@
+#![expect(dead_code, reason = "this is used by rustc")]
+
 use std::ops::ControlFlow;
 
 use hir_def::{ImplId, TraitId};
@@ -61,7 +63,7 @@
 ///     so they are noops when unioned with a definite error, and within
 ///     the categories it's easy to see that the unions are correct.
 #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
-pub enum EvaluationResult {
+pub(crate) enum EvaluationResult {
     /// Evaluation successful.
     EvaluatedToOk,
     /// Evaluation successful, but there were unevaluated region obligations.
@@ -91,17 +93,17 @@
 impl EvaluationResult {
     /// Returns `true` if this evaluation result is known to apply, even
     /// considering outlives constraints.
-    pub fn must_apply_considering_regions(self) -> bool {
+    pub(crate) fn must_apply_considering_regions(self) -> bool {
         self == EvaluatedToOk
     }
 
     /// Returns `true` if this evaluation result is known to apply, ignoring
     /// outlives constraints.
-    pub fn must_apply_modulo_regions(self) -> bool {
+    pub(crate) fn must_apply_modulo_regions(self) -> bool {
         self <= EvaluatedToOkModuloRegions
     }
 
-    pub fn may_apply(self) -> bool {
+    pub(crate) fn may_apply(self) -> bool {
         match self {
             EvaluatedToOkModuloOpaqueTypes
             | EvaluatedToOk
@@ -113,7 +115,7 @@
         }
     }
 
-    pub fn is_stack_dependent(self) -> bool {
+    pub(crate) fn is_stack_dependent(self) -> bool {
         match self {
             EvaluatedToAmbigStackDependent => true,
 
@@ -135,9 +137,9 @@
 
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct SignatureMismatchData<'db> {
-    pub found_trait_ref: TraitRef<'db>,
-    pub expected_trait_ref: TraitRef<'db>,
-    pub terr: TypeError<'db>,
+    pub(crate) found_trait_ref: TraitRef<'db>,
+    pub(crate) expected_trait_ref: TraitRef<'db>,
+    pub(crate) terr: TypeError<'db>,
 }
 
 /// When performing resolution, it is typically the case that there
@@ -147,7 +149,7 @@
 /// - `Ok(None)`: could not definitely determine anything, usually due
 ///   to inconclusive type inference.
 /// - `Err(e)`: error `e` occurred
-pub type SelectionResult<'db, T> = Result<Option<T>, SelectionError<'db>>;
+pub(crate) type SelectionResult<'db, T> = Result<Option<T>, SelectionError<'db>>;
 
 /// Given the successful resolution of an obligation, the `ImplSource`
 /// indicates where the impl comes from.
@@ -179,7 +181,7 @@
 ///
 /// See explanation on `ImplSourceUserDefinedData`.
 #[derive(Debug, Clone, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)]
-pub enum ImplSource<'db, N> {
+pub(crate) enum ImplSource<'db, N> {
     /// ImplSource identifying a particular impl.
     UserDefined(ImplSourceUserDefinedData<'db, N>),
 
@@ -194,28 +196,28 @@
 }
 
 impl<'db, N> ImplSource<'db, N> {
-    pub fn nested_obligations(self) -> Vec<N> {
+    pub(crate) fn nested_obligations(self) -> Vec<N> {
         match self {
             ImplSource::UserDefined(i) => i.nested,
             ImplSource::Param(n) | ImplSource::Builtin(_, n) => n,
         }
     }
 
-    pub fn borrow_nested_obligations(&self) -> &[N] {
+    pub(crate) fn borrow_nested_obligations(&self) -> &[N] {
         match self {
             ImplSource::UserDefined(i) => &i.nested,
             ImplSource::Param(n) | ImplSource::Builtin(_, n) => n,
         }
     }
 
-    pub fn borrow_nested_obligations_mut(&mut self) -> &mut [N] {
+    pub(crate) fn borrow_nested_obligations_mut(&mut self) -> &mut [N] {
         match self {
             ImplSource::UserDefined(i) => &mut i.nested,
             ImplSource::Param(n) | ImplSource::Builtin(_, n) => n,
         }
     }
 
-    pub fn map<M, F>(self, f: F) -> ImplSource<'db, M>
+    pub(crate) fn map<M, F>(self, f: F) -> ImplSource<'db, M>
     where
         F: FnMut(N) -> M,
     {
@@ -244,15 +246,15 @@
 /// is `()`, because codegen only requires a shallow resolution of an
 /// impl, and nested obligations are satisfied later.
 #[derive(Debug, Clone, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)]
-pub struct ImplSourceUserDefinedData<'db, N> {
+pub(crate) struct ImplSourceUserDefinedData<'db, N> {
     #[type_visitable(ignore)]
     #[type_foldable(identity)]
-    pub impl_def_id: ImplId,
-    pub args: GenericArgs<'db>,
-    pub nested: Vec<N>,
+    pub(crate) impl_def_id: ImplId,
+    pub(crate) args: GenericArgs<'db>,
+    pub(crate) nested: Vec<N>,
 }
 
-pub type Selection<'db> = ImplSource<'db, PredicateObligation<'db>>;
+pub(crate) type Selection<'db> = ImplSource<'db, PredicateObligation<'db>>;
 
 impl<'db> InferCtxt<'db> {
     pub(crate) fn select(
@@ -351,7 +353,9 @@
         // Prefer dyn candidates over non-dyn candidates. This is necessary to
         // handle the unsoundness between `impl<T: ?Sized> Any for T` and `dyn Any: Any`.
         (
-            CandidateSource::Impl(_) | CandidateSource::ParamEnv(_) | CandidateSource::AliasBound,
+            CandidateSource::Impl(_)
+            | CandidateSource::ParamEnv(_)
+            | CandidateSource::AliasBound(_),
             CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }),
         ) => true,
 
@@ -397,7 +401,9 @@
                 })
             }
             CandidateSource::BuiltinImpl(builtin) => ImplSource::Builtin(builtin, nested),
-            CandidateSource::ParamEnv(_) | CandidateSource::AliasBound => ImplSource::Param(nested),
+            CandidateSource::ParamEnv(_) | CandidateSource::AliasBound(_) => {
+                ImplSource::Param(nested)
+            }
             CandidateSource::CoherenceUnknowable => {
                 panic!("didn't expect to select an unknowable candidate")
             }
diff --git a/crates/hir-ty/src/next_solver/infer/snapshot/fudge.rs b/crates/hir-ty/src/next_solver/infer/snapshot/fudge.rs
index 7435357..5902f80 100644
--- a/crates/hir-ty/src/next_solver/infer/snapshot/fudge.rs
+++ b/crates/hir-ty/src/next_solver/infer/snapshot/fudge.rs
@@ -41,9 +41,7 @@
         range.clone(),
         iter_idx_range(range)
             .map(|index| match table.probe_value(index) {
-                ConstVariableValue::Known { value: _ } => {
-                    ConstVariableOrigin { param_def_id: None }
-                }
+                ConstVariableValue::Known { value: _ } => ConstVariableOrigin {},
                 ConstVariableValue::Unknown { origin, universe: _ } => origin,
             })
             .collect(),
@@ -228,7 +226,6 @@
     fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
         if let RegionKind::ReVar(vid) = r.kind() {
             if self.snapshot_vars.region_vars.contains(&vid) {
-                let idx = vid.index() - self.snapshot_vars.region_vars.start.index();
                 self.infcx.next_region_var()
             } else {
                 r
diff --git a/crates/hir-ty/src/next_solver/infer/snapshot/undo_log.rs b/crates/hir-ty/src/next_solver/infer/snapshot/undo_log.rs
index 05a1013..c8ec8da 100644
--- a/crates/hir-ty/src/next_solver/infer/snapshot/undo_log.rs
+++ b/crates/hir-ty/src/next_solver/infer/snapshot/undo_log.rs
@@ -1,7 +1,5 @@
 //! Snapshotting in the infer ctxt of the next-trait-solver.
 
-use std::marker::PhantomData;
-
 use ena::snapshot_vec as sv;
 use ena::undo_log::{Rollback, UndoLogs};
 use ena::unify as ut;
@@ -14,7 +12,6 @@
 use crate::next_solver::infer::unify_key::ConstVidKey;
 use crate::next_solver::infer::unify_key::RegionVidKey;
 use crate::next_solver::infer::{InferCtxtInner, region_constraints, type_variable};
-use crate::traits;
 
 pub struct Snapshot {
     pub(crate) undo_len: usize,
@@ -31,6 +28,7 @@
     FloatUnificationTable(sv::UndoLog<ut::Delegate<FloatVid>>),
     RegionConstraintCollector(region_constraints::UndoLog<'db>),
     RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'db>>>),
+    #[expect(dead_code, reason = "this is used in rustc")]
     PushRegionObligation,
 }
 
diff --git a/crates/hir-ty/src/next_solver/infer/traits.rs b/crates/hir-ty/src/next_solver/infer/traits.rs
index bc905c2..4f000c2 100644
--- a/crates/hir-ty/src/next_solver/infer/traits.rs
+++ b/crates/hir-ty/src/next_solver/infer/traits.rs
@@ -9,17 +9,13 @@
 
 use hir_def::TraitId;
 use macros::{TypeFoldable, TypeVisitable};
+use rustc_type_ir::Upcast;
 use rustc_type_ir::elaborate::Elaboratable;
-use rustc_type_ir::{
-    PredicatePolarity, Upcast,
-    solve::{Certainty, NoSolution},
-};
-use rustc_type_ir::{TypeFoldable, TypeVisitable};
 use tracing::debug;
 
 use crate::next_solver::{
-    Binder, Clause, DbInterner, Goal, ParamEnv, PolyTraitPredicate, Predicate, SolverDefId, Span,
-    TraitPredicate, TraitRef, Ty,
+    Clause, DbInterner, Goal, ParamEnv, PolyTraitPredicate, Predicate, Span, TraitPredicate,
+    TraitRef, Ty,
 };
 
 use super::InferCtxt;
@@ -106,9 +102,9 @@
     fn child_with_derived_cause(
         &self,
         clause: Clause<'db>,
-        span: Span,
-        parent_trait_pred: PolyTraitPredicate<'db>,
-        index: usize,
+        _span: Span,
+        _parent_trait_pred: PolyTraitPredicate<'db>,
+        _index: usize,
     ) -> Self {
         let cause = ObligationCause::new();
         Obligation {
@@ -153,16 +149,16 @@
     }
 }
 
-pub type PredicateObligation<'db> = Obligation<'db, Predicate<'db>>;
-pub type TraitObligation<'db> = Obligation<'db, TraitPredicate<'db>>;
+pub(crate) type PredicateObligation<'db> = Obligation<'db, Predicate<'db>>;
+pub(crate) type TraitObligation<'db> = Obligation<'db, TraitPredicate<'db>>;
 
-pub type PredicateObligations<'db> = Vec<PredicateObligation<'db>>;
+pub(crate) type PredicateObligations<'db> = Vec<PredicateObligation<'db>>;
 
 impl<'db> PredicateObligation<'db> {
     /// Flips the polarity of the inner predicate.
     ///
     /// Given `T: Trait` predicate it returns `T: !Trait` and given `T: !Trait` returns `T: Trait`.
-    pub fn flip_polarity(&self, tcx: DbInterner<'db>) -> Option<PredicateObligation<'db>> {
+    pub fn flip_polarity(&self, _interner: DbInterner<'db>) -> Option<PredicateObligation<'db>> {
         Some(PredicateObligation {
             cause: self.cause.clone(),
             param_env: self.param_env,
@@ -215,7 +211,7 @@
 /// `bound` or is not known to meet bound (note that this is
 /// conservative towards *no impl*, which is the opposite of the
 /// `evaluate` methods).
-pub fn type_known_to_meet_bound_modulo_regions<'tcx>(
+pub(crate) fn type_known_to_meet_bound_modulo_regions<'tcx>(
     infcx: &InferCtxt<'tcx>,
     param_env: ParamEnv<'tcx>,
     ty: Ty<'tcx>,
diff --git a/crates/hir-ty/src/next_solver/infer/unify_key.rs b/crates/hir-ty/src/next_solver/infer/unify_key.rs
index dc913b2..a09f65f 100644
--- a/crates/hir-ty/src/next_solver/infer/unify_key.rs
+++ b/crates/hir-ty/src/next_solver/infer/unify_key.rs
@@ -6,18 +6,18 @@
 use ena::unify::{NoError, UnifyKey, UnifyValue};
 use rustc_type_ir::{ConstVid, RegionKind, RegionVid, UniverseIndex, inherent::IntoKind};
 
-use crate::next_solver::{Const, Region, SolverDefId, Ty};
+use crate::next_solver::{Const, Region};
 
 #[derive(Clone, Debug)]
-pub enum RegionVariableValue<'db> {
+pub(crate) enum RegionVariableValue<'db> {
     Known { value: Region<'db> },
     Unknown { universe: UniverseIndex },
 }
 
 #[derive(PartialEq, Copy, Clone, Debug)]
-pub struct RegionVidKey<'db> {
-    pub vid: RegionVid,
-    pub phantom: PhantomData<RegionVariableValue<'db>>,
+pub(crate) struct RegionVidKey<'db> {
+    pub(crate) vid: RegionVid,
+    pub(crate) phantom: PhantomData<RegionVariableValue<'db>>,
 }
 
 impl<'db> From<RegionVid> for RegionVidKey<'db> {
@@ -41,7 +41,7 @@
     }
 }
 
-pub struct RegionUnificationError;
+pub(crate) struct RegionUnificationError;
 impl<'db> UnifyValue for RegionVariableValue<'db> {
     type Error = RegionUnificationError;
 
@@ -90,15 +90,10 @@
 // Generic consts.
 
 #[derive(Copy, Clone, Debug)]
-pub struct ConstVariableOrigin {
-    /// `DefId` of the const parameter this was instantiated for, if any.
-    ///
-    /// This should only be used for diagnostics.
-    pub param_def_id: Option<SolverDefId>,
-}
+pub struct ConstVariableOrigin {}
 
 #[derive(Clone, Debug)]
-pub enum ConstVariableValue<'db> {
+pub(crate) enum ConstVariableValue<'db> {
     Known { value: Const<'db> },
     Unknown { origin: ConstVariableOrigin, universe: UniverseIndex },
 }
@@ -106,7 +101,7 @@
 impl<'db> ConstVariableValue<'db> {
     /// If this value is known, returns the const it is known to be.
     /// Otherwise, `None`.
-    pub fn known(&self) -> Option<Const<'db>> {
+    pub(crate) fn known(&self) -> Option<Const<'db>> {
         match self {
             ConstVariableValue::Unknown { .. } => None,
             ConstVariableValue::Known { value } => Some(*value),
@@ -115,9 +110,9 @@
 }
 
 #[derive(PartialEq, Copy, Clone, Debug)]
-pub struct ConstVidKey<'db> {
-    pub vid: ConstVid,
-    pub phantom: PhantomData<Const<'db>>,
+pub(crate) struct ConstVidKey<'db> {
+    pub(crate) vid: ConstVid,
+    pub(crate) phantom: PhantomData<Const<'db>>,
 }
 
 impl<'db> From<ConstVid> for ConstVidKey<'db> {
diff --git a/crates/hir-ty/src/next_solver/inspect.rs b/crates/hir-ty/src/next_solver/inspect.rs
index 0db4746..d66aa9f 100644
--- a/crates/hir-ty/src/next_solver/inspect.rs
+++ b/crates/hir-ty/src/next_solver/inspect.rs
@@ -1,4 +1,4 @@
-pub use rustc_next_trait_solver::solve::inspect::*;
+pub(crate) use rustc_next_trait_solver::solve::inspect::*;
 
 use rustc_ast_ir::try_visit;
 use rustc_next_trait_solver::{
@@ -23,11 +23,11 @@
     obligation_ctxt::ObligationCtxt,
 };
 
-pub struct InspectConfig {
-    pub max_depth: usize,
+pub(crate) struct InspectConfig {
+    pub(crate) max_depth: usize,
 }
 
-pub struct InspectGoal<'a, 'db> {
+pub(crate) struct InspectGoal<'a, 'db> {
     infcx: &'a SolverContext<'db>,
     depth: usize,
     orig_values: Vec<GenericArg<'db>>,
@@ -103,7 +103,7 @@
     }
 }
 
-pub struct InspectCandidate<'a, 'db> {
+pub(crate) struct InspectCandidate<'a, 'db> {
     goal: &'a InspectGoal<'a, 'db>,
     kind: inspect::ProbeKind<DbInterner<'db>>,
     steps: Vec<&'a inspect::ProbeStep<DbInterner<'db>>>,
@@ -113,15 +113,15 @@
 }
 
 impl<'a, 'db> InspectCandidate<'a, 'db> {
-    pub fn kind(&self) -> inspect::ProbeKind<DbInterner<'db>> {
+    pub(crate) fn kind(&self) -> inspect::ProbeKind<DbInterner<'db>> {
         self.kind
     }
 
-    pub fn result(&self) -> Result<Certainty, NoSolution> {
+    pub(crate) fn result(&self) -> Result<Certainty, NoSolution> {
         self.result.map(|c| c.value.certainty)
     }
 
-    pub fn goal(&self) -> &'a InspectGoal<'a, 'db> {
+    pub(crate) fn goal(&self) -> &'a InspectGoal<'a, 'db> {
         self.goal
     }
 
@@ -133,14 +133,17 @@
     ///
     /// This is *not* the certainty of the candidate's full nested evaluation, which
     /// can be accessed with [`Self::result`] instead.
-    pub fn shallow_certainty(&self) -> Certainty {
+    pub(crate) fn shallow_certainty(&self) -> Certainty {
         self.shallow_certainty
     }
 
     /// Visit all nested goals of this candidate without rolling
     /// back their inference constraints. This function modifies
     /// the state of the `infcx`.
-    pub fn visit_nested_no_probe<V: ProofTreeVisitor<'db>>(&self, visitor: &mut V) -> V::Result {
+    pub(crate) fn visit_nested_no_probe<V: ProofTreeVisitor<'db>>(
+        &self,
+        visitor: &mut V,
+    ) -> V::Result {
         for goal in self.instantiate_nested_goals() {
             try_visit!(goal.visit_with(visitor));
         }
@@ -152,7 +155,7 @@
     /// inference constraints. This function modifies the state of the `infcx`.
     ///
     /// See [`Self::instantiate_impl_args`] if you need the impl args too.
-    pub fn instantiate_nested_goals(&self) -> Vec<InspectGoal<'a, 'db>> {
+    pub(crate) fn instantiate_nested_goals(&self) -> Vec<InspectGoal<'a, 'db>> {
         let infcx = self.goal.infcx;
         let param_env = self.goal.goal.param_env;
         let mut orig_values = self.goal.orig_values.to_vec();
@@ -200,7 +203,7 @@
     /// Instantiate the args of an impl if this candidate came from a
     /// `CandidateSource::Impl`. This function modifies the state of the
     /// `infcx`.
-    pub fn instantiate_impl_args(&self) -> GenericArgs<'db> {
+    pub(crate) fn instantiate_impl_args(&self) -> GenericArgs<'db> {
         let infcx = self.goal.infcx;
         let param_env = self.goal.goal.param_env;
         let mut orig_values = self.goal.orig_values.to_vec();
@@ -241,7 +244,7 @@
         panic!("expected impl args probe step for `instantiate_impl_args`");
     }
 
-    pub fn instantiate_proof_tree_for_nested_goal(
+    pub(crate) fn instantiate_proof_tree_for_nested_goal(
         &self,
         source: GoalSource,
         goal: Goal<'db, Predicate<'db>>,
@@ -307,29 +310,33 @@
 
     /// Visit all nested goals of this candidate, rolling back
     /// all inference constraints.
-    pub fn visit_nested_in_probe<V: ProofTreeVisitor<'db>>(&self, visitor: &mut V) -> V::Result {
+    #[expect(dead_code, reason = "used in rustc")]
+    pub(crate) fn visit_nested_in_probe<V: ProofTreeVisitor<'db>>(
+        &self,
+        visitor: &mut V,
+    ) -> V::Result {
         self.goal.infcx.probe(|_| self.visit_nested_no_probe(visitor))
     }
 }
 
 impl<'a, 'db> InspectGoal<'a, 'db> {
-    pub fn infcx(&self) -> &'a InferCtxt<'db> {
+    pub(crate) fn infcx(&self) -> &'a InferCtxt<'db> {
         self.infcx
     }
 
-    pub fn goal(&self) -> Goal<'db, Predicate<'db>> {
+    pub(crate) fn goal(&self) -> Goal<'db, Predicate<'db>> {
         self.goal
     }
 
-    pub fn result(&self) -> Result<Certainty, NoSolution> {
+    pub(crate) fn result(&self) -> Result<Certainty, NoSolution> {
         self.result
     }
 
-    pub fn source(&self) -> GoalSource {
+    pub(crate) fn source(&self) -> GoalSource {
         self.source
     }
 
-    pub fn depth(&self) -> usize {
+    pub(crate) fn depth(&self) -> usize {
         self.depth
     }
 
@@ -405,7 +412,7 @@
         }
     }
 
-    pub fn candidates(&'a self) -> Vec<InspectCandidate<'a, 'db>> {
+    pub(crate) fn candidates(&'a self) -> Vec<InspectCandidate<'a, 'db>> {
         let mut candidates = vec![];
         let mut nested_goals = vec![];
         self.candidates_recur(&mut candidates, &mut nested_goals, &self.final_revision);
@@ -415,7 +422,7 @@
     /// Returns the single candidate applicable for the current goal, if it exists.
     ///
     /// Returns `None` if there are either no or multiple applicable candidates.
-    pub fn unique_applicable_candidate(&'a self) -> Option<InspectCandidate<'a, 'db>> {
+    pub(crate) fn unique_applicable_candidate(&'a self) -> Option<InspectCandidate<'a, 'db>> {
         // FIXME(-Znext-solver): This does not handle impl candidates
         // hidden by env candidates.
         let mut candidates = self.candidates();
@@ -467,7 +474,7 @@
 }
 
 /// The public API to interact with proof trees.
-pub trait ProofTreeVisitor<'db> {
+pub(crate) trait ProofTreeVisitor<'db> {
     type Result: VisitorResult;
 
     fn config(&self) -> InspectConfig {
diff --git a/crates/hir-ty/src/next_solver/interner.rs b/crates/hir-ty/src/next_solver/interner.rs
index 3fd8e7b..c1ccbaf 100644
--- a/crates/hir-ty/src/next_solver/interner.rs
+++ b/crates/hir-ty/src/next_solver/interner.rs
@@ -1,89 +1,68 @@
 //! Things related to the Interner in the next-trait-solver.
-#![allow(unused)] // FIXME(next-solver): Remove this.
 
 use std::{fmt, ops::ControlFlow};
 
+pub use tls_cache::clear_tls_solver_cache;
 pub use tls_db::{attach_db, attach_db_allow_change, with_attached_db};
 
 use base_db::Crate;
-use chalk_ir::{ProgramClauseImplication, SeparatorTraitRef, Variances};
 use hir_def::{
-    AdtId, AttrDefId, BlockId, CallableDefId, EnumVariantId, GenericDefId, ItemContainerId, Lookup,
-    StructId, TypeAliasId, UnionId, VariantId,
+    AdtId, AttrDefId, BlockId, CallableDefId, EnumVariantId, ItemContainerId, StructId, UnionId,
+    VariantId,
     lang_item::LangItem,
     signatures::{FieldData, FnFlags, ImplFlags, StructFlags, TraitFlags},
 };
-use intern::sym::non_exhaustive;
-use intern::{Interned, impl_internable, sym};
 use la_arena::Idx;
-use rustc_abi::{Align, ReprFlags, ReprOptions};
-use rustc_ast_ir::visit::VisitorResult;
+use rustc_abi::{ReprFlags, ReprOptions};
 use rustc_hash::FxHashSet;
-use rustc_index::{IndexVec, bit_set::DenseBitSet};
+use rustc_index::bit_set::DenseBitSet;
 use rustc_type_ir::{
-    AliasTerm, AliasTermKind, AliasTy, AliasTyKind, BoundVar, CollectAndApply, DebruijnIndex,
-    EarlyBinder, FlagComputation, Flags, GenericArgKind, ImplPolarity, InferTy,
-    ProjectionPredicate, RegionKind, TermKind, TraitPredicate, TraitRef, TypeVisitableExt,
-    UniverseIndex, Upcast, Variance, WithCachedTypeInfo,
-    elaborate::{self, elaborate},
+    AliasTermKind, AliasTyKind, BoundVar, CollectAndApply, CoroutineWitnessTypes, DebruijnIndex,
+    EarlyBinder, FlagComputation, Flags, GenericArgKind, ImplPolarity, InferTy, Interner, TraitRef,
+    TypeVisitableExt, UniverseIndex, Upcast, Variance,
+    elaborate::elaborate,
     error::TypeError,
-    inherent::{
-        self, AdtDef as _, Const as _, GenericArgs as _, GenericsOf, IntoKind, ParamEnv as _,
-        Region as _, SliceLike as _, Span as _, Ty as _,
-    },
-    ir_print,
+    inherent::{self, GenericsOf, IntoKind, SliceLike as _, Span as _, Ty as _},
     lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem},
-    relate,
     solve::SizedTraitKind,
 };
-use salsa::plumbing::AsId;
-use smallvec::{SmallVec, smallvec};
-use syntax::ast::SelfParamKind;
-use tracing::debug;
-use triomphe::Arc;
 
 use crate::{
-    ConstScalar, FnAbi, Interner,
-    db::HirDatabase,
-    lower_nextsolver::{self, TyLoweringContext},
+    FnAbi,
+    db::{HirDatabase, InternedCoroutine},
     method_resolution::{ALL_FLOAT_FPS, ALL_INT_FPS, TyFingerprint},
     next_solver::{
         AdtIdWrapper, BoundConst, CallableIdWrapper, CanonicalVarKind, ClosureIdWrapper,
-        CoroutineIdWrapper, Ctor, FnSig, FxIndexMap, ImplIdWrapper, InternedWrapperNoDebug,
+        CoroutineIdWrapper, Ctor, FnSig, FxIndexMap, ImplIdWrapper, OpaqueTypeKey,
         RegionAssumptions, SolverContext, SolverDefIds, TraitIdWrapper, TypeAliasIdWrapper,
-        TypingMode,
-        infer::{
-            DbInternerInferExt, InferCtxt,
-            traits::{Obligation, ObligationCause},
-        },
-        obligation_ctxt::ObligationCtxt,
         util::{ContainsTypeErrors, explicit_item_bounds, for_trait_impls},
     },
 };
 
 use super::{
-    Binder, BoundExistentialPredicate, BoundExistentialPredicates, BoundTy, BoundTyKind, Clause,
-    ClauseKind, Clauses, Const, ConstKind, ErrorGuaranteed, ExprConst, ExternalConstraints,
-    ExternalConstraintsData, GenericArg, GenericArgs, InternedClausesWrapper, ParamConst, ParamEnv,
-    ParamTy, PlaceholderConst, PlaceholderTy, PredefinedOpaques, PredefinedOpaquesData, Predicate,
-    PredicateKind, SolverDefId, Term, Ty, TyKind, Tys, Valtree, ValueConst,
+    Binder, BoundExistentialPredicates, BoundTy, BoundTyKind, Clause, ClauseKind, Clauses, Const,
+    ErrorGuaranteed, ExprConst, ExternalConstraints, GenericArg, GenericArgs, ParamConst, ParamEnv,
+    ParamTy, PlaceholderConst, PlaceholderTy, PredefinedOpaques, Predicate, SolverDefId, Term, Ty,
+    TyKind, Tys, Valtree, ValueConst,
     abi::Safety,
     fold::{BoundVarReplacer, BoundVarReplacerDelegate, FnMutDelegate},
     generics::{Generics, generics},
-    mapping::ChalkToNextSolver,
     region::{
         BoundRegion, BoundRegionKind, EarlyParamRegion, LateParamRegion, PlaceholderRegion, Region,
     },
     util::sizedness_constraint_for_ty,
 };
 
+#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Clone)]
+pub struct InternedWrapperNoDebug<T>(pub(crate) T);
+
 #[macro_export]
 #[doc(hidden)]
 macro_rules! _interned_vec_nolifetime_salsa {
     ($name:ident, $ty:ty) => {
         interned_vec_nolifetime_salsa!($name, $ty, nofold);
 
-        impl<'db> rustc_type_ir::TypeFoldable<DbInterner<'db>> for $name {
+        impl<'db> rustc_type_ir::TypeFoldable<DbInterner<'db>> for $name<'db> {
             fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
                 self,
                 folder: &mut F,
@@ -104,7 +83,7 @@
             }
         }
 
-        impl<'db> rustc_type_ir::TypeVisitable<DbInterner<'db>> for $name {
+        impl<'db> rustc_type_ir::TypeVisitable<DbInterner<'db>> for $name<'db> {
             fn visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
                 &self,
                 visitor: &mut V,
@@ -117,14 +96,14 @@
         }
     };
     ($name:ident, $ty:ty, nofold) => {
-        #[salsa::interned(no_lifetime, constructor = new_, debug)]
+        #[salsa::interned(constructor = new_, debug)]
         pub struct $name {
             #[returns(ref)]
             inner_: smallvec::SmallVec<[$ty; 2]>,
         }
 
-        impl $name {
-            pub fn new_from_iter<'db>(
+        impl<'db> $name<'db> {
+            pub fn new_from_iter(
                 interner: DbInterner<'db>,
                 data: impl IntoIterator<Item = $ty>,
             ) -> Self {
@@ -140,7 +119,7 @@
             }
         }
 
-        impl rustc_type_ir::inherent::SliceLike for $name {
+        impl<'db> rustc_type_ir::inherent::SliceLike for $name<'db> {
             type Item = $ty;
 
             type IntoIter = <smallvec::SmallVec<[$ty; 2]> as IntoIterator>::IntoIter;
@@ -154,7 +133,7 @@
             }
         }
 
-        impl IntoIterator for $name {
+        impl<'db> IntoIterator for $name<'db> {
             type Item = $ty;
             type IntoIter = <Self as rustc_type_ir::inherent::SliceLike>::IntoIter;
 
@@ -163,7 +142,7 @@
             }
         }
 
-        impl Default for $name {
+        impl<'db> Default for $name<'db> {
             fn default() -> Self {
                 $name::new_from_iter(DbInterner::conjure(), [])
             }
@@ -631,12 +610,11 @@
         self,
         interner: DbInterner<'db>,
     ) -> Option<EarlyBinder<DbInterner<'db>, Ty<'db>>> {
-        let db = interner.db();
         let hir_def::AdtId::StructId(struct_id) = self.inner().id else {
             return None;
         };
         let id: VariantId = struct_id.into();
-        let field_types = interner.db().field_types_ns(id);
+        let field_types = interner.db().field_types(id);
 
         field_types.iter().last().map(|f| *f.1)
     }
@@ -647,23 +625,10 @@
     ) -> EarlyBinder<DbInterner<'db>, impl IntoIterator<Item = Ty<'db>>> {
         let db = interner.db();
         // FIXME: this is disabled just to match the behavior with chalk right now
-        let field_tys = |id: VariantId| {
-            let variant_data = id.fields(db);
-            let fields = if variant_data.fields().is_empty() {
-                vec![]
-            } else {
-                let field_types = db.field_types_ns(id);
-                variant_data
-                    .fields()
-                    .iter()
-                    .map(|(idx, _)| {
-                        let ty = field_types[idx];
-                        ty.skip_binder()
-                    })
-                    .collect()
-            };
+        let _field_tys = |id: VariantId| {
+            db.field_types(id).iter().map(|(_, ty)| ty.skip_binder()).collect::<Vec<_>>()
         };
-        let field_tys = |id: VariantId| vec![];
+        let field_tys = |_id: VariantId| vec![];
         let tys: Vec<_> = match self.inner().id {
             hir_def::AdtId::StructId(id) => field_tys(id.into()),
             hir_def::AdtId::UnionId(id) => field_tys(id.into()),
@@ -696,7 +661,7 @@
 
     fn destructor(
         self,
-        interner: DbInterner<'db>,
+        _interner: DbInterner<'db>,
     ) -> Option<rustc_type_ir::solve::AdtDestructorKind> {
         // FIXME(next-solver)
         None
@@ -742,7 +707,7 @@
         false
     }
 
-    fn feature_bound_holds_in_crate(self, symbol: ()) -> bool {
+    fn feature_bound_holds_in_crate(self, _symbol: ()) -> bool {
         false
     }
 }
@@ -884,10 +849,10 @@
     }};
 }
 
-impl<'db> rustc_type_ir::Interner for DbInterner<'db> {
+impl<'db> Interner for DbInterner<'db> {
     type DefId = SolverDefId;
     type LocalDefId = SolverDefId;
-    type LocalDefIds = SolverDefIds;
+    type LocalDefIds = SolverDefIds<'db>;
     type TraitId = TraitIdWrapper;
     type ForeignId = TypeAliasIdWrapper;
     type FunctionId = CallableIdWrapper;
@@ -904,16 +869,16 @@
 
     type Term = Term<'db>;
 
-    type BoundVarKinds = BoundVarKinds;
+    type BoundVarKinds = BoundVarKinds<'db>;
     type BoundVarKind = BoundVarKind;
 
     type PredefinedOpaques = PredefinedOpaques<'db>;
 
     fn mk_predefined_opaques_in_body(
         self,
-        data: rustc_type_ir::solve::PredefinedOpaquesData<Self>,
+        data: &[(OpaqueTypeKey<'db>, Self::Ty)],
     ) -> Self::PredefinedOpaques {
-        PredefinedOpaques::new(self, data)
+        PredefinedOpaques::new_from_iter(self, data.iter().cloned())
     }
 
     type CanonicalVarKinds = CanonicalVars<'db>;
@@ -977,7 +942,7 @@
 
     type GenericsOf = Generics;
 
-    type VariancesOf = VariancesOf;
+    type VariancesOf = VariancesOf<'db>;
 
     type AdtDef = AdtDef;
 
@@ -1002,7 +967,7 @@
     fn mk_tracked<T: fmt::Debug + Clone>(
         self,
         data: T,
-        dep_node: Self::DepNodeIndex,
+        _dep_node: Self::DepNodeIndex,
     ) -> Self::Tracked<T> {
         Tracked(data)
     }
@@ -1024,15 +989,15 @@
 
     fn canonical_param_env_cache_get_or_insert<R>(
         self,
-        param_env: Self::ParamEnv,
+        _param_env: Self::ParamEnv,
         f: impl FnOnce() -> rustc_type_ir::CanonicalParamEnvCacheEntry<Self>,
         from_entry: impl FnOnce(&rustc_type_ir::CanonicalParamEnvCacheEntry<Self>) -> R,
     ) -> R {
         from_entry(&f())
     }
 
-    fn evaluation_is_concurrent(&self) -> bool {
-        false
+    fn assert_evaluation_is_concurrent(&self) {
+        panic!("evaluation shouldn't be concurrent yet")
     }
 
     fn expand_abstract_consts<T: rustc_type_ir::TypeFoldable<Self>>(self, _: T) -> T {
@@ -1045,10 +1010,9 @@
 
     fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf {
         let generic_def = match def_id {
-            SolverDefId::FunctionId(def_id) => def_id.into(),
-            SolverDefId::AdtId(def_id) => def_id.into(),
-            SolverDefId::Ctor(Ctor::Struct(def_id)) => def_id.into(),
-            SolverDefId::Ctor(Ctor::Enum(def_id)) => def_id.loc(self.db).parent.into(),
+            SolverDefId::Ctor(Ctor::Enum(def_id)) | SolverDefId::EnumVariantId(def_id) => {
+                def_id.loc(self.db).parent.into()
+            }
             SolverDefId::InternedOpaqueTyId(_def_id) => {
                 // FIXME(next-solver): track variances
                 //
@@ -1059,17 +1023,20 @@
                     (0..self.generics_of(def_id).count()).map(|_| Variance::Invariant),
                 );
             }
-            _ => return VariancesOf::new_from_iter(self, []),
+            SolverDefId::Ctor(Ctor::Struct(def_id)) => def_id.into(),
+            SolverDefId::AdtId(def_id) => def_id.into(),
+            SolverDefId::FunctionId(def_id) => def_id.into(),
+            SolverDefId::ConstId(_)
+            | SolverDefId::StaticId(_)
+            | SolverDefId::TraitId(_)
+            | SolverDefId::TypeAliasId(_)
+            | SolverDefId::ImplId(_)
+            | SolverDefId::InternedClosureId(_)
+            | SolverDefId::InternedCoroutineId(_) => {
+                return VariancesOf::new_from_iter(self, []);
+            }
         };
-        VariancesOf::new_from_iter(
-            self,
-            self.db()
-                .variances_of(generic_def)
-                .as_deref()
-                .unwrap_or_default()
-                .iter()
-                .map(|v| v.to_nextsolver(self)),
-        )
+        self.db.variances_of(generic_def)
     }
 
     fn type_of(self, def_id: Self::DefId) -> EarlyBinder<Self, Self::Ty> {
@@ -1160,17 +1127,17 @@
         (TraitRef::new_from_args(self, trait_def_id.try_into().unwrap(), trait_args), alias_args)
     }
 
-    fn check_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs) -> bool {
+    fn check_args_compatible(self, _def_id: Self::DefId, _args: Self::GenericArgs) -> bool {
         // FIXME
         true
     }
 
-    fn debug_assert_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs) {}
+    fn debug_assert_args_compatible(self, _def_id: Self::DefId, _args: Self::GenericArgs) {}
 
     fn debug_assert_existential_args_compatible(
         self,
-        def_id: Self::DefId,
-        args: Self::GenericArgs,
+        _def_id: Self::DefId,
+        _args: Self::GenericArgs,
     ) {
     }
 
@@ -1211,6 +1178,7 @@
             | SolverDefId::AdtId(_)
             | SolverDefId::TraitId(_)
             | SolverDefId::ImplId(_)
+            | SolverDefId::EnumVariantId(..)
             | SolverDefId::Ctor(..)
             | SolverDefId::InternedOpaqueTyId(..) => panic!(),
         };
@@ -1238,11 +1206,27 @@
     }
 
     fn coroutine_movability(self, def_id: Self::CoroutineId) -> rustc_ast_ir::Movability {
-        unimplemented!()
+        // FIXME: Make this a query? I don't believe this can be accessed from bodies other than
+        // the current infer query, except with revealed opaques - is it rare enough to not matter?
+        let InternedCoroutine(owner, expr_id) = def_id.0.loc(self.db);
+        let body = self.db.body(owner);
+        let expr = &body[expr_id];
+        match *expr {
+            hir_def::hir::Expr::Closure { closure_kind, .. } => match closure_kind {
+                hir_def::hir::ClosureKind::Coroutine(movability) => match movability {
+                    hir_def::hir::Movability::Static => rustc_ast_ir::Movability::Static,
+                    hir_def::hir::Movability::Movable => rustc_ast_ir::Movability::Movable,
+                },
+                hir_def::hir::ClosureKind::Async => rustc_ast_ir::Movability::Static,
+                _ => panic!("unexpected expression for a coroutine: {expr:?}"),
+            },
+            hir_def::hir::Expr::Async { .. } => rustc_ast_ir::Movability::Static,
+            _ => panic!("unexpected expression for a coroutine: {expr:?}"),
+        }
     }
 
-    fn coroutine_for_closure(self, def_id: Self::CoroutineId) -> Self::CoroutineId {
-        unimplemented!()
+    fn coroutine_for_closure(self, def_id: Self::CoroutineClosureId) -> Self::CoroutineId {
+        def_id
     }
 
     fn generics_require_sized_self(self, def_id: Self::DefId) -> bool {
@@ -1319,7 +1303,7 @@
         self,
         def_id: Self::DefId,
     ) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> {
-        let predicates = self.db().generic_predicates_ns(def_id.try_into().unwrap());
+        let predicates = self.db().generic_predicates(def_id.try_into().unwrap());
         let predicates: Vec<_> = predicates.iter().cloned().collect();
         EarlyBinder::bind(predicates.into_iter())
     }
@@ -1346,7 +1330,7 @@
 
         let predicates: Vec<(Clause<'db>, Span)> = self
             .db()
-            .generic_predicates_ns(def_id.0.into())
+            .generic_predicates(def_id.0.into())
             .iter()
             .filter(|p| match p.kind().skip_binder() {
                 // rustc has the following assertion:
@@ -1380,7 +1364,7 @@
 
         let predicates: Vec<(Clause<'db>, Span)> = self
             .db()
-            .generic_predicates_ns(def_id.try_into().unwrap())
+            .generic_predicates(def_id.try_into().unwrap())
             .iter()
             .filter(|p| match p.kind().skip_binder() {
                 rustc_type_ir::ClauseKind::Trait(it) => is_self_or_assoc(it.self_ty()),
@@ -1418,9 +1402,10 @@
         })
     }
 
+    #[expect(unreachable_code)]
     fn const_conditions(
         self,
-        def_id: Self::DefId,
+        _def_id: Self::DefId,
     ) -> EarlyBinder<
         Self,
         impl IntoIterator<Item = rustc_type_ir::Binder<Self, rustc_type_ir::TraitRef<Self>>>,
@@ -1428,7 +1413,7 @@
         EarlyBinder::bind([unimplemented!()])
     }
 
-    fn has_target_features(self, def_id: Self::FunctionId) -> bool {
+    fn has_target_features(self, _def_id: Self::FunctionId) -> bool {
         false
     }
 
@@ -1459,7 +1444,7 @@
             hir_def::lang_item::LangItemTarget::Union(union_id) => union_id.into(),
             hir_def::lang_item::LangItemTarget::TypeAlias(type_alias_id) => type_alias_id.into(),
             hir_def::lang_item::LangItemTarget::Trait(trait_id) => trait_id.into(),
-            hir_def::lang_item::LangItemTarget::EnumVariant(enum_variant_id) => unimplemented!(),
+            hir_def::lang_item::LangItemTarget::EnumVariant(_) => unimplemented!(),
         }
     }
 
@@ -1549,7 +1534,6 @@
             CoroutineReturn,
             CoroutineYield,
             FutureOutput,
-            AsyncFnOnceOutput,
             CallRefFuture,
             CallOnceFuture,
             AsyncFnOnceOutput,
@@ -1593,7 +1577,6 @@
             AsyncFnMut,
             AsyncFnOnce,
             AsyncFnOnceOutput,
-            AsyncFnOnceOutput,
         )
     }
 
@@ -1633,7 +1616,7 @@
         };
 
         if fps.is_empty() {
-            for_trait_impls(
+            _ = for_trait_impls(
                 self.db(),
                 self.krate.expect("Must have self.krate"),
                 self.block,
@@ -1655,7 +1638,7 @@
                 },
             );
         } else {
-            for_trait_impls(
+            _ = for_trait_impls(
                 self.db(),
                 self.krate.expect("Must have self.krate"),
                 self.block,
@@ -1695,7 +1678,7 @@
         }
     }
 
-    fn has_item_definition(self, def_id: Self::DefId) -> bool {
+    fn has_item_definition(self, _def_id: Self::DefId) -> bool {
         // FIXME(next-solver): should check if the associated item has a value.
         true
     }
@@ -1743,13 +1726,13 @@
         trait_data.flags.contains(TraitFlags::FUNDAMENTAL)
     }
 
-    fn trait_may_be_implemented_via_object(self, trait_def_id: Self::TraitId) -> bool {
+    fn trait_may_be_implemented_via_object(self, _trait_def_id: Self::TraitId) -> bool {
         // FIXME(next-solver): should check the `TraitFlags` for
         // the `#[rustc_do_not_implement_via_object]` flag
         true
     }
 
-    fn is_impl_trait_in_trait(self, def_id: Self::DefId) -> bool {
+    fn is_impl_trait_in_trait(self, _def_id: Self::DefId) -> bool {
         // FIXME(next-solver)
         false
     }
@@ -1758,23 +1741,39 @@
         panic!("Bug encountered in next-trait-solver: {}", msg.to_string())
     }
 
-    fn is_general_coroutine(self, coroutine_def_id: Self::CoroutineId) -> bool {
-        // FIXME(next-solver)
-        true
+    fn is_general_coroutine(self, def_id: Self::CoroutineId) -> bool {
+        // FIXME: Make this a query? I don't believe this can be accessed from bodies other than
+        // the current infer query, except with revealed opaques - is it rare enough to not matter?
+        let InternedCoroutine(owner, expr_id) = def_id.0.loc(self.db);
+        let body = self.db.body(owner);
+        matches!(
+            body[expr_id],
+            hir_def::hir::Expr::Closure {
+                closure_kind: hir_def::hir::ClosureKind::Coroutine(_),
+                ..
+            }
+        )
     }
 
-    fn coroutine_is_async(self, coroutine_def_id: Self::CoroutineId) -> bool {
-        // FIXME(next-solver)
-        true
+    fn coroutine_is_async(self, def_id: Self::CoroutineId) -> bool {
+        // FIXME: Make this a query? I don't believe this can be accessed from bodies other than
+        // the current infer query, except with revealed opaques - is it rare enough to not matter?
+        let InternedCoroutine(owner, expr_id) = def_id.0.loc(self.db);
+        let body = self.db.body(owner);
+        matches!(
+            body[expr_id],
+            hir_def::hir::Expr::Closure { closure_kind: hir_def::hir::ClosureKind::Async, .. }
+                | hir_def::hir::Expr::Async { .. }
+        )
     }
 
-    fn coroutine_is_gen(self, coroutine_def_id: Self::CoroutineId) -> bool {
-        // FIXME(next-solver)
+    fn coroutine_is_gen(self, _coroutine_def_id: Self::CoroutineId) -> bool {
+        // We don't handle gen coroutines yet.
         false
     }
 
-    fn coroutine_is_async_gen(self, coroutine_def_id: Self::CoroutineId) -> bool {
-        // FIXME(next-solver)
+    fn coroutine_is_async_gen(self, _coroutine_def_id: Self::CoroutineId) -> bool {
+        // We don't handle gen coroutines yet.
         false
     }
 
@@ -1801,7 +1800,7 @@
             return UnsizingParams(DenseBitSet::new_empty(num_params));
         };
 
-        let field_types = self.db().field_types_ns(variant.id());
+        let field_types = self.db().field_types(variant.id());
         let mut unsizing_params = DenseBitSet::new_empty(num_params);
         let ty = field_types[tail_field.0];
         for arg in ty.instantiate_identity().walk() {
@@ -1867,19 +1866,19 @@
         Binder::bind_with_vars(inner, bound_vars)
     }
 
-    fn opaque_types_defined_by(self, defining_anchor: Self::LocalDefId) -> Self::LocalDefIds {
+    fn opaque_types_defined_by(self, _defining_anchor: Self::LocalDefId) -> Self::LocalDefIds {
         // FIXME(next-solver)
         SolverDefIds::new_from_iter(self, [])
     }
 
-    fn alias_has_const_conditions(self, def_id: Self::DefId) -> bool {
+    fn alias_has_const_conditions(self, _def_id: Self::DefId) -> bool {
         // FIXME(next-solver)
         false
     }
 
     fn explicit_implied_const_bounds(
         self,
-        def_id: Self::DefId,
+        _def_id: Self::DefId,
     ) -> EarlyBinder<
         Self,
         impl IntoIterator<Item = rustc_type_ir::Binder<Self, rustc_type_ir::TraitRef<Self>>>,
@@ -1896,14 +1895,14 @@
         self.db().function_signature(id).flags.contains(FnFlags::CONST)
     }
 
-    fn impl_is_const(self, def_id: Self::ImplId) -> bool {
+    fn impl_is_const(self, _def_id: Self::ImplId) -> bool {
         false
     }
 
     fn opt_alias_variances(
         self,
-        kind: impl Into<rustc_type_ir::AliasTermKind>,
-        def_id: Self::DefId,
+        _kind: impl Into<rustc_type_ir::AliasTermKind>,
+        _def_id: Self::DefId,
     ) -> Option<Self::VariancesOf> {
         None
     }
@@ -1915,10 +1914,9 @@
                 match impl_trait_id {
                     crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => {
                         let infer = self.db().infer(func.into());
-                        EarlyBinder::bind(infer.type_of_rpit[idx.to_nextsolver(self)])
+                        EarlyBinder::bind(infer.type_of_rpit[idx])
                     }
-                    crate::ImplTraitId::TypeAliasImplTrait(..)
-                    | crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => {
+                    crate::ImplTraitId::TypeAliasImplTrait(..) => {
                         // FIXME(next-solver)
                         EarlyBinder::bind(Ty::new_error(self, ErrorGuaranteed))
                     }
@@ -1930,11 +1928,13 @@
 
     fn coroutine_hidden_types(
         self,
-        def_id: Self::CoroutineId,
-    ) -> EarlyBinder<Self, rustc_type_ir::Binder<Self, rustc_type_ir::CoroutineWitnessTypes<Self>>>
-    {
-        // FIXME(next-solver)
-        unimplemented!()
+        _def_id: Self::CoroutineId,
+    ) -> EarlyBinder<Self, Binder<'db, CoroutineWitnessTypes<Self>>> {
+        // FIXME: Actually implement this.
+        EarlyBinder::bind(Binder::dummy(CoroutineWitnessTypes {
+            types: Tys::default(),
+            assumptions: RegionAssumptions::default(),
+        }))
     }
 
     fn is_default_trait(self, def_id: Self::TraitId) -> bool {
@@ -1949,7 +1949,7 @@
         self.db().trait_signature(trait_.0).flags.contains(TraitFlags::UNSAFE)
     }
 
-    fn impl_self_is_guaranteed_unsized(self, def_id: Self::ImplId) -> bool {
+    fn impl_self_is_guaranteed_unsized(self, _def_id: Self::ImplId) -> bool {
         false
     }
 
@@ -1958,7 +1958,11 @@
         specializing_impl_def_id: Self::ImplId,
         parent_impl_def_id: Self::ImplId,
     ) -> bool {
-        false
+        crate::specialization::specializes(
+            self.db,
+            specializing_impl_def_id.0,
+            parent_impl_def_id.0,
+        )
     }
 
     fn next_trait_solver_globally(self) -> bool {
@@ -1967,10 +1971,9 @@
 
     fn opaque_types_and_coroutines_defined_by(
         self,
-        defining_anchor: Self::LocalDefId,
+        _defining_anchor: Self::LocalDefId,
     ) -> Self::LocalDefIds {
-        // FIXME(next-solver)
-        unimplemented!()
+        Default::default()
     }
 
     type Probe = rustc_type_ir::solve::inspect::Probe<DbInterner<'db>>;
@@ -1986,6 +1989,13 @@
             Self,
         >(self, canonical_goal)
     }
+
+    fn is_sizedness_trait(self, def_id: Self::TraitId) -> bool {
+        matches!(
+            self.as_trait_lang_item(def_id),
+            Some(SolverTraitLangItem::Sized | SolverTraitLangItem::MetaSized)
+        )
+    }
 }
 
 impl<'db> DbInterner<'db> {
@@ -2273,4 +2283,12 @@
             })
         })
     }
+
+    /// Clears the thread-local trait solver cache.
+    ///
+    /// Should be called before getting memory usage estimations, as the solver cache
+    /// is per-revision and usually should be excluded from estimations.
+    pub fn clear_tls_solver_cache() {
+        GLOBAL_CACHE.with_borrow_mut(|handle| *handle = None);
+    }
 }
diff --git a/crates/hir-ty/src/next_solver/ir_print.rs b/crates/hir-ty/src/next_solver/ir_print.rs
index 69afcf5..dab0fe9 100644
--- a/crates/hir-ty/src/next_solver/ir_print.rs
+++ b/crates/hir-ty/src/next_solver/ir_print.rs
@@ -5,8 +5,6 @@
 use rustc_type_ir::inherent::SliceLike;
 use rustc_type_ir::{self as ty, ir_print::IrPrint};
 
-use crate::db::HirDatabase;
-
 use super::SolverDefId;
 use super::interner::DbInterner;
 
diff --git a/crates/hir-ty/src/next_solver/mapping.rs b/crates/hir-ty/src/next_solver/mapping.rs
deleted file mode 100644
index 1a5982c..0000000
--- a/crates/hir-ty/src/next_solver/mapping.rs
+++ /dev/null
@@ -1,1779 +0,0 @@
-//! Things useful for mapping to/from Chalk and next-trait-solver types.
-
-use base_db::Crate;
-use chalk_ir::{
-    CanonicalVarKind, CanonicalVarKinds, FnPointer, InferenceVar, Substitution, TyVariableKind,
-    WellFormed, cast::Cast, fold::Shift, interner::HasInterner,
-};
-use hir_def::{
-    CallableDefId, ConstParamId, FunctionId, GeneralConstId, LifetimeParamId, TypeAliasId,
-    TypeOrConstParamId, TypeParamId, signatures::TraitFlags,
-};
-use hir_def::{GenericDefId, GenericParamId};
-use intern::sym;
-use rustc_type_ir::{
-    AliasTerm, BoundVar, DebruijnIndex, ExistentialProjection, ExistentialTraitRef, Interner as _,
-    OutlivesPredicate, ProjectionPredicate, TypeFoldable, TypeSuperFoldable, TypeVisitable,
-    TypeVisitableExt, UniverseIndex, elaborate,
-    inherent::{BoundVarLike, Clause as _, IntoKind, PlaceholderLike, SliceLike, Ty as _},
-    shift_vars,
-    solve::Goal,
-};
-use salsa::plumbing::FromId;
-use salsa::{Id, plumbing::AsId};
-
-use crate::next_solver::BoundConst;
-use crate::{
-    ConstScalar, ImplTraitId, Interner, MemoryMap,
-    db::{
-        HirDatabase, InternedClosureId, InternedCoroutineId, InternedLifetimeParamId,
-        InternedOpaqueTyId, InternedTypeOrConstParamId,
-    },
-    from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
-    mapping::ToChalk,
-    next_solver::{
-        Binder, ClauseKind, ConstBytes, TraitPredicate, UnevaluatedConst,
-        interner::{AdtDef, BoundVarKind, BoundVarKinds, DbInterner},
-    },
-    to_assoc_type_id, to_chalk_trait_id, to_foreign_def_id,
-};
-use crate::{
-    from_placeholder_idx, lt_from_placeholder_idx, lt_to_placeholder_idx, to_placeholder_idx,
-};
-
-use super::{
-    BoundExistentialPredicate, BoundExistentialPredicates, BoundRegion, BoundRegionKind, BoundTy,
-    BoundTyKind, Canonical, CanonicalVars, Clause, Clauses, Const, Ctor, EarlyParamRegion,
-    ErrorGuaranteed, ExistentialPredicate, GenericArg, GenericArgs, ParamConst, ParamEnv, ParamTy,
-    Placeholder, PlaceholderConst, PlaceholderRegion, PlaceholderTy, Predicate, PredicateKind,
-    Region, SolverDefId, SubtypePredicate, Term, TraitRef, Ty, Tys, ValueConst, VariancesOf,
-};
-
-// FIXME: This should urgently go (as soon as we finish the migration off Chalk, that is).
-pub fn convert_binder_to_early_binder<'db, T: rustc_type_ir::TypeFoldable<DbInterner<'db>>>(
-    interner: DbInterner<'db>,
-    def: GenericDefId,
-    binder: rustc_type_ir::Binder<DbInterner<'db>, T>,
-) -> rustc_type_ir::EarlyBinder<DbInterner<'db>, T> {
-    let mut folder = BinderToEarlyBinder {
-        interner,
-        debruijn: rustc_type_ir::DebruijnIndex::ZERO,
-        params: crate::generics::generics(interner.db, def).iter_id().collect(),
-    };
-    rustc_type_ir::EarlyBinder::bind(binder.skip_binder().fold_with(&mut folder))
-}
-
-struct BinderToEarlyBinder<'db> {
-    interner: DbInterner<'db>,
-    debruijn: rustc_type_ir::DebruijnIndex,
-    params: Vec<GenericParamId>,
-}
-
-impl<'db> rustc_type_ir::TypeFolder<DbInterner<'db>> for BinderToEarlyBinder<'db> {
-    fn cx(&self) -> DbInterner<'db> {
-        self.interner
-    }
-
-    fn fold_binder<T>(
-        &mut self,
-        t: rustc_type_ir::Binder<DbInterner<'db>, T>,
-    ) -> rustc_type_ir::Binder<DbInterner<'db>, T>
-    where
-        T: TypeFoldable<DbInterner<'db>>,
-    {
-        self.debruijn.shift_in(1);
-        let result = t.super_fold_with(self);
-        self.debruijn.shift_out(1);
-        result
-    }
-
-    fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> {
-        match t.kind() {
-            rustc_type_ir::TyKind::Bound(debruijn, bound_ty) if self.debruijn == debruijn => {
-                let var: rustc_type_ir::BoundVar = bound_ty.var();
-                let GenericParamId::TypeParamId(id) = self.params[bound_ty.var.as_usize()] else {
-                    unreachable!()
-                };
-                Ty::new(
-                    self.cx(),
-                    rustc_type_ir::TyKind::Param(ParamTy { index: var.as_u32(), id }),
-                )
-            }
-            _ => t.super_fold_with(self),
-        }
-    }
-
-    fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
-        match r.kind() {
-            rustc_type_ir::ReBound(debruijn, bound_region) if self.debruijn == debruijn => {
-                let var: rustc_type_ir::BoundVar = bound_region.var();
-                let GenericParamId::LifetimeParamId(id) = self.params[bound_region.var.as_usize()]
-                else {
-                    unreachable!()
-                };
-                Region::new(
-                    self.cx(),
-                    rustc_type_ir::RegionKind::ReEarlyParam(EarlyParamRegion {
-                        index: var.as_u32(),
-                        id,
-                    }),
-                )
-            }
-            _ => r,
-        }
-    }
-
-    fn fold_const(&mut self, c: Const<'db>) -> Const<'db> {
-        match c.kind() {
-            rustc_type_ir::ConstKind::Bound(debruijn, var) if self.debruijn == debruijn => {
-                let GenericParamId::ConstParamId(id) = self.params[var.var.as_usize()] else {
-                    unreachable!()
-                };
-                Const::new(
-                    self.cx(),
-                    rustc_type_ir::ConstKind::Param(ParamConst { index: var.var.as_u32(), id }),
-                )
-            }
-            _ => c.super_fold_with(self),
-        }
-    }
-}
-
-pub trait ChalkToNextSolver<'db, Out> {
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> Out;
-}
-
-impl<'db, A, OutA, B, OutB> ChalkToNextSolver<'db, (OutA, OutB)> for (A, B)
-where
-    A: ChalkToNextSolver<'db, OutA>,
-    B: ChalkToNextSolver<'db, OutB>,
-{
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> (OutA, OutB) {
-        (self.0.to_nextsolver(interner), self.1.to_nextsolver(interner))
-    }
-}
-
-pub trait NextSolverToChalk<'db, Out> {
-    fn to_chalk(self, interner: DbInterner<'db>) -> Out;
-}
-
-impl<'db, T, Out> NextSolverToChalk<'db, Option<Out>> for Option<T>
-where
-    T: NextSolverToChalk<'db, Out>,
-{
-    fn to_chalk(self, interner: DbInterner<'db>) -> Option<Out> {
-        self.map(|it| it.to_chalk(interner))
-    }
-}
-
-impl NextSolverToChalk<'_, chalk_ir::Mutability> for rustc_ast_ir::Mutability {
-    fn to_chalk(self, interner: DbInterner<'_>) -> chalk_ir::Mutability {
-        match self {
-            rustc_ast_ir::Mutability::Not => chalk_ir::Mutability::Not,
-            rustc_ast_ir::Mutability::Mut => chalk_ir::Mutability::Mut,
-        }
-    }
-}
-
-impl NextSolverToChalk<'_, chalk_ir::Safety> for crate::next_solver::abi::Safety {
-    fn to_chalk(self, interner: DbInterner<'_>) -> chalk_ir::Safety {
-        match self {
-            crate::next_solver::abi::Safety::Unsafe => chalk_ir::Safety::Unsafe,
-            crate::next_solver::abi::Safety::Safe => chalk_ir::Safety::Safe,
-        }
-    }
-}
-
-impl<'db> ChalkToNextSolver<'db, Ty<'db>> for chalk_ir::Ty<Interner> {
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> Ty<'db> {
-        Ty::new(
-            interner,
-            match self.kind(Interner) {
-                chalk_ir::TyKind::Adt(adt_id, substitution) => {
-                    let def = AdtDef::new(adt_id.0, interner);
-                    let args = substitution.to_nextsolver(interner);
-                    rustc_type_ir::TyKind::Adt(def, args)
-                }
-                chalk_ir::TyKind::AssociatedType(assoc_type_id, substitution) => {
-                    let def_id = SolverDefId::TypeAliasId(from_assoc_type_id(*assoc_type_id));
-                    let args: GenericArgs<'db> = substitution.to_nextsolver(interner);
-                    let alias_ty = rustc_type_ir::AliasTy::new(interner, def_id, args.iter());
-                    rustc_type_ir::TyKind::Alias(rustc_type_ir::AliasTyKind::Projection, alias_ty)
-                }
-                chalk_ir::TyKind::Scalar(scalar) => match scalar {
-                    chalk_ir::Scalar::Bool => rustc_type_ir::TyKind::Bool,
-                    chalk_ir::Scalar::Char => rustc_type_ir::TyKind::Char,
-                    chalk_ir::Scalar::Int(chalk_ir::IntTy::Isize) => {
-                        rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::Isize)
-                    }
-                    chalk_ir::Scalar::Int(chalk_ir::IntTy::I8) => {
-                        rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I8)
-                    }
-                    chalk_ir::Scalar::Int(chalk_ir::IntTy::I16) => {
-                        rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I16)
-                    }
-                    chalk_ir::Scalar::Int(chalk_ir::IntTy::I32) => {
-                        rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I32)
-                    }
-                    chalk_ir::Scalar::Int(chalk_ir::IntTy::I64) => {
-                        rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I64)
-                    }
-                    chalk_ir::Scalar::Int(chalk_ir::IntTy::I128) => {
-                        rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I128)
-                    }
-                    chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize) => {
-                        rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::Usize)
-                    }
-                    chalk_ir::Scalar::Uint(chalk_ir::UintTy::U8) => {
-                        rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U8)
-                    }
-                    chalk_ir::Scalar::Uint(chalk_ir::UintTy::U16) => {
-                        rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U16)
-                    }
-                    chalk_ir::Scalar::Uint(chalk_ir::UintTy::U32) => {
-                        rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U32)
-                    }
-                    chalk_ir::Scalar::Uint(chalk_ir::UintTy::U64) => {
-                        rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U64)
-                    }
-                    chalk_ir::Scalar::Uint(chalk_ir::UintTy::U128) => {
-                        rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U128)
-                    }
-                    chalk_ir::Scalar::Float(chalk_ir::FloatTy::F16) => {
-                        rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F16)
-                    }
-                    chalk_ir::Scalar::Float(chalk_ir::FloatTy::F32) => {
-                        rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F32)
-                    }
-                    chalk_ir::Scalar::Float(chalk_ir::FloatTy::F64) => {
-                        rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F64)
-                    }
-                    chalk_ir::Scalar::Float(chalk_ir::FloatTy::F128) => {
-                        rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F128)
-                    }
-                },
-                chalk_ir::TyKind::Tuple(_, substitution) => {
-                    let args = substitution.to_nextsolver(interner);
-                    rustc_type_ir::TyKind::Tuple(args)
-                }
-                chalk_ir::TyKind::Array(ty, len) => rustc_type_ir::TyKind::Array(
-                    ty.to_nextsolver(interner),
-                    len.to_nextsolver(interner),
-                ),
-                chalk_ir::TyKind::Slice(ty) => {
-                    rustc_type_ir::TyKind::Slice(ty.to_nextsolver(interner))
-                }
-                chalk_ir::TyKind::Raw(mutability, ty) => rustc_type_ir::RawPtr(
-                    ty.to_nextsolver(interner),
-                    mutability.to_nextsolver(interner),
-                ),
-                chalk_ir::TyKind::Ref(mutability, lifetime, ty) => rustc_type_ir::TyKind::Ref(
-                    lifetime.to_nextsolver(interner),
-                    ty.to_nextsolver(interner),
-                    mutability.to_nextsolver(interner),
-                ),
-                chalk_ir::TyKind::OpaqueType(def_id, substitution) => {
-                    let id: InternedOpaqueTyId = (*def_id).into();
-                    let args: GenericArgs<'db> = substitution.to_nextsolver(interner);
-                    let alias_ty = rustc_type_ir::AliasTy::new(interner, id.into(), args);
-                    rustc_type_ir::TyKind::Alias(rustc_type_ir::AliasTyKind::Opaque, alias_ty)
-                }
-                chalk_ir::TyKind::FnDef(fn_def_id, substitution) => {
-                    let def_id = CallableDefId::from_chalk(interner.db(), *fn_def_id);
-                    rustc_type_ir::TyKind::FnDef(
-                        def_id.into(),
-                        substitution.to_nextsolver(interner),
-                    )
-                }
-                chalk_ir::TyKind::Str => rustc_type_ir::TyKind::Str,
-                chalk_ir::TyKind::Never => rustc_type_ir::TyKind::Never,
-                chalk_ir::TyKind::Closure(closure_id, substitution) => {
-                    let id: InternedClosureId = (*closure_id).into();
-                    rustc_type_ir::TyKind::Closure(id.into(), substitution.to_nextsolver(interner))
-                }
-                chalk_ir::TyKind::Coroutine(coroutine_id, substitution) => {
-                    let id: InternedCoroutineId = (*coroutine_id).into();
-                    rustc_type_ir::TyKind::Coroutine(
-                        id.into(),
-                        substitution.to_nextsolver(interner),
-                    )
-                }
-                chalk_ir::TyKind::CoroutineWitness(coroutine_id, substitution) => {
-                    let id: InternedCoroutineId = (*coroutine_id).into();
-                    rustc_type_ir::TyKind::CoroutineWitness(
-                        id.into(),
-                        substitution.to_nextsolver(interner),
-                    )
-                }
-                chalk_ir::TyKind::Foreign(foreign_def_id) => rustc_type_ir::TyKind::Foreign(
-                    crate::from_foreign_def_id(*foreign_def_id).into(),
-                ),
-                chalk_ir::TyKind::Error => rustc_type_ir::TyKind::Error(ErrorGuaranteed),
-                chalk_ir::TyKind::Dyn(dyn_ty) => {
-                    // exists<type> { for<...> ^1.0: ... }
-                    let bounds = BoundExistentialPredicates::new_from_iter(
-                        interner,
-                        dyn_ty.bounds.skip_binders().iter(Interner).filter_map(|pred| {
-                            // for<...> ^1.0: ...
-                            let (val, binders) = pred.clone().into_value_and_skipped_binders();
-                            let bound_vars = binders.to_nextsolver(interner);
-                            let clause = match val {
-                                chalk_ir::WhereClause::Implemented(trait_ref) => {
-                                    let trait_id = from_chalk_trait_id(trait_ref.trait_id);
-                                    if interner
-                                        .db()
-                                        .trait_signature(trait_id)
-                                        .flags
-                                        .contains(TraitFlags::AUTO)
-                                    {
-                                        ExistentialPredicate::AutoTrait(trait_id.into())
-                                    } else {
-                                        let args = GenericArgs::new_from_iter(
-                                            interner,
-                                            trait_ref
-                                                .substitution
-                                                .iter(Interner)
-                                                .skip(1)
-                                                .map(|a| a.clone().shifted_out(Interner).unwrap())
-                                                .map(|a| a.to_nextsolver(interner)),
-                                        );
-                                        let trait_ref = ExistentialTraitRef::new_from_args(
-                                            interner, trait_id.into(), args,
-                                        );
-                                        ExistentialPredicate::Trait(trait_ref)
-                                    }
-                                }
-                                chalk_ir::WhereClause::AliasEq(alias_eq) => {
-                                    let (def_id, args) = match &alias_eq.alias {
-                                        chalk_ir::AliasTy::Projection(projection) => {
-                                            let id =
-                                                from_assoc_type_id(projection.associated_ty_id);
-                                            let def_id = SolverDefId::TypeAliasId(id);
-                                            let generics = interner.generics_of(def_id);
-                                            let parent_len = generics.parent_count;
-                                            let substs = projection.substitution.iter(Interner).skip(1);
-
-                                            let args = GenericArgs::new_from_iter(
-                                                interner,
-                                                substs
-                                                    .map(|a| {
-                                                        a.clone().shifted_out(Interner).unwrap()
-                                                    })
-                                                    .map(|a| a.to_nextsolver(interner)),
-                                            );
-                                            (def_id, args)
-                                        }
-                                        chalk_ir::AliasTy::Opaque(opaque_ty) => {
-                                            panic!("Invalid ExistentialPredicate (opaques can't be named).");
-                                        }
-                                    };
-                                    let term = alias_eq
-                                        .ty
-                                        .clone()
-                                        .shifted_out(Interner)
-                                        .unwrap()
-                                        .to_nextsolver(interner)
-                                        .into();
-                                    let projection = ExistentialProjection::new_from_args(
-                                        interner, def_id, args, term,
-                                    );
-                                    ExistentialPredicate::Projection(projection)
-                                }
-                                chalk_ir::WhereClause::LifetimeOutlives(lifetime_outlives) => {
-                                    return None;
-                                }
-                                chalk_ir::WhereClause::TypeOutlives(type_outlives) => return None,
-                            };
-
-                            Some(Binder::bind_with_vars(clause, bound_vars))
-                        }),
-                    );
-                    let region = dyn_ty.lifetime.to_nextsolver(interner);
-                    rustc_type_ir::TyKind::Dynamic(bounds, region)
-                }
-                chalk_ir::TyKind::Alias(alias_ty) => match alias_ty {
-                    chalk_ir::AliasTy::Projection(projection_ty) => {
-                        let def_id = SolverDefId::TypeAliasId(from_assoc_type_id(
-                            projection_ty.associated_ty_id,
-                        ));
-                        let alias_ty = rustc_type_ir::AliasTy::new_from_args(
-                            interner,
-                            def_id,
-                            projection_ty.substitution.to_nextsolver(interner),
-                        );
-                        rustc_type_ir::TyKind::Alias(
-                            rustc_type_ir::AliasTyKind::Projection,
-                            alias_ty,
-                        )
-                    }
-                    chalk_ir::AliasTy::Opaque(opaque_ty) => {
-                        let id: InternedOpaqueTyId = opaque_ty.opaque_ty_id.into();
-                        let def_id = SolverDefId::InternedOpaqueTyId(id);
-                        let alias_ty = rustc_type_ir::AliasTy::new_from_args(
-                            interner,
-                            def_id,
-                            opaque_ty.substitution.to_nextsolver(interner),
-                        );
-                        rustc_type_ir::TyKind::Alias(rustc_type_ir::AliasTyKind::Opaque, alias_ty)
-                    }
-                },
-                chalk_ir::TyKind::Function(fn_pointer) => {
-                    let sig_tys = fn_pointer.clone().into_binders(Interner).to_nextsolver(interner);
-                    let header = rustc_type_ir::FnHeader {
-                        abi: fn_pointer.sig.abi,
-                        c_variadic: fn_pointer.sig.variadic,
-                        safety: match fn_pointer.sig.safety {
-                            chalk_ir::Safety::Safe => super::abi::Safety::Safe,
-                            chalk_ir::Safety::Unsafe => super::abi::Safety::Unsafe,
-                        },
-                    };
-
-                    rustc_type_ir::TyKind::FnPtr(sig_tys, header)
-                }
-                // The schema here is quite confusing.
-                // The new solver, like rustc, uses `Param` and `EarlyBinder` for generic params. It uses `BoundVar`
-                // and `Placeholder` together with `Binder` for HRTB, which we mostly don't handle.
-                // Chalk uses `Placeholder` for generic params and `BoundVar` quite liberally, and this is quite a
-                // problem. `chalk_ir::TyKind::BoundVar` can represent either HRTB or generic params, depending on the
-                // context. When returned from signature queries, the outer `Binders` represent the generic params.
-                // But there are also inner `Binders` for HRTB.
-                // AFAIK there is no way to tell which of the meanings is relevant, so we just use `rustc_type_ir::Bound`
-                // here, and hope for the best. If you are working with new solver types, therefore, use the new solver
-                // lower queries.
-                // Hopefully sooner than later Chalk will be ripped from the codebase and we can avoid that problem.
-                // For details about the rustc setup, read: https://rustc-dev-guide.rust-lang.org/generic_parameters_summary.html
-                // and the following chapters.
-                chalk_ir::TyKind::Placeholder(placeholder_index) => {
-                    let (id, index) = from_placeholder_idx(interner.db, *placeholder_index);
-                    rustc_type_ir::TyKind::Param(ParamTy {
-                        id: TypeParamId::from_unchecked(id),
-                        index,
-                    })
-                }
-                chalk_ir::TyKind::BoundVar(bound_var) => rustc_type_ir::TyKind::Bound(
-                    bound_var.debruijn.to_nextsolver(interner),
-                    BoundTy {
-                        var: rustc_type_ir::BoundVar::from_usize(bound_var.index),
-                        kind: BoundTyKind::Anon,
-                    },
-                ),
-                chalk_ir::TyKind::InferenceVar(inference_var, ty_variable_kind) => {
-                    rustc_type_ir::TyKind::Infer(
-                        (*inference_var, *ty_variable_kind).to_nextsolver(interner),
-                    )
-                }
-            },
-        )
-    }
-}
-
-impl<'db> NextSolverToChalk<'db, chalk_ir::Ty<Interner>> for Ty<'db> {
-    fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Ty<Interner> {
-        convert_ty_for_result(interner, self)
-    }
-}
-
-impl<'db> ChalkToNextSolver<'db, Region<'db>> for chalk_ir::Lifetime<Interner> {
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> Region<'db> {
-        Region::new(
-            interner,
-            match self.data(Interner) {
-                chalk_ir::LifetimeData::BoundVar(bound_var) => rustc_type_ir::RegionKind::ReBound(
-                    bound_var.debruijn.to_nextsolver(interner),
-                    BoundRegion {
-                        var: rustc_type_ir::BoundVar::from_u32(bound_var.index as u32),
-                        kind: BoundRegionKind::Anon,
-                    },
-                ),
-                chalk_ir::LifetimeData::InferenceVar(inference_var) => {
-                    rustc_type_ir::RegionKind::ReVar(rustc_type_ir::RegionVid::from_u32(
-                        inference_var.index(),
-                    ))
-                }
-                chalk_ir::LifetimeData::Placeholder(placeholder_index) => {
-                    let (id, index) = lt_from_placeholder_idx(interner.db, *placeholder_index);
-                    rustc_type_ir::RegionKind::ReEarlyParam(EarlyParamRegion { id, index })
-                }
-                chalk_ir::LifetimeData::Static => rustc_type_ir::RegionKind::ReStatic,
-                chalk_ir::LifetimeData::Erased => rustc_type_ir::RegionKind::ReErased,
-                chalk_ir::LifetimeData::Phantom(_, _) => {
-                    unreachable!()
-                }
-                chalk_ir::LifetimeData::Error => {
-                    rustc_type_ir::RegionKind::ReError(ErrorGuaranteed)
-                }
-            },
-        )
-    }
-}
-
-impl<'db> NextSolverToChalk<'db, chalk_ir::Lifetime<Interner>> for Region<'db> {
-    fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Lifetime<Interner> {
-        convert_region_for_result(interner, self)
-    }
-}
-
-impl<'db> ChalkToNextSolver<'db, Const<'db>> for chalk_ir::Const<Interner> {
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> Const<'db> {
-        let data = self.data(Interner);
-        Const::new(
-            interner,
-            match &data.value {
-                chalk_ir::ConstValue::BoundVar(bound_var) => rustc_type_ir::ConstKind::Bound(
-                    bound_var.debruijn.to_nextsolver(interner),
-                    BoundConst { var: rustc_type_ir::BoundVar::from_usize(bound_var.index) },
-                ),
-                chalk_ir::ConstValue::InferenceVar(inference_var) => {
-                    rustc_type_ir::ConstKind::Infer(rustc_type_ir::InferConst::Var(
-                        rustc_type_ir::ConstVid::from_u32(inference_var.index()),
-                    ))
-                }
-                chalk_ir::ConstValue::Placeholder(placeholder_index) => {
-                    let (id, index) = from_placeholder_idx(interner.db, *placeholder_index);
-                    rustc_type_ir::ConstKind::Param(ParamConst {
-                        id: ConstParamId::from_unchecked(id),
-                        index,
-                    })
-                }
-                chalk_ir::ConstValue::Concrete(concrete_const) => match &concrete_const.interned {
-                    ConstScalar::Bytes(bytes, memory) => {
-                        rustc_type_ir::ConstKind::Value(ValueConst::new(
-                            data.ty.to_nextsolver(interner),
-                            ConstBytes { memory: bytes.clone(), memory_map: memory.clone() },
-                        ))
-                    }
-                    ConstScalar::UnevaluatedConst(c, subst) => {
-                        let def = match *c {
-                            GeneralConstId::ConstId(id) => SolverDefId::ConstId(id),
-                            GeneralConstId::StaticId(id) => SolverDefId::StaticId(id),
-                        };
-                        let args = subst.to_nextsolver(interner);
-                        rustc_type_ir::ConstKind::Unevaluated(UnevaluatedConst::new(def, args))
-                    }
-                    ConstScalar::Unknown => rustc_type_ir::ConstKind::Error(ErrorGuaranteed),
-                },
-            },
-        )
-    }
-}
-
-impl<'db> NextSolverToChalk<'db, chalk_ir::Const<Interner>> for Const<'db> {
-    fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Const<Interner> {
-        convert_const_for_result(interner, self)
-    }
-}
-
-impl<'db> ChalkToNextSolver<'db, rustc_type_ir::FnSigTys<DbInterner<'db>>>
-    for chalk_ir::FnSubst<Interner>
-{
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_type_ir::FnSigTys<DbInterner<'db>> {
-        rustc_type_ir::FnSigTys {
-            inputs_and_output: Tys::new_from_iter(
-                interner,
-                self.0.iter(Interner).map(|g| g.assert_ty_ref(Interner).to_nextsolver(interner)),
-            ),
-        }
-    }
-}
-
-impl<
-    'db,
-    U: TypeVisitable<DbInterner<'db>>,
-    T: Clone + ChalkToNextSolver<'db, U> + HasInterner<Interner = Interner>,
-> ChalkToNextSolver<'db, rustc_type_ir::Binder<DbInterner<'db>, U>> for chalk_ir::Binders<T>
-{
-    fn to_nextsolver(
-        &self,
-        interner: DbInterner<'db>,
-    ) -> rustc_type_ir::Binder<DbInterner<'db>, U> {
-        let (val, binders) = self.clone().into_value_and_skipped_binders();
-        rustc_type_ir::Binder::bind_with_vars(
-            val.to_nextsolver(interner),
-            binders.to_nextsolver(interner),
-        )
-    }
-}
-
-impl<'db, T: NextSolverToChalk<'db, U>, U: HasInterner<Interner = Interner>>
-    NextSolverToChalk<'db, chalk_ir::Binders<U>> for rustc_type_ir::Binder<DbInterner<'db>, T>
-{
-    fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Binders<U> {
-        chalk_ir::Binders::new(
-            self.bound_vars().to_chalk(interner),
-            self.skip_binder().to_chalk(interner),
-        )
-    }
-}
-
-impl<'db> ChalkToNextSolver<'db, BoundVarKinds> for chalk_ir::VariableKinds<Interner> {
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> BoundVarKinds {
-        BoundVarKinds::new_from_iter(
-            interner,
-            self.iter(Interner).map(|v| v.to_nextsolver(interner)),
-        )
-    }
-}
-
-impl<'db> NextSolverToChalk<'db, chalk_ir::VariableKinds<Interner>> for BoundVarKinds {
-    fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::VariableKinds<Interner> {
-        chalk_ir::VariableKinds::from_iter(Interner, self.iter().map(|v| v.to_chalk(interner)))
-    }
-}
-
-impl<'db> ChalkToNextSolver<'db, BoundVarKind> for chalk_ir::VariableKind<Interner> {
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> BoundVarKind {
-        match self {
-            chalk_ir::VariableKind::Ty(_ty_variable_kind) => BoundVarKind::Ty(BoundTyKind::Anon),
-            chalk_ir::VariableKind::Lifetime => BoundVarKind::Region(BoundRegionKind::Anon),
-            chalk_ir::VariableKind::Const(_ty) => BoundVarKind::Const,
-        }
-    }
-}
-
-impl<'db> NextSolverToChalk<'db, chalk_ir::VariableKind<Interner>> for BoundVarKind {
-    fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::VariableKind<Interner> {
-        match self {
-            BoundVarKind::Ty(_) => chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
-            BoundVarKind::Region(_) => chalk_ir::VariableKind::Lifetime,
-            BoundVarKind::Const => {
-                chalk_ir::VariableKind::Const(chalk_ir::TyKind::Error.intern(Interner))
-            }
-        }
-    }
-}
-
-impl<'db> ChalkToNextSolver<'db, GenericArg<'db>> for chalk_ir::GenericArg<Interner> {
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> GenericArg<'db> {
-        match self.data(Interner) {
-            chalk_ir::GenericArgData::Ty(ty) => ty.to_nextsolver(interner).into(),
-            chalk_ir::GenericArgData::Lifetime(lifetime) => lifetime.to_nextsolver(interner).into(),
-            chalk_ir::GenericArgData::Const(const_) => const_.to_nextsolver(interner).into(),
-        }
-    }
-}
-
-impl<'db> NextSolverToChalk<'db, crate::GenericArg> for GenericArg<'db> {
-    fn to_chalk(self, interner: DbInterner<'db>) -> crate::GenericArg {
-        match self {
-            GenericArg::Ty(ty) => ty.to_chalk(interner).cast(Interner),
-            GenericArg::Lifetime(region) => region.to_chalk(interner).cast(Interner),
-            GenericArg::Const(konst) => konst.to_chalk(interner).cast(Interner),
-        }
-    }
-}
-
-impl<'db> ChalkToNextSolver<'db, GenericArgs<'db>> for chalk_ir::Substitution<Interner> {
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> GenericArgs<'db> {
-        GenericArgs::new_from_iter(
-            interner,
-            self.iter(Interner).map(|arg| -> GenericArg<'db> { arg.to_nextsolver(interner) }),
-        )
-    }
-}
-
-impl<'db> ChalkToNextSolver<'db, crate::lower_nextsolver::ImplTraitIdx<'db>>
-    for crate::ImplTraitIdx
-{
-    fn to_nextsolver(
-        &self,
-        interner: DbInterner<'db>,
-    ) -> crate::lower_nextsolver::ImplTraitIdx<'db> {
-        crate::lower_nextsolver::ImplTraitIdx::from_raw(self.into_raw())
-    }
-}
-
-impl<'db> NextSolverToChalk<'db, chalk_ir::Substitution<Interner>> for GenericArgs<'db> {
-    fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Substitution<Interner> {
-        convert_args_for_result(interner, self.as_slice())
-    }
-}
-
-impl<'db> ChalkToNextSolver<'db, Tys<'db>> for chalk_ir::Substitution<Interner> {
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> Tys<'db> {
-        Tys::new_from_iter(
-            interner,
-            self.iter(Interner).map(|arg| -> Ty<'db> {
-                match arg.data(Interner) {
-                    chalk_ir::GenericArgData::Ty(ty) => ty.to_nextsolver(interner),
-                    chalk_ir::GenericArgData::Lifetime(_) => unreachable!(),
-                    chalk_ir::GenericArgData::Const(_) => unreachable!(),
-                }
-            }),
-        )
-    }
-}
-
-impl<'db> NextSolverToChalk<'db, crate::Substitution> for Tys<'db> {
-    fn to_chalk(self, interner: DbInterner<'db>) -> crate::Substitution {
-        Substitution::from_iter(
-            Interner,
-            self.inner().iter().map(|ty| ty.to_chalk(interner).cast(Interner)),
-        )
-    }
-}
-
-impl<'db> ChalkToNextSolver<'db, rustc_type_ir::DebruijnIndex> for chalk_ir::DebruijnIndex {
-    fn to_nextsolver(&self, _interner: DbInterner<'db>) -> rustc_type_ir::DebruijnIndex {
-        rustc_type_ir::DebruijnIndex::from_u32(self.depth())
-    }
-}
-
-impl<'db> NextSolverToChalk<'db, chalk_ir::DebruijnIndex> for rustc_type_ir::DebruijnIndex {
-    fn to_chalk(self, _interner: DbInterner<'db>) -> chalk_ir::DebruijnIndex {
-        chalk_ir::DebruijnIndex::new(self.index() as u32)
-    }
-}
-
-impl<'db> ChalkToNextSolver<'db, rustc_type_ir::UniverseIndex> for chalk_ir::UniverseIndex {
-    fn to_nextsolver(&self, _interner: DbInterner<'db>) -> rustc_type_ir::UniverseIndex {
-        rustc_type_ir::UniverseIndex::from_u32(self.counter as u32)
-    }
-}
-
-impl<'db> NextSolverToChalk<'db, chalk_ir::UniverseIndex> for rustc_type_ir::UniverseIndex {
-    fn to_chalk(self, _interner: DbInterner<'db>) -> chalk_ir::UniverseIndex {
-        chalk_ir::UniverseIndex { counter: self.index() }
-    }
-}
-
-impl<'db> ChalkToNextSolver<'db, rustc_type_ir::InferTy>
-    for (chalk_ir::InferenceVar, chalk_ir::TyVariableKind)
-{
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_type_ir::InferTy {
-        match self.1 {
-            chalk_ir::TyVariableKind::General => {
-                rustc_type_ir::InferTy::TyVar(rustc_type_ir::TyVid::from_u32(self.0.index()))
-            }
-            chalk_ir::TyVariableKind::Integer => {
-                rustc_type_ir::InferTy::IntVar(rustc_type_ir::IntVid::from_u32(self.0.index()))
-            }
-            chalk_ir::TyVariableKind::Float => {
-                rustc_type_ir::InferTy::FloatVar(rustc_type_ir::FloatVid::from_u32(self.0.index()))
-            }
-        }
-    }
-}
-
-impl<'db> ChalkToNextSolver<'db, rustc_ast_ir::Mutability> for chalk_ir::Mutability {
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_ast_ir::Mutability {
-        match self {
-            chalk_ir::Mutability::Mut => rustc_ast_ir::Mutability::Mut,
-            chalk_ir::Mutability::Not => rustc_ast_ir::Mutability::Not,
-        }
-    }
-}
-
-impl<'db> ChalkToNextSolver<'db, rustc_type_ir::Variance> for crate::Variance {
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_type_ir::Variance {
-        match self {
-            crate::Variance::Covariant => rustc_type_ir::Variance::Covariant,
-            crate::Variance::Invariant => rustc_type_ir::Variance::Invariant,
-            crate::Variance::Contravariant => rustc_type_ir::Variance::Contravariant,
-            crate::Variance::Bivariant => rustc_type_ir::Variance::Bivariant,
-        }
-    }
-}
-
-impl<'db> ChalkToNextSolver<'db, rustc_type_ir::Variance> for chalk_ir::Variance {
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_type_ir::Variance {
-        match self {
-            chalk_ir::Variance::Covariant => rustc_type_ir::Variance::Covariant,
-            chalk_ir::Variance::Invariant => rustc_type_ir::Variance::Invariant,
-            chalk_ir::Variance::Contravariant => rustc_type_ir::Variance::Contravariant,
-        }
-    }
-}
-
-impl<'db> ChalkToNextSolver<'db, VariancesOf> for chalk_ir::Variances<Interner> {
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> VariancesOf {
-        VariancesOf::new_from_iter(
-            interner,
-            self.as_slice(Interner).iter().map(|v| v.to_nextsolver(interner)),
-        )
-    }
-}
-
-impl<'db> ChalkToNextSolver<'db, Goal<DbInterner<'db>, Predicate<'db>>>
-    for chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>
-{
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> Goal<DbInterner<'db>, Predicate<'db>> {
-        Goal::new(
-            interner,
-            self.environment.to_nextsolver(interner),
-            self.goal.to_nextsolver(interner),
-        )
-    }
-}
-
-impl<'db> NextSolverToChalk<'db, chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>>
-    for Goal<DbInterner<'db>, Predicate<'db>>
-{
-    fn to_chalk(
-        self,
-        interner: DbInterner<'db>,
-    ) -> chalk_ir::InEnvironment<chalk_ir::Goal<Interner>> {
-        chalk_ir::InEnvironment {
-            environment: self.param_env.to_chalk(interner),
-            goal: self.predicate.to_chalk(interner),
-        }
-    }
-}
-
-impl<'db, T: HasInterner<Interner = Interner> + ChalkToNextSolver<'db, U>, U>
-    ChalkToNextSolver<'db, Canonical<'db, U>> for chalk_ir::Canonical<T>
-{
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> Canonical<'db, U> {
-        let variables = CanonicalVars::new_from_iter(
-            interner,
-            self.binders.iter(Interner).map(|k| match &k.kind {
-                chalk_ir::VariableKind::Ty(ty_variable_kind) => match ty_variable_kind {
-                    // FIXME(next-solver): the info is incorrect, but we have no way to store the information in Chalk.
-                    TyVariableKind::General => rustc_type_ir::CanonicalVarKind::Ty {
-                        ui: UniverseIndex::ROOT,
-                        sub_root: BoundVar::from_u32(0),
-                    },
-                    TyVariableKind::Integer => rustc_type_ir::CanonicalVarKind::Int,
-                    TyVariableKind::Float => rustc_type_ir::CanonicalVarKind::Float,
-                },
-                chalk_ir::VariableKind::Lifetime => {
-                    rustc_type_ir::CanonicalVarKind::Region(UniverseIndex::ROOT)
-                }
-                chalk_ir::VariableKind::Const(ty) => {
-                    rustc_type_ir::CanonicalVarKind::Const(UniverseIndex::ROOT)
-                }
-            }),
-        );
-        Canonical {
-            max_universe: UniverseIndex::ROOT,
-            value: self.value.to_nextsolver(interner),
-            variables,
-        }
-    }
-}
-
-impl<'db, T: NextSolverToChalk<'db, U>, U: HasInterner<Interner = Interner>>
-    NextSolverToChalk<'db, chalk_ir::Canonical<U>> for Canonical<'db, T>
-{
-    fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Canonical<U> {
-        let binders = chalk_ir::CanonicalVarKinds::from_iter(
-            Interner,
-            self.variables.iter().map(|v| match v {
-                rustc_type_ir::CanonicalVarKind::Ty { ui, sub_root: _ } => {
-                    chalk_ir::CanonicalVarKind::new(
-                        chalk_ir::VariableKind::Ty(TyVariableKind::General),
-                        chalk_ir::UniverseIndex { counter: ui.as_usize() },
-                    )
-                }
-                rustc_type_ir::CanonicalVarKind::Int => chalk_ir::CanonicalVarKind::new(
-                    chalk_ir::VariableKind::Ty(TyVariableKind::Integer),
-                    chalk_ir::UniverseIndex::root(),
-                ),
-                rustc_type_ir::CanonicalVarKind::Float => chalk_ir::CanonicalVarKind::new(
-                    chalk_ir::VariableKind::Ty(TyVariableKind::Float),
-                    chalk_ir::UniverseIndex::root(),
-                ),
-                rustc_type_ir::CanonicalVarKind::Region(ui) => chalk_ir::CanonicalVarKind::new(
-                    chalk_ir::VariableKind::Lifetime,
-                    chalk_ir::UniverseIndex { counter: ui.as_usize() },
-                ),
-                rustc_type_ir::CanonicalVarKind::Const(ui) => chalk_ir::CanonicalVarKind::new(
-                    chalk_ir::VariableKind::Const(chalk_ir::TyKind::Error.intern(Interner)),
-                    chalk_ir::UniverseIndex { counter: ui.as_usize() },
-                ),
-                rustc_type_ir::CanonicalVarKind::PlaceholderTy(_) => unimplemented!(),
-                rustc_type_ir::CanonicalVarKind::PlaceholderRegion(_) => unimplemented!(),
-                rustc_type_ir::CanonicalVarKind::PlaceholderConst(_) => unimplemented!(),
-            }),
-        );
-        let value = self.value.to_chalk(interner);
-        chalk_ir::Canonical { binders, value }
-    }
-}
-
-impl<'db> ChalkToNextSolver<'db, Predicate<'db>> for chalk_ir::Goal<Interner> {
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> Predicate<'db> {
-        match self.data(Interner) {
-            chalk_ir::GoalData::Quantified(quantifier_kind, binders) => {
-                if !binders.binders.is_empty(Interner) {
-                    panic!("Should not be constructed.");
-                }
-                let (val, _) = binders.clone().into_value_and_skipped_binders();
-                val.shifted_out(Interner).unwrap().to_nextsolver(interner)
-            }
-            chalk_ir::GoalData::Implies(program_clauses, goal) => {
-                panic!("Should not be constructed.")
-            }
-            chalk_ir::GoalData::All(goals) => panic!("Should not be constructed."),
-            chalk_ir::GoalData::Not(goal) => panic!("Should not be constructed."),
-            chalk_ir::GoalData::EqGoal(eq_goal) => {
-                let arg_to_term = |g: &chalk_ir::GenericArg<Interner>| match g.data(Interner) {
-                    chalk_ir::GenericArgData::Ty(ty) => Term::Ty(ty.to_nextsolver(interner)),
-                    chalk_ir::GenericArgData::Const(const_) => {
-                        Term::Const(const_.to_nextsolver(interner))
-                    }
-                    chalk_ir::GenericArgData::Lifetime(lifetime) => unreachable!(),
-                };
-                let pred_kind = PredicateKind::AliasRelate(
-                    arg_to_term(&eq_goal.a),
-                    arg_to_term(&eq_goal.b),
-                    rustc_type_ir::AliasRelationDirection::Equate,
-                );
-                let pred_kind =
-                    Binder::bind_with_vars(pred_kind, BoundVarKinds::new_from_iter(interner, []));
-                Predicate::new(interner, pred_kind)
-            }
-            chalk_ir::GoalData::SubtypeGoal(subtype_goal) => {
-                let subtype_predicate = SubtypePredicate {
-                    a: subtype_goal.a.to_nextsolver(interner),
-                    b: subtype_goal.b.to_nextsolver(interner),
-                    a_is_expected: true,
-                };
-                let pred_kind = PredicateKind::Subtype(subtype_predicate);
-                let pred_kind = Binder::bind_with_vars(
-                    shift_vars(interner, pred_kind, 1),
-                    BoundVarKinds::new_from_iter(interner, []),
-                );
-                Predicate::new(interner, pred_kind)
-            }
-            chalk_ir::GoalData::DomainGoal(domain_goal) => {
-                let pred_kind = domain_goal.to_nextsolver(interner);
-                let pred_kind = Binder::bind_with_vars(
-                    shift_vars(interner, pred_kind, 1),
-                    BoundVarKinds::new_from_iter(interner, []),
-                );
-                Predicate::new(interner, pred_kind)
-            }
-            chalk_ir::GoalData::CannotProve => panic!("Should not be constructed."),
-        }
-    }
-}
-
-impl<'db> NextSolverToChalk<'db, chalk_ir::Goal<Interner>> for Predicate<'db> {
-    fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Goal<Interner> {
-        chalk_ir::Goal::new(Interner, self.kind().skip_binder().to_chalk(interner))
-    }
-}
-
-impl<'db> NextSolverToChalk<'db, crate::ProjectionTy> for crate::next_solver::AliasTy<'db> {
-    fn to_chalk(self, interner: DbInterner<'db>) -> crate::ProjectionTy {
-        let SolverDefId::TypeAliasId(assoc_id) = self.def_id else { unreachable!() };
-        crate::ProjectionTy {
-            associated_ty_id: to_assoc_type_id(assoc_id),
-            substitution: self.args.to_chalk(interner),
-        }
-    }
-}
-
-impl<'db> ChalkToNextSolver<'db, ParamEnv<'db>> for chalk_ir::Environment<Interner> {
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> ParamEnv<'db> {
-        let clauses = Clauses::new_from_iter(
-            interner,
-            self.clauses.iter(Interner).map(|c| c.to_nextsolver(interner)),
-        );
-        let clauses =
-            Clauses::new_from_iter(interner, elaborate::elaborate(interner, clauses.iter()));
-        ParamEnv { clauses }
-    }
-}
-
-impl<'db> NextSolverToChalk<'db, chalk_ir::Environment<Interner>> for ParamEnv<'db> {
-    fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Environment<Interner> {
-        let clauses = chalk_ir::ProgramClauses::from_iter(
-            Interner,
-            self.clauses.iter().filter_map(|c| -> Option<chalk_ir::ProgramClause<Interner>> {
-                c.to_chalk(interner)
-            }),
-        );
-        chalk_ir::Environment { clauses }
-    }
-}
-
-impl<'db> ChalkToNextSolver<'db, Clause<'db>> for chalk_ir::ProgramClause<Interner> {
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> Clause<'db> {
-        Clause(Predicate::new(interner, self.data(Interner).0.to_nextsolver(interner)))
-    }
-}
-
-impl<'db> NextSolverToChalk<'db, Option<chalk_ir::ProgramClause<Interner>>> for Clause<'db> {
-    fn to_chalk(self, interner: DbInterner<'db>) -> Option<chalk_ir::ProgramClause<Interner>> {
-        let value: chalk_ir::ProgramClauseImplication<Interner> =
-            <PredicateKind<'db> as NextSolverToChalk<
-                'db,
-                Option<chalk_ir::ProgramClauseImplication<Interner>>,
-            >>::to_chalk(self.0.kind().skip_binder(), interner)?;
-        Some(chalk_ir::ProgramClause::new(
-            Interner,
-            chalk_ir::ProgramClauseData(chalk_ir::Binders::empty(Interner, value)),
-        ))
-    }
-}
-
-impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>>
-    for chalk_ir::ProgramClauseImplication<Interner>
-{
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> PredicateKind<'db> {
-        assert!(self.conditions.is_empty(Interner));
-        assert!(self.constraints.is_empty(Interner));
-        self.consequence.to_nextsolver(interner)
-    }
-}
-
-impl<'db> NextSolverToChalk<'db, Option<chalk_ir::ProgramClauseImplication<Interner>>>
-    for PredicateKind<'db>
-{
-    fn to_chalk(
-        self,
-        interner: DbInterner<'db>,
-    ) -> Option<chalk_ir::ProgramClauseImplication<Interner>> {
-        let chalk_ir::GoalData::DomainGoal(consequence) = self.to_chalk(interner) else {
-            return None;
-        };
-
-        Some(chalk_ir::ProgramClauseImplication {
-            consequence,
-            conditions: chalk_ir::Goals::empty(Interner),
-            constraints: chalk_ir::Constraints::empty(Interner),
-            priority: chalk_ir::ClausePriority::High,
-        })
-    }
-}
-
-impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>> for chalk_ir::DomainGoal<Interner> {
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> PredicateKind<'db> {
-        match self {
-            chalk_ir::DomainGoal::Holds(where_clause) => match where_clause {
-                chalk_ir::WhereClause::Implemented(trait_ref) => {
-                    let predicate = TraitPredicate {
-                        trait_ref: trait_ref.to_nextsolver(interner),
-                        polarity: rustc_type_ir::PredicatePolarity::Positive,
-                    };
-                    PredicateKind::Clause(ClauseKind::Trait(predicate))
-                }
-                chalk_ir::WhereClause::AliasEq(alias_eq) => match &alias_eq.alias {
-                    chalk_ir::AliasTy::Projection(p) => {
-                        let def_id =
-                            SolverDefId::TypeAliasId(from_assoc_type_id(p.associated_ty_id));
-                        let args = p.substitution.to_nextsolver(interner);
-                        let term: Ty<'db> = alias_eq.ty.to_nextsolver(interner);
-                        let term: Term<'db> = term.into();
-                        let predicate = ProjectionPredicate {
-                            projection_term: AliasTerm::new_from_args(interner, def_id, args),
-                            term,
-                        };
-                        PredicateKind::Clause(ClauseKind::Projection(predicate))
-                    }
-                    chalk_ir::AliasTy::Opaque(opaque) => {
-                        let id: InternedOpaqueTyId = opaque.opaque_ty_id.into();
-                        let def_id = SolverDefId::InternedOpaqueTyId(id);
-                        let args = opaque.substitution.to_nextsolver(interner);
-                        let term: Ty<'db> = alias_eq.ty.to_nextsolver(interner);
-                        let term: Term<'db> = term.into();
-                        let opaque_ty = Ty::new(
-                            interner,
-                            rustc_type_ir::TyKind::Alias(
-                                rustc_type_ir::AliasTyKind::Opaque,
-                                rustc_type_ir::AliasTy::new_from_args(interner, def_id, args),
-                            ),
-                        )
-                        .into();
-                        PredicateKind::AliasRelate(
-                            opaque_ty,
-                            term,
-                            rustc_type_ir::AliasRelationDirection::Equate,
-                        )
-                    }
-                },
-                chalk_ir::WhereClause::LifetimeOutlives(lifetime_outlives) => {
-                    let predicate = OutlivesPredicate(
-                        lifetime_outlives.a.to_nextsolver(interner),
-                        lifetime_outlives.b.to_nextsolver(interner),
-                    );
-                    PredicateKind::Clause(ClauseKind::RegionOutlives(predicate))
-                }
-                chalk_ir::WhereClause::TypeOutlives(type_outlives) => {
-                    let predicate = OutlivesPredicate(
-                        type_outlives.ty.to_nextsolver(interner),
-                        type_outlives.lifetime.to_nextsolver(interner),
-                    );
-                    PredicateKind::Clause(ClauseKind::TypeOutlives(predicate))
-                }
-            },
-            chalk_ir::DomainGoal::Normalize(normalize) => {
-                let proj_ty = match &normalize.alias {
-                    chalk_ir::AliasTy::Projection(proj) => proj,
-                    _ => unimplemented!(),
-                };
-                let args: GenericArgs<'db> = proj_ty.substitution.to_nextsolver(interner);
-                let alias = Ty::new(
-                    interner,
-                    rustc_type_ir::TyKind::Alias(
-                        rustc_type_ir::AliasTyKind::Projection,
-                        rustc_type_ir::AliasTy::new(
-                            interner,
-                            from_assoc_type_id(proj_ty.associated_ty_id).into(),
-                            args,
-                        ),
-                    ),
-                )
-                .into();
-                let term = normalize.ty.to_nextsolver(interner).into();
-                PredicateKind::AliasRelate(
-                    alias,
-                    term,
-                    rustc_type_ir::AliasRelationDirection::Equate,
-                )
-            }
-            chalk_ir::DomainGoal::WellFormed(well_formed) => {
-                let term = match well_formed {
-                    WellFormed::Trait(_) => panic!("Should not be constructed."),
-                    WellFormed::Ty(ty) => Term::Ty(ty.to_nextsolver(interner)),
-                };
-                PredicateKind::Clause(rustc_type_ir::ClauseKind::WellFormed(term))
-            }
-            chalk_ir::DomainGoal::FromEnv(from_env) => match from_env {
-                chalk_ir::FromEnv::Trait(trait_ref) => {
-                    let predicate = TraitPredicate {
-                        trait_ref: trait_ref.to_nextsolver(interner),
-                        polarity: rustc_type_ir::PredicatePolarity::Positive,
-                    };
-                    PredicateKind::Clause(ClauseKind::Trait(predicate))
-                }
-                chalk_ir::FromEnv::Ty(ty) => PredicateKind::Clause(ClauseKind::WellFormed(
-                    Term::Ty(ty.to_nextsolver(interner)),
-                )),
-            },
-            chalk_ir::DomainGoal::IsLocal(ty) => panic!("Should not be constructed."),
-            chalk_ir::DomainGoal::IsUpstream(ty) => panic!("Should not be constructed."),
-            chalk_ir::DomainGoal::IsFullyVisible(ty) => panic!("Should not be constructed."),
-            chalk_ir::DomainGoal::LocalImplAllowed(trait_ref) => {
-                panic!("Should not be constructed.")
-            }
-            chalk_ir::DomainGoal::Compatible => panic!("Should not be constructed."),
-            chalk_ir::DomainGoal::DownstreamType(ty) => panic!("Should not be constructed."),
-            chalk_ir::DomainGoal::Reveal => panic!("Should not be constructed."),
-            chalk_ir::DomainGoal::ObjectSafe(trait_id) => panic!("Should not be constructed."),
-        }
-    }
-}
-
-impl<'db> NextSolverToChalk<'db, chalk_ir::GoalData<Interner>> for PredicateKind<'db> {
-    fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::GoalData<Interner> {
-        match self {
-            rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Trait(trait_pred)) => {
-                let trait_ref = trait_pred.trait_ref.to_chalk(interner);
-                let where_clause = chalk_ir::WhereClause::Implemented(trait_ref);
-                chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause))
-            }
-            rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Projection(
-                proj_predicate,
-            )) => {
-                let associated_ty_id = match proj_predicate.def_id() {
-                    SolverDefId::TypeAliasId(id) => to_assoc_type_id(id),
-                    _ => unreachable!(),
-                };
-                let substitution = proj_predicate.projection_term.args.to_chalk(interner);
-                let alias = chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy {
-                    associated_ty_id,
-                    substitution,
-                });
-                let ty = match proj_predicate.term.kind() {
-                    rustc_type_ir::TermKind::Ty(ty) => ty,
-                    rustc_type_ir::TermKind::Const(_) => unimplemented!(),
-                };
-                let ty = ty.to_chalk(interner);
-                let alias_eq = chalk_ir::AliasEq { alias, ty };
-                let where_clause = chalk_ir::WhereClause::AliasEq(alias_eq);
-                chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause))
-            }
-            rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::TypeOutlives(
-                outlives,
-            )) => {
-                let lifetime = outlives.1.to_chalk(interner);
-                let ty = outlives.0.to_chalk(interner);
-                let where_clause =
-                    chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { lifetime, ty });
-                chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause))
-            }
-            rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::RegionOutlives(
-                outlives,
-            )) => {
-                let a = outlives.0.to_chalk(interner);
-                let b = outlives.1.to_chalk(interner);
-                let where_clause =
-                    chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { a, b });
-                chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause))
-            }
-            rustc_type_ir::PredicateKind::AliasRelate(
-                alias_term,
-                target_term,
-                alias_relation_direction,
-            ) => {
-                let term_to_generic_arg = |term: Term<'db>| match term {
-                    Term::Ty(ty) => chalk_ir::GenericArg::new(
-                        Interner,
-                        chalk_ir::GenericArgData::Ty(ty.to_chalk(interner)),
-                    ),
-                    Term::Const(const_) => chalk_ir::GenericArg::new(
-                        Interner,
-                        chalk_ir::GenericArgData::Const(const_.to_chalk(interner)),
-                    ),
-                };
-
-                chalk_ir::GoalData::EqGoal(chalk_ir::EqGoal {
-                    a: term_to_generic_arg(alias_term),
-                    b: term_to_generic_arg(target_term),
-                })
-            }
-            rustc_type_ir::PredicateKind::Clause(_) => unimplemented!(),
-            rustc_type_ir::PredicateKind::DynCompatible(_) => unimplemented!(),
-            rustc_type_ir::PredicateKind::Subtype(_) => unimplemented!(),
-            rustc_type_ir::PredicateKind::Coerce(_) => unimplemented!(),
-            rustc_type_ir::PredicateKind::ConstEquate(_, _) => unimplemented!(),
-            rustc_type_ir::PredicateKind::Ambiguous => unimplemented!(),
-            rustc_type_ir::PredicateKind::NormalizesTo(_) => unimplemented!(),
-        }
-    }
-}
-
-impl<'db> ChalkToNextSolver<'db, TraitRef<'db>> for chalk_ir::TraitRef<Interner> {
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> TraitRef<'db> {
-        let args = self.substitution.to_nextsolver(interner);
-        TraitRef::new_from_args(interner, from_chalk_trait_id(self.trait_id).into(), args)
-    }
-}
-
-impl<'db> NextSolverToChalk<'db, chalk_ir::TraitRef<Interner>> for TraitRef<'db> {
-    fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::TraitRef<Interner> {
-        let trait_id = to_chalk_trait_id(self.def_id.0);
-        let substitution = self.args.to_chalk(interner);
-        chalk_ir::TraitRef { trait_id, substitution }
-    }
-}
-
-impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>> for chalk_ir::WhereClause<Interner> {
-    fn to_nextsolver(&self, interner: DbInterner<'db>) -> PredicateKind<'db> {
-        match self {
-            chalk_ir::WhereClause::Implemented(trait_ref) => {
-                let predicate = TraitPredicate {
-                    trait_ref: trait_ref.to_nextsolver(interner),
-                    polarity: rustc_type_ir::PredicatePolarity::Positive,
-                };
-                PredicateKind::Clause(ClauseKind::Trait(predicate))
-            }
-            chalk_ir::WhereClause::AliasEq(alias_eq) => {
-                let projection = match &alias_eq.alias {
-                    chalk_ir::AliasTy::Projection(p) => p,
-                    _ => unimplemented!(),
-                };
-                let def_id =
-                    SolverDefId::TypeAliasId(from_assoc_type_id(projection.associated_ty_id));
-                let args = projection.substitution.to_nextsolver(interner);
-                let term: Ty<'db> = alias_eq.ty.to_nextsolver(interner);
-                let term: Term<'db> = term.into();
-                let predicate = ProjectionPredicate {
-                    projection_term: AliasTerm::new_from_args(interner, def_id, args),
-                    term,
-                };
-                PredicateKind::Clause(ClauseKind::Projection(predicate))
-            }
-            chalk_ir::WhereClause::TypeOutlives(type_outlives) => {
-                let ty = type_outlives.ty.to_nextsolver(interner);
-                let r = type_outlives.lifetime.to_nextsolver(interner);
-                PredicateKind::Clause(ClauseKind::TypeOutlives(OutlivesPredicate(ty, r)))
-            }
-            chalk_ir::WhereClause::LifetimeOutlives(lifetime_outlives) => {
-                let a = lifetime_outlives.a.to_nextsolver(interner);
-                let b = lifetime_outlives.b.to_nextsolver(interner);
-                PredicateKind::Clause(ClauseKind::RegionOutlives(OutlivesPredicate(a, b)))
-            }
-        }
-    }
-}
-
-impl<'db, I> NextSolverToChalk<'db, chalk_ir::ConstrainedSubst<Interner>> for I
-where
-    I: IntoIterator<Item = GenericArg<'db>>,
-{
-    fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::ConstrainedSubst<Interner> {
-        chalk_ir::ConstrainedSubst {
-            constraints: chalk_ir::Constraints::empty(Interner),
-            subst: GenericArgs::new_from_iter(interner, self).to_chalk(interner),
-        }
-    }
-}
-
-impl<'db> NextSolverToChalk<'db, crate::CallableSig> for rustc_type_ir::FnSig<DbInterner<'db>> {
-    fn to_chalk(self, interner: DbInterner<'db>) -> crate::CallableSig {
-        crate::CallableSig {
-            abi: self.abi,
-            is_varargs: self.c_variadic,
-            safety: match self.safety {
-                super::abi::Safety::Safe => chalk_ir::Safety::Safe,
-                super::abi::Safety::Unsafe => chalk_ir::Safety::Unsafe,
-            },
-            params_and_return: triomphe::Arc::from_iter(
-                self.inputs_and_output.iter().map(|ty| convert_ty_for_result(interner, ty)),
-            ),
-        }
-    }
-}
-
-pub fn convert_canonical_args_for_result<'db>(
-    interner: DbInterner<'db>,
-    args: Canonical<'db, Vec<GenericArg<'db>>>,
-) -> chalk_ir::Canonical<chalk_ir::ConstrainedSubst<Interner>> {
-    args.to_chalk(interner)
-}
-
-pub fn convert_args_for_result<'db>(
-    interner: DbInterner<'db>,
-    args: &[GenericArg<'db>],
-) -> crate::Substitution {
-    let mut substs = Vec::with_capacity(args.len());
-    for arg in args {
-        match (*arg).kind() {
-            rustc_type_ir::GenericArgKind::Type(ty) => {
-                let ty = convert_ty_for_result(interner, ty);
-                substs.push(chalk_ir::GenericArgData::Ty(ty).intern(Interner));
-            }
-            rustc_type_ir::GenericArgKind::Lifetime(region) => {
-                let lifetime = convert_region_for_result(interner, region);
-                substs.push(chalk_ir::GenericArgData::Lifetime(lifetime).intern(Interner));
-            }
-            rustc_type_ir::GenericArgKind::Const(const_) => {
-                substs.push(
-                    chalk_ir::GenericArgData::Const(convert_const_for_result(interner, const_))
-                        .intern(Interner),
-                );
-            }
-        }
-    }
-    Substitution::from_iter(Interner, substs)
-}
-
-pub fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) -> crate::Ty {
-    use crate::{Scalar, TyKind};
-    use chalk_ir::{FloatTy, IntTy, UintTy};
-    match ty.kind() {
-        rustc_type_ir::TyKind::Bool => TyKind::Scalar(Scalar::Bool),
-        rustc_type_ir::TyKind::Char => TyKind::Scalar(Scalar::Char),
-        rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I8) => {
-            TyKind::Scalar(Scalar::Int(IntTy::I8))
-        }
-        rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I16) => {
-            TyKind::Scalar(Scalar::Int(IntTy::I16))
-        }
-        rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I32) => {
-            TyKind::Scalar(Scalar::Int(IntTy::I32))
-        }
-        rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I64) => {
-            TyKind::Scalar(Scalar::Int(IntTy::I64))
-        }
-        rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I128) => {
-            TyKind::Scalar(Scalar::Int(IntTy::I128))
-        }
-        rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::Isize) => {
-            TyKind::Scalar(Scalar::Int(IntTy::Isize))
-        }
-        rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U8) => {
-            TyKind::Scalar(Scalar::Uint(UintTy::U8))
-        }
-        rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U16) => {
-            TyKind::Scalar(Scalar::Uint(UintTy::U16))
-        }
-        rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U32) => {
-            TyKind::Scalar(Scalar::Uint(UintTy::U32))
-        }
-        rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U64) => {
-            TyKind::Scalar(Scalar::Uint(UintTy::U64))
-        }
-        rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U128) => {
-            TyKind::Scalar(Scalar::Uint(UintTy::U128))
-        }
-        rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::Usize) => {
-            TyKind::Scalar(Scalar::Uint(UintTy::Usize))
-        }
-        rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F16) => {
-            TyKind::Scalar(Scalar::Float(FloatTy::F16))
-        }
-        rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F32) => {
-            TyKind::Scalar(Scalar::Float(FloatTy::F32))
-        }
-        rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F64) => {
-            TyKind::Scalar(Scalar::Float(FloatTy::F64))
-        }
-        rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F128) => {
-            TyKind::Scalar(Scalar::Float(FloatTy::F128))
-        }
-        rustc_type_ir::TyKind::Str => TyKind::Str,
-        rustc_type_ir::TyKind::Error(_) => TyKind::Error,
-        rustc_type_ir::TyKind::Never => TyKind::Never,
-
-        rustc_type_ir::TyKind::Adt(def, args) => {
-            let adt_id = def.inner().id;
-            let subst = convert_args_for_result(interner, args.as_slice());
-            TyKind::Adt(chalk_ir::AdtId(adt_id), subst)
-        }
-
-        rustc_type_ir::TyKind::Infer(infer_ty) => {
-            let (var, kind) = match infer_ty {
-                rustc_type_ir::InferTy::TyVar(var) => {
-                    (InferenceVar::from(var.as_u32()), TyVariableKind::General)
-                }
-                rustc_type_ir::InferTy::IntVar(var) => {
-                    (InferenceVar::from(var.as_u32()), TyVariableKind::Integer)
-                }
-                rustc_type_ir::InferTy::FloatVar(var) => {
-                    (InferenceVar::from(var.as_u32()), TyVariableKind::Float)
-                }
-                rustc_type_ir::InferTy::FreshFloatTy(..)
-                | rustc_type_ir::InferTy::FreshIntTy(..)
-                | rustc_type_ir::InferTy::FreshTy(..) => {
-                    panic!("Freshening shouldn't happen.")
-                }
-            };
-            TyKind::InferenceVar(var, kind)
-        }
-
-        rustc_type_ir::TyKind::Ref(r, ty, mutability) => {
-            let mutability = match mutability {
-                rustc_ast_ir::Mutability::Mut => chalk_ir::Mutability::Mut,
-                rustc_ast_ir::Mutability::Not => chalk_ir::Mutability::Not,
-            };
-            let r = convert_region_for_result(interner, r);
-            let ty = convert_ty_for_result(interner, ty);
-            TyKind::Ref(mutability, r, ty)
-        }
-
-        rustc_type_ir::TyKind::Tuple(tys) => {
-            let size = tys.len();
-            let subst = Substitution::from_iter(
-                Interner,
-                tys.iter().map(|ty| {
-                    chalk_ir::GenericArgData::Ty(convert_ty_for_result(interner, ty))
-                        .intern(Interner)
-                }),
-            );
-            TyKind::Tuple(size, subst)
-        }
-
-        rustc_type_ir::TyKind::Array(ty, const_) => {
-            let ty = convert_ty_for_result(interner, ty);
-            let const_ = convert_const_for_result(interner, const_);
-            TyKind::Array(ty, const_)
-        }
-
-        rustc_type_ir::TyKind::Alias(alias_ty_kind, alias_ty) => match alias_ty_kind {
-            rustc_type_ir::AliasTyKind::Projection => {
-                let assoc_ty_id = match alias_ty.def_id {
-                    SolverDefId::TypeAliasId(id) => id,
-                    _ => unreachable!(),
-                };
-                let associated_ty_id = to_assoc_type_id(assoc_ty_id);
-                let substitution = convert_args_for_result(interner, alias_ty.args.as_slice());
-                TyKind::Alias(crate::AliasTy::Projection(crate::ProjectionTy {
-                    associated_ty_id,
-                    substitution,
-                }))
-            }
-            rustc_type_ir::AliasTyKind::Opaque => {
-                let opaque_ty_id = match alias_ty.def_id {
-                    SolverDefId::InternedOpaqueTyId(id) => id,
-                    _ => unreachable!(),
-                };
-                let substitution = convert_args_for_result(interner, alias_ty.args.as_slice());
-                TyKind::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy {
-                    opaque_ty_id: opaque_ty_id.into(),
-                    substitution,
-                }))
-            }
-            rustc_type_ir::AliasTyKind::Inherent => unimplemented!(),
-            rustc_type_ir::AliasTyKind::Free => unimplemented!(),
-        },
-
-        // For `Placeholder`, `Bound` and `Param`, see the comment on the reverse conversion.
-        rustc_type_ir::TyKind::Placeholder(placeholder) => {
-            unimplemented!(
-                "A `rustc_type_ir::TyKind::Placeholder` doesn't have a direct \
-                correspondence in Chalk, as it represents a universally instantiated `Bound`.\n\
-                It therefore feels safer to leave it panicking, but if you hit this panic \
-                feel free to do the same as in `rustc_type_ir::TyKind::Bound` here."
-            )
-        }
-        rustc_type_ir::TyKind::Bound(debruijn_index, ty) => TyKind::BoundVar(chalk_ir::BoundVar {
-            debruijn: chalk_ir::DebruijnIndex::new(debruijn_index.as_u32()),
-            index: ty.var.as_usize(),
-        }),
-        rustc_type_ir::TyKind::Param(param) => {
-            let placeholder = to_placeholder_idx(interner.db, param.id.into(), param.index);
-            TyKind::Placeholder(placeholder)
-        }
-
-        rustc_type_ir::TyKind::FnPtr(bound_sig, fn_header) => {
-            let num_binders = bound_sig.bound_vars().len();
-            let sig = chalk_ir::FnSig {
-                abi: fn_header.abi,
-                safety: match fn_header.safety {
-                    crate::next_solver::abi::Safety::Safe => chalk_ir::Safety::Safe,
-                    crate::next_solver::abi::Safety::Unsafe => chalk_ir::Safety::Unsafe,
-                },
-                variadic: fn_header.c_variadic,
-            };
-            let args = GenericArgs::new_from_iter(
-                interner,
-                bound_sig.skip_binder().inputs_and_output.iter().map(|a| a.into()),
-            );
-            let substitution = convert_args_for_result(interner, args.as_slice());
-            let substitution = chalk_ir::FnSubst(substitution);
-            let fnptr = chalk_ir::FnPointer { num_binders, sig, substitution };
-            TyKind::Function(fnptr)
-        }
-
-        rustc_type_ir::TyKind::Dynamic(preds, region) => {
-            let self_ty = Ty::new_bound(
-                interner,
-                DebruijnIndex::from_u32(1),
-                BoundTy { kind: BoundTyKind::Anon, var: BoundVar::from_u32(0) },
-            );
-            let bounds = chalk_ir::QuantifiedWhereClauses::from_iter(
-                Interner,
-                preds.iter().map(|p| {
-                    let binders = chalk_ir::VariableKinds::from_iter(
-                        Interner,
-                        p.bound_vars().iter().map(|b| match b {
-                            BoundVarKind::Ty(kind) => {
-                                chalk_ir::VariableKind::Ty(TyVariableKind::General)
-                            }
-                            BoundVarKind::Region(kind) => chalk_ir::VariableKind::Lifetime,
-                            BoundVarKind::Const => {
-                                chalk_ir::VariableKind::Const(crate::TyKind::Error.intern(Interner))
-                            }
-                        }),
-                    );
-
-                    // Rust and chalk have slightly different
-                    // representation for trait objects.
-                    //
-                    // Chalk uses `for<T0> for<'a> T0: Trait<'a>` while rustc
-                    // uses `ExistentialPredicate`s, which do not have a self ty.
-                    // We need to shift escaping bound vars by 1 to accommodate
-                    // the newly introduced `for<T0>` binder.
-                    let p = shift_vars(interner, p, 1);
-
-                    let where_clause = match p.skip_binder() {
-                        rustc_type_ir::ExistentialPredicate::Trait(trait_ref) => {
-                            let trait_ref = TraitRef::new(
-                                interner,
-                                trait_ref.def_id,
-                                [self_ty.into()].into_iter().chain(trait_ref.args.iter()),
-                            );
-                            let trait_id = to_chalk_trait_id(trait_ref.def_id.0);
-                            let substitution =
-                                convert_args_for_result(interner, trait_ref.args.as_slice());
-                            let trait_ref = chalk_ir::TraitRef { trait_id, substitution };
-                            chalk_ir::WhereClause::Implemented(trait_ref)
-                        }
-                        rustc_type_ir::ExistentialPredicate::AutoTrait(trait_) => {
-                            let trait_id = to_chalk_trait_id(trait_.0);
-                            let substitution = chalk_ir::Substitution::from1(
-                                Interner,
-                                convert_ty_for_result(interner, self_ty),
-                            );
-                            let trait_ref = chalk_ir::TraitRef { trait_id, substitution };
-                            chalk_ir::WhereClause::Implemented(trait_ref)
-                        }
-                        rustc_type_ir::ExistentialPredicate::Projection(existential_projection) => {
-                            let projection = ProjectionPredicate {
-                                projection_term: AliasTerm::new(
-                                    interner,
-                                    existential_projection.def_id,
-                                    [self_ty.into()]
-                                        .iter()
-                                        .chain(existential_projection.args.iter()),
-                                ),
-                                term: existential_projection.term,
-                            };
-                            let associated_ty_id = match projection.projection_term.def_id {
-                                SolverDefId::TypeAliasId(id) => to_assoc_type_id(id),
-                                _ => unreachable!(),
-                            };
-                            let substitution = convert_args_for_result(
-                                interner,
-                                projection.projection_term.args.as_slice(),
-                            );
-                            let alias = chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy {
-                                associated_ty_id,
-                                substitution,
-                            });
-                            let ty = match projection.term {
-                                Term::Ty(ty) => ty,
-                                _ => unreachable!(),
-                            };
-                            let ty = convert_ty_for_result(interner, ty);
-                            let alias_eq = chalk_ir::AliasEq { alias, ty };
-                            chalk_ir::WhereClause::AliasEq(alias_eq)
-                        }
-                    };
-                    chalk_ir::Binders::new(binders, where_clause)
-                }),
-            );
-            let binders = chalk_ir::VariableKinds::from1(
-                Interner,
-                chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
-            );
-            let bounds = chalk_ir::Binders::new(binders, bounds);
-            let dyn_ty =
-                chalk_ir::DynTy { bounds, lifetime: convert_region_for_result(interner, region) };
-            TyKind::Dyn(dyn_ty)
-        }
-
-        rustc_type_ir::TyKind::Slice(ty) => {
-            let ty = convert_ty_for_result(interner, ty);
-            TyKind::Slice(ty)
-        }
-
-        rustc_type_ir::TyKind::Foreign(foreign) => TyKind::Foreign(to_foreign_def_id(foreign.0)),
-        rustc_type_ir::TyKind::Pat(_, _) => unimplemented!(),
-        rustc_type_ir::TyKind::RawPtr(ty, mutability) => {
-            let mutability = match mutability {
-                rustc_ast_ir::Mutability::Mut => chalk_ir::Mutability::Mut,
-                rustc_ast_ir::Mutability::Not => chalk_ir::Mutability::Not,
-            };
-            let ty = convert_ty_for_result(interner, ty);
-            TyKind::Raw(mutability, ty)
-        }
-        rustc_type_ir::TyKind::FnDef(def_id, args) => {
-            let subst = convert_args_for_result(interner, args.as_slice());
-            TyKind::FnDef(def_id.0.to_chalk(interner.db()), subst)
-        }
-
-        rustc_type_ir::TyKind::Closure(def_id, args) => {
-            let subst = convert_args_for_result(interner, args.as_slice());
-            TyKind::Closure(def_id.0.into(), subst)
-        }
-        rustc_type_ir::TyKind::CoroutineClosure(_, _) => unimplemented!(),
-        rustc_type_ir::TyKind::Coroutine(def_id, args) => {
-            let subst = convert_args_for_result(interner, args.as_slice());
-            TyKind::Coroutine(def_id.0.into(), subst)
-        }
-        rustc_type_ir::TyKind::CoroutineWitness(def_id, args) => {
-            let subst = convert_args_for_result(interner, args.as_slice());
-            TyKind::CoroutineWitness(def_id.0.into(), subst)
-        }
-
-        rustc_type_ir::TyKind::UnsafeBinder(_) => unimplemented!(),
-    }
-    .intern(Interner)
-}
-
-pub fn convert_const_for_result<'db>(
-    interner: DbInterner<'db>,
-    const_: Const<'db>,
-) -> crate::Const {
-    let value: chalk_ir::ConstValue<Interner> = match const_.kind() {
-        rustc_type_ir::ConstKind::Infer(rustc_type_ir::InferConst::Var(var)) => {
-            chalk_ir::ConstValue::InferenceVar(chalk_ir::InferenceVar::from(var.as_u32()))
-        }
-        rustc_type_ir::ConstKind::Infer(rustc_type_ir::InferConst::Fresh(fresh)) => {
-            panic!("Vars should not be freshened.")
-        }
-        rustc_type_ir::ConstKind::Param(param) => {
-            let placeholder = to_placeholder_idx(interner.db, param.id.into(), param.index);
-            chalk_ir::ConstValue::Placeholder(placeholder)
-        }
-        rustc_type_ir::ConstKind::Bound(debruijn_index, var) => {
-            chalk_ir::ConstValue::BoundVar(chalk_ir::BoundVar::new(
-                chalk_ir::DebruijnIndex::new(debruijn_index.as_u32()),
-                var.var.index(),
-            ))
-        }
-        rustc_type_ir::ConstKind::Placeholder(placeholder_const) => {
-            unimplemented!(
-                "A `rustc_type_ir::ConstKind::Placeholder` doesn't have a direct \
-                correspondence in Chalk, as it represents a universally instantiated `Bound`.\n\
-                It therefore feels safer to leave it panicking, but if you hit this panic \
-                feel free to do the same as in `rustc_type_ir::ConstKind::Bound` here."
-            )
-        }
-        rustc_type_ir::ConstKind::Unevaluated(unevaluated_const) => {
-            let id = match unevaluated_const.def {
-                SolverDefId::ConstId(id) => GeneralConstId::ConstId(id),
-                SolverDefId::StaticId(id) => GeneralConstId::StaticId(id),
-                _ => unreachable!(),
-            };
-            let subst = convert_args_for_result(interner, unevaluated_const.args.as_slice());
-            chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst {
-                interned: ConstScalar::UnevaluatedConst(id, subst),
-            })
-        }
-        rustc_type_ir::ConstKind::Value(value_const) => {
-            let bytes = value_const.value.inner();
-            let value = chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst {
-                // SAFETY: we will never actually use this without a database
-                interned: ConstScalar::Bytes(bytes.memory.clone(), unsafe {
-                    std::mem::transmute::<MemoryMap<'db>, MemoryMap<'static>>(
-                        bytes.memory_map.clone(),
-                    )
-                }),
-            });
-            return chalk_ir::ConstData {
-                ty: convert_ty_for_result(interner, value_const.ty),
-                value,
-            }
-            .intern(Interner);
-        }
-        rustc_type_ir::ConstKind::Error(_) => {
-            chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst {
-                interned: ConstScalar::Unknown,
-            })
-        }
-        rustc_type_ir::ConstKind::Expr(_) => unimplemented!(),
-    };
-    chalk_ir::ConstData { ty: crate::TyKind::Error.intern(Interner), value }.intern(Interner)
-}
-
-pub fn convert_region_for_result<'db>(
-    interner: DbInterner<'db>,
-    region: Region<'db>,
-) -> crate::Lifetime {
-    let lifetime = match region.kind() {
-        rustc_type_ir::RegionKind::ReEarlyParam(early) => {
-            let placeholder = lt_to_placeholder_idx(interner.db, early.id, early.index);
-            chalk_ir::LifetimeData::Placeholder(placeholder)
-        }
-        rustc_type_ir::RegionKind::ReBound(db, bound) => {
-            chalk_ir::LifetimeData::BoundVar(chalk_ir::BoundVar::new(
-                chalk_ir::DebruijnIndex::new(db.as_u32()),
-                bound.var.as_usize(),
-            ))
-        }
-        rustc_type_ir::RegionKind::RePlaceholder(placeholder) => unimplemented!(
-            "A `rustc_type_ir::RegionKind::RePlaceholder` doesn't have a direct \
-            correspondence in Chalk, as it represents a universally instantiated `Bound`.\n\
-            It therefore feels safer to leave it panicking, but if you hit this panic \
-            feel free to do the same as in `rustc_type_ir::RegionKind::ReBound` here."
-        ),
-        rustc_type_ir::RegionKind::ReLateParam(_) => unimplemented!(),
-        rustc_type_ir::RegionKind::ReStatic => chalk_ir::LifetimeData::Static,
-        rustc_type_ir::RegionKind::ReVar(vid) => {
-            chalk_ir::LifetimeData::InferenceVar(chalk_ir::InferenceVar::from(vid.as_u32()))
-        }
-        rustc_type_ir::RegionKind::ReErased => chalk_ir::LifetimeData::Erased,
-        rustc_type_ir::RegionKind::ReError(_) => chalk_ir::LifetimeData::Error,
-    };
-    chalk_ir::Lifetime::new(Interner, lifetime)
-}
-
-pub trait InferenceVarExt {
-    fn to_vid(self) -> rustc_type_ir::TyVid;
-    fn from_vid(vid: rustc_type_ir::TyVid) -> InferenceVar;
-}
-
-impl InferenceVarExt for InferenceVar {
-    fn to_vid(self) -> rustc_type_ir::TyVid {
-        rustc_type_ir::TyVid::from_u32(self.index())
-    }
-    fn from_vid(vid: rustc_type_ir::TyVid) -> InferenceVar {
-        InferenceVar::from(vid.as_u32())
-    }
-}
diff --git a/crates/hir-ty/src/next_solver/normalize.rs b/crates/hir-ty/src/next_solver/normalize.rs
index 2f241f8..bd678b3 100644
--- a/crates/hir-ty/src/next_solver/normalize.rs
+++ b/crates/hir-ty/src/next_solver/normalize.rs
@@ -5,7 +5,6 @@
     inherent::{IntoKind, Term as _},
 };
 
-use crate::next_solver::SolverDefId;
 use crate::next_solver::{
     Binder, Const, ConstKind, DbInterner, Goal, ParamEnv, Predicate, PredicateKind, Term, Ty,
     TyKind,
diff --git a/crates/hir-ty/src/next_solver/obligation_ctxt.rs b/crates/hir-ty/src/next_solver/obligation_ctxt.rs
index e85574a..ae92aea 100644
--- a/crates/hir-ty/src/next_solver/obligation_ctxt.rs
+++ b/crates/hir-ty/src/next_solver/obligation_ctxt.rs
@@ -1,14 +1,15 @@
 use hir_def::TraitId;
-use rustc_type_ir::relate::Relate;
 use rustc_type_ir::{TypeFoldable, Upcast, Variance};
 
-use crate::next_solver::fulfill::{FulfillmentCtxt, NextSolverError};
-use crate::next_solver::infer::at::ToTrace;
-use crate::next_solver::infer::traits::{
-    Obligation, ObligationCause, PredicateObligation, PredicateObligations,
+use crate::next_solver::{
+    Const, DbInterner, ParamEnv, Term, TraitRef, Ty, TypeError,
+    fulfill::{FulfillmentCtxt, NextSolverError},
+    infer::{
+        InferCtxt, InferOk,
+        at::ToTrace,
+        traits::{Obligation, ObligationCause, PredicateObligation, PredicateObligations},
+    },
 };
-use crate::next_solver::infer::{DefineOpaqueTypes, InferCtxt, InferOk, TypeTrace};
-use crate::next_solver::{Const, DbInterner, ParamEnv, Term, TraitRef, Ty, TypeError};
 
 /// Used if you want to have pleasant experience when dealing
 /// with obligations outside of hir or mir typeck.
@@ -69,21 +70,7 @@
     ) -> Result<(), TypeError<'db>> {
         self.infcx
             .at(cause, param_env)
-            .eq(DefineOpaqueTypes::Yes, expected, actual)
-            .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
-    }
-
-    pub fn eq_trace<T: Relate<DbInterner<'db>>>(
-        &mut self,
-        cause: &ObligationCause,
-        param_env: ParamEnv<'db>,
-        trace: TypeTrace<'db>,
-        expected: T,
-        actual: T,
-    ) -> Result<(), TypeError<'db>> {
-        self.infcx
-            .at(cause, param_env)
-            .eq_trace(DefineOpaqueTypes::Yes, trace, expected, actual)
+            .eq(expected, actual)
             .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
     }
 
@@ -97,7 +84,7 @@
     ) -> Result<(), TypeError<'db>> {
         self.infcx
             .at(cause, param_env)
-            .sub(DefineOpaqueTypes::Yes, expected, actual)
+            .sub(expected, actual)
             .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
     }
 
@@ -111,7 +98,7 @@
     ) -> Result<(), TypeError<'db>> {
         self.infcx
             .at(cause, param_env)
-            .relate(DefineOpaqueTypes::Yes, expected, variance, actual)
+            .relate(expected, variance, actual)
             .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
     }
 
@@ -125,7 +112,7 @@
     ) -> Result<(), TypeError<'db>> {
         self.infcx
             .at(cause, param_env)
-            .sup(DefineOpaqueTypes::Yes, expected, actual)
+            .sup(expected, actual)
             .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
     }
 
diff --git a/crates/hir-ty/src/next_solver/opaques.rs b/crates/hir-ty/src/next_solver/opaques.rs
index 0aee779..e8f5be2 100644
--- a/crates/hir-ty/src/next_solver/opaques.rs
+++ b/crates/hir-ty/src/next_solver/opaques.rs
@@ -1,86 +1,18 @@
 //! Things related to opaques in the next-trait-solver.
 
-use intern::Interned;
 use rustc_ast_ir::try_visit;
+use rustc_type_ir::inherent::SliceLike;
 
-use crate::next_solver::SolverDefId;
-
-use super::{CanonicalVarKind, DbInterner, interned_vec_nolifetime_salsa};
+use super::{DbInterner, SolverDefId, Ty, interned_vec_db, interned_vec_nolifetime_salsa};
 
 pub type OpaqueTypeKey<'db> = rustc_type_ir::OpaqueTypeKey<DbInterner<'db>>;
-pub type PredefinedOpaquesData<'db> = rustc_type_ir::solve::PredefinedOpaquesData<DbInterner<'db>>;
+
+type PredefinedOpaque<'db> = (OpaqueTypeKey<'db>, Ty<'db>);
+interned_vec_db!(PredefinedOpaques, PredefinedOpaque);
+
 pub type ExternalConstraintsData<'db> =
     rustc_type_ir::solve::ExternalConstraintsData<DbInterner<'db>>;
 
-#[salsa::interned(constructor = new_, debug)]
-pub struct PredefinedOpaques<'db> {
-    #[returns(ref)]
-    kind_: rustc_type_ir::solve::PredefinedOpaquesData<DbInterner<'db>>,
-}
-
-impl<'db> PredefinedOpaques<'db> {
-    pub fn new(interner: DbInterner<'db>, data: PredefinedOpaquesData<'db>) -> Self {
-        PredefinedOpaques::new_(interner.db(), data)
-    }
-
-    pub fn inner(&self) -> &PredefinedOpaquesData<'db> {
-        crate::with_attached_db(|db| {
-            let inner = self.kind_(db);
-            // SAFETY: ¯\_(ツ)_/¯
-            unsafe { std::mem::transmute(inner) }
-        })
-    }
-}
-
-impl<'db> rustc_type_ir::TypeVisitable<DbInterner<'db>> for PredefinedOpaques<'db> {
-    fn visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
-        &self,
-        visitor: &mut V,
-    ) -> V::Result {
-        self.opaque_types.visit_with(visitor)
-    }
-}
-
-impl<'db> rustc_type_ir::TypeFoldable<DbInterner<'db>> for PredefinedOpaques<'db> {
-    fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
-        Ok(PredefinedOpaques::new(
-            folder.cx(),
-            PredefinedOpaquesData {
-                opaque_types: self
-                    .opaque_types
-                    .iter()
-                    .cloned()
-                    .map(|opaque| opaque.try_fold_with(folder))
-                    .collect::<Result<_, F::Error>>()?,
-            },
-        ))
-    }
-    fn fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self {
-        PredefinedOpaques::new(
-            folder.cx(),
-            PredefinedOpaquesData {
-                opaque_types: self
-                    .opaque_types
-                    .iter()
-                    .cloned()
-                    .map(|opaque| opaque.fold_with(folder))
-                    .collect(),
-            },
-        )
-    }
-}
-
-impl<'db> std::ops::Deref for PredefinedOpaques<'db> {
-    type Target = PredefinedOpaquesData<'db>;
-
-    fn deref(&self) -> &Self::Target {
-        self.inner()
-    }
-}
-
 interned_vec_nolifetime_salsa!(SolverDefIds, SolverDefId);
 
 #[salsa::interned(constructor = new_, debug)]
diff --git a/crates/hir-ty/src/next_solver/predicate.rs b/crates/hir-ty/src/next_solver/predicate.rs
index 9dda9d0..3438b75 100644
--- a/crates/hir-ty/src/next_solver/predicate.rs
+++ b/crates/hir-ty/src/next_solver/predicate.rs
@@ -2,21 +2,18 @@
 
 use std::cmp::Ordering;
 
-use intern::Interned;
 use macros::{TypeFoldable, TypeVisitable};
-use rustc_ast_ir::try_visit;
 use rustc_type_ir::{
     self as ty, CollectAndApply, DebruijnIndex, EarlyBinder, FlagComputation, Flags,
     PredicatePolarity, TypeFlags, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable,
-    TypeVisitable, Upcast, UpcastFrom, VisitorResult, WithCachedTypeInfo,
+    TypeVisitable, Upcast, UpcastFrom, WithCachedTypeInfo,
     elaborate::Elaboratable,
     error::{ExpectedFound, TypeError},
     inherent::{IntoKind, SliceLike},
-    relate::Relate,
 };
-use smallvec::{SmallVec, smallvec};
+use smallvec::SmallVec;
 
-use crate::next_solver::TraitIdWrapper;
+use crate::next_solver::{InternedWrapperNoDebug, TraitIdWrapper};
 
 use super::{Binder, BoundVarKinds, DbInterner, Region, Ty, interned_vec_db};
 
@@ -56,11 +53,11 @@
     // FIXME: this is actual unstable - see impl in predicate.rs in `rustc_middle`
     match (a, b) {
         (ExistentialPredicate::Trait(_), ExistentialPredicate::Trait(_)) => Ordering::Equal,
-        (ExistentialPredicate::Projection(a), ExistentialPredicate::Projection(b)) => {
+        (ExistentialPredicate::Projection(_a), ExistentialPredicate::Projection(_b)) => {
             // Should sort by def path hash
             Ordering::Equal
         }
-        (ExistentialPredicate::AutoTrait(a), ExistentialPredicate::AutoTrait(b)) => {
+        (ExistentialPredicate::AutoTrait(_a), ExistentialPredicate::AutoTrait(_b)) => {
             // Should sort by def path hash
             Ordering::Equal
         }
@@ -174,9 +171,6 @@
     }
 }
 
-#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Clone)]
-pub struct InternedWrapperNoDebug<T>(pub(crate) T);
-
 #[salsa::interned(constructor = new_)]
 pub struct Predicate<'db> {
     #[returns(ref)]
@@ -283,8 +277,6 @@
     }
 }
 
-type InternedClauses<'db> = Interned<InternedClausesWrapper<'db>>;
-
 #[salsa::interned(constructor = new_)]
 pub struct Clauses<'db> {
     #[returns(ref)]
@@ -647,6 +639,26 @@
         PredicateKind::Clause(ClauseKind::RegionOutlives(from)).upcast(interner)
     }
 }
+impl<'db> UpcastFrom<DbInterner<'db>, ty::OutlivesPredicate<DbInterner<'db>, Ty<'db>>>
+    for Clause<'db>
+{
+    fn upcast_from(
+        from: ty::OutlivesPredicate<DbInterner<'db>, Ty<'db>>,
+        interner: DbInterner<'db>,
+    ) -> Self {
+        Clause(from.upcast(interner))
+    }
+}
+impl<'db> UpcastFrom<DbInterner<'db>, ty::OutlivesPredicate<DbInterner<'db>, Region<'db>>>
+    for Clause<'db>
+{
+    fn upcast_from(
+        from: ty::OutlivesPredicate<DbInterner<'db>, Region<'db>>,
+        interner: DbInterner<'db>,
+    ) -> Self {
+        Clause(from.upcast(interner))
+    }
+}
 
 impl<'db> UpcastFrom<DbInterner<'db>, PolyRegionOutlivesPredicate<'db>> for Predicate<'db> {
     fn upcast_from(from: PolyRegionOutlivesPredicate<'db>, tcx: DbInterner<'db>) -> Self {
diff --git a/crates/hir-ty/src/next_solver/region.rs b/crates/hir-ty/src/next_solver/region.rs
index 5e7eb75..b5f0e6d 100644
--- a/crates/hir-ty/src/next_solver/region.rs
+++ b/crates/hir-ty/src/next_solver/region.rs
@@ -1,10 +1,10 @@
 //! Things related to regions.
 
 use hir_def::LifetimeParamId;
-use intern::{Interned, Symbol};
+use intern::Symbol;
 use rustc_type_ir::{
-    BoundVar, DebruijnIndex, Flags, INNERMOST, RegionVid, TypeFlags, TypeFoldable, TypeVisitable,
-    VisitorResult,
+    BoundVar, BoundVarIndexKind, DebruijnIndex, Flags, INNERMOST, RegionVid, TypeFlags,
+    TypeFoldable, TypeVisitable,
     inherent::{IntoKind, PlaceholderLike, SliceLike},
     relate::Relate,
 };
@@ -68,7 +68,7 @@
         index: DebruijnIndex,
         bound: BoundRegion,
     ) -> Region<'db> {
-        Region::new(interner, RegionKind::ReBound(index, bound))
+        Region::new(interner, RegionKind::ReBound(BoundVarIndexKind::Bound(index), bound))
     }
 
     pub fn is_placeholder(&self) -> bool {
@@ -117,7 +117,11 @@
             RegionKind::ReStatic => {
                 flags |= TypeFlags::HAS_FREE_REGIONS;
             }
-            RegionKind::ReBound(..) => {
+            RegionKind::ReBound(BoundVarIndexKind::Canonical, ..) => {
+                flags |= TypeFlags::HAS_RE_BOUND;
+                flags |= TypeFlags::HAS_CANONICAL_BOUND;
+            }
+            RegionKind::ReBound(BoundVarIndexKind::Bound(..), ..) => {
                 flags |= TypeFlags::HAS_RE_BOUND;
             }
             RegionKind::ReErased => {
@@ -294,7 +298,7 @@
 
     fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex {
         match &self.inner() {
-            RegionKind::ReBound(debruijn, _) => debruijn.shifted_in(1),
+            RegionKind::ReBound(BoundVarIndexKind::Bound(debruijn), _) => debruijn.shifted_in(1),
             _ => INNERMOST,
         }
     }
@@ -306,7 +310,7 @@
         debruijn: rustc_type_ir::DebruijnIndex,
         var: BoundRegion,
     ) -> Self {
-        Region::new(interner, RegionKind::ReBound(debruijn, var))
+        Region::new(interner, RegionKind::ReBound(BoundVarIndexKind::Bound(debruijn), var))
     }
 
     fn new_anon_bound(
@@ -316,7 +320,20 @@
     ) -> Self {
         Region::new(
             interner,
-            RegionKind::ReBound(debruijn, BoundRegion { var, kind: BoundRegionKind::Anon }),
+            RegionKind::ReBound(
+                BoundVarIndexKind::Bound(debruijn),
+                BoundRegion { var, kind: BoundRegionKind::Anon },
+            ),
+        )
+    }
+
+    fn new_canonical_bound(interner: DbInterner<'db>, var: rustc_type_ir::BoundVar) -> Self {
+        Region::new(
+            interner,
+            RegionKind::ReBound(
+                BoundVarIndexKind::Canonical,
+                BoundRegion { var, kind: BoundRegionKind::Anon },
+            ),
         )
     }
 
diff --git a/crates/hir-ty/src/next_solver/solver.rs b/crates/hir-ty/src/next_solver/solver.rs
index 2457447..487d164 100644
--- a/crates/hir-ty/src/next_solver/solver.rs
+++ b/crates/hir-ty/src/next_solver/solver.rs
@@ -1,29 +1,22 @@
 //! Defining `SolverContext` for next-trait-solver.
 
-use hir_def::{AssocItemId, GeneralConstId, TypeAliasId};
+use hir_def::{AssocItemId, GeneralConstId};
 use rustc_next_trait_solver::delegate::SolverDelegate;
 use rustc_type_ir::GenericArgKind;
 use rustc_type_ir::lang_items::SolverTraitLangItem;
 use rustc_type_ir::{
-    InferCtxtLike, Interner, PredicatePolarity, TypeFlags, TypeVisitableExt, UniverseIndex,
-    inherent::{IntoKind, SliceLike, Span as _, Term as _, Ty as _},
+    InferCtxtLike, Interner, PredicatePolarity, TypeFlags, TypeVisitableExt,
+    inherent::{IntoKind, Term as _, Ty as _},
     solve::{Certainty, NoSolution},
 };
 
-use crate::next_solver::mapping::NextSolverToChalk;
 use crate::next_solver::{CanonicalVarKind, ImplIdWrapper};
-use crate::{
-    TraitRefExt,
-    db::HirDatabase,
-    next_solver::{
-        ClauseKind, CoercePredicate, PredicateKind, SubtypePredicate, mapping::ChalkToNextSolver,
-        util::sizedness_fast_path,
-    },
+use crate::next_solver::{
+    ClauseKind, CoercePredicate, PredicateKind, SubtypePredicate, util::sizedness_fast_path,
 };
 
 use super::{
-    Canonical, CanonicalVarValues, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs,
-    ParamEnv, Predicate, SolverDefId, Span, Ty, UnevaluatedConst,
+    DbInterner, ErrorGuaranteed, GenericArg, SolverDefId, Span,
     infer::{DbInternerInferExt, InferCtxt, canonical::instantiate::CanonicalExt},
 };
 
@@ -66,7 +59,7 @@
         (SolverContext(infcx), value, vars)
     }
 
-    fn fresh_var_for_kind_with_span(&self, arg: GenericArg<'db>, span: Span) -> GenericArg<'db> {
+    fn fresh_var_for_kind_with_span(&self, arg: GenericArg<'db>, _span: Span) -> GenericArg<'db> {
         match arg.kind() {
             GenericArgKind::Lifetime(_) => self.next_region_var().into(),
             GenericArgKind::Type(_) => self.next_ty_var().into(),
@@ -76,15 +69,15 @@
 
     fn leak_check(
         &self,
-        max_input_universe: rustc_type_ir::UniverseIndex,
+        _max_input_universe: rustc_type_ir::UniverseIndex,
     ) -> Result<(), NoSolution> {
         Ok(())
     }
 
     fn well_formed_goals(
         &self,
-        param_env: <Self::Interner as rustc_type_ir::Interner>::ParamEnv,
-        arg: <Self::Interner as rustc_type_ir::Interner>::Term,
+        _param_env: <Self::Interner as rustc_type_ir::Interner>::ParamEnv,
+        _arg: <Self::Interner as rustc_type_ir::Interner>::Term,
     ) -> Option<
         Vec<
             rustc_type_ir::solve::Goal<
@@ -123,7 +116,7 @@
     fn instantiate_canonical_var(
         &self,
         kind: CanonicalVarKind<'db>,
-        span: <Self::Interner as Interner>::Span,
+        _span: <Self::Interner as Interner>::Span,
         var_values: &[GenericArg<'db>],
         universe_map: impl Fn(rustc_type_ir::UniverseIndex) -> rustc_type_ir::UniverseIndex,
     ) -> GenericArg<'db> {
@@ -132,11 +125,11 @@
 
     fn add_item_bounds_for_hidden_type(
         &self,
-        def_id: <Self::Interner as rustc_type_ir::Interner>::DefId,
-        args: <Self::Interner as rustc_type_ir::Interner>::GenericArgs,
-        param_env: <Self::Interner as rustc_type_ir::Interner>::ParamEnv,
-        hidden_ty: <Self::Interner as rustc_type_ir::Interner>::Ty,
-        goals: &mut Vec<
+        _def_id: <Self::Interner as rustc_type_ir::Interner>::DefId,
+        _args: <Self::Interner as rustc_type_ir::Interner>::GenericArgs,
+        _param_env: <Self::Interner as rustc_type_ir::Interner>::ParamEnv,
+        _hidden_ty: <Self::Interner as rustc_type_ir::Interner>::Ty,
+        _goals: &mut Vec<
             rustc_type_ir::solve::Goal<
                 Self::Interner,
                 <Self::Interner as rustc_type_ir::Interner>::Predicate,
@@ -148,21 +141,10 @@
 
     fn fetch_eligible_assoc_item(
         &self,
-        goal_trait_ref: rustc_type_ir::TraitRef<Self::Interner>,
+        _goal_trait_ref: rustc_type_ir::TraitRef<Self::Interner>,
         trait_assoc_def_id: SolverDefId,
         impl_id: ImplIdWrapper,
     ) -> Result<Option<SolverDefId>, ErrorGuaranteed> {
-        let trait_ = self
-            .0
-            .interner
-            .db()
-            .impl_trait(impl_id.0)
-            // ImplIds for impls where the trait ref can't be resolved should never reach solver
-            .expect("invalid impl passed to next-solver")
-            .skip_binder()
-            .def_id
-            .0;
-        let trait_data = trait_.trait_items(self.0.interner.db());
         let impl_items = impl_id.0.impl_items(self.0.interner.db());
         let id = match trait_assoc_def_id {
             SolverDefId::TypeAliasId(trait_assoc_id) => {
@@ -208,16 +190,16 @@
 
     fn is_transmutable(
         &self,
-        dst: <Self::Interner as rustc_type_ir::Interner>::Ty,
-        src: <Self::Interner as rustc_type_ir::Interner>::Ty,
-        assume: <Self::Interner as rustc_type_ir::Interner>::Const,
+        _dst: <Self::Interner as rustc_type_ir::Interner>::Ty,
+        _src: <Self::Interner as rustc_type_ir::Interner>::Ty,
+        _assume: <Self::Interner as rustc_type_ir::Interner>::Const,
     ) -> Result<Certainty, NoSolution> {
         unimplemented!()
     }
 
     fn evaluate_const(
         &self,
-        param_env: <Self::Interner as rustc_type_ir::Interner>::ParamEnv,
+        _param_env: <Self::Interner as rustc_type_ir::Interner>::ParamEnv,
         uv: rustc_type_ir::UnevaluatedConst<Self::Interner>,
     ) -> Option<<Self::Interner as rustc_type_ir::Interner>::Const> {
         let c = match uv.def {
@@ -236,7 +218,7 @@
             Self::Interner,
             <Self::Interner as rustc_type_ir::Interner>::Predicate,
         >,
-        span: <Self::Interner as rustc_type_ir::Interner>::Span,
+        _span: <Self::Interner as rustc_type_ir::Interner>::Span,
     ) -> Option<Certainty> {
         if let Some(trait_pred) = goal.predicate.as_trait_clause() {
             if self.shallow_resolve(trait_pred.self_ty().skip_binder()).is_ty_var()
@@ -279,8 +261,8 @@
 
         let pred = goal.predicate.kind();
         match pred.no_bound_vars()? {
-            PredicateKind::Clause(ClauseKind::RegionOutlives(outlives)) => Some(Certainty::Yes),
-            PredicateKind::Clause(ClauseKind::TypeOutlives(outlives)) => Some(Certainty::Yes),
+            PredicateKind::Clause(ClauseKind::RegionOutlives(_outlives)) => Some(Certainty::Yes),
+            PredicateKind::Clause(ClauseKind::TypeOutlives(_outlives)) => Some(Certainty::Yes),
             PredicateKind::Subtype(SubtypePredicate { a, b, .. })
             | PredicateKind::Coerce(CoercePredicate { a, b }) => {
                 if self.shallow_resolve(a).is_ty_var() && self.shallow_resolve(b).is_ty_var() {
diff --git a/crates/hir-ty/src/next_solver/ty.rs b/crates/hir-ty/src/next_solver/ty.rs
index 44b85ab..b8406fe 100644
--- a/crates/hir-ty/src/next_solver/ty.rs
+++ b/crates/hir-ty/src/next_solver/ty.rs
@@ -1,41 +1,37 @@
 //! Things related to tys in the next-trait-solver.
 
-use std::iter;
 use std::ops::ControlFlow;
 
 use hir_def::{
-    AdtId, DefWithBodyId, GenericDefId, HasModule, TypeOrConstParamId, TypeParamId,
+    AdtId, HasModule, TypeParamId,
     hir::generics::{TypeOrConstParamData, TypeParamProvenance},
     lang_item::LangItem,
 };
 use hir_def::{TraitId, type_ref::Rawness};
-use intern::{Interned, Symbol, sym};
 use rustc_abi::{Float, Integer, Size};
 use rustc_ast_ir::{Mutability, try_visit, visit::VisitorResult};
 use rustc_type_ir::{
-    AliasTyKind, BoundVar, ClosureKind, CollectAndApply, FlagComputation, Flags, FloatTy, FloatVid,
-    InferTy, IntTy, IntVid, Interner, TyVid, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable,
-    TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, WithCachedTypeInfo,
+    AliasTyKind, BoundVar, BoundVarIndexKind, ClosureKind, CoroutineArgs, CoroutineArgsParts,
+    DebruijnIndex, FlagComputation, Flags, FloatTy, FloatVid, InferTy, IntTy, IntVid, Interner,
+    TyVid, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
+    TypeVisitor, UintTy, Upcast, WithCachedTypeInfo,
     inherent::{
-        Abi, AdtDef as _, BoundExistentialPredicates, BoundVarLike, Const as _, GenericArgs as _,
+        AdtDef as _, BoundExistentialPredicates, BoundVarLike, Const as _, GenericArgs as _,
         IntoKind, ParamLike, PlaceholderLike, Safety as _, SliceLike, Ty as _,
     },
     relate::Relate,
     solve::SizedTraitKind,
     walk::TypeWalker,
 };
-use salsa::plumbing::{AsId, FromId};
-use smallvec::SmallVec;
 
 use crate::{
-    FnAbi, ImplTraitId,
-    db::HirDatabase,
-    interner::InternedWrapperNoDebug,
+    ImplTraitId,
+    db::{HirDatabase, InternedCoroutine},
     next_solver::{
-        AdtDef, Binder, CallableIdWrapper, Clause, ClauseKind, ClosureIdWrapper, Const,
+        AdtDef, AliasTy, Binder, CallableIdWrapper, Clause, ClauseKind, ClosureIdWrapper, Const,
         CoroutineIdWrapper, FnSig, GenericArg, PolyFnSig, Region, TraitRef, TypeAliasIdWrapper,
         abi::Safety,
-        mapping::ChalkToNextSolver,
+        interner::InternedWrapperNoDebug,
         util::{CoroutineArgsExt, IntegerTypeExt},
     },
 };
@@ -83,7 +79,7 @@
         Ty::new(interner, TyKind::Adt(AdtDef::new(adt_id, interner), args))
     }
 
-    pub fn new_param(interner: DbInterner<'db>, id: TypeParamId, index: u32, name: Symbol) -> Self {
+    pub fn new_param(interner: DbInterner<'db>, id: TypeParamId, index: u32) -> Self {
         Ty::new(interner, TyKind::Param(ParamTy { id, index }))
     }
 
@@ -404,10 +400,44 @@
                 Some(interner.fn_sig(callable).instantiate(interner, args))
             }
             TyKind::FnPtr(sig, hdr) => Some(sig.with(hdr)),
-            TyKind::Closure(closure_id, closure_args) => closure_args
+            TyKind::Closure(_, closure_args) => closure_args
                 .split_closure_args_untupled()
                 .closure_sig_as_fn_ptr_ty
                 .callable_sig(interner),
+            TyKind::CoroutineClosure(coroutine_id, args) => {
+                Some(args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| {
+                    let unit_ty = Ty::new_unit(interner);
+                    let return_ty = Ty::new_coroutine(
+                        interner,
+                        coroutine_id,
+                        CoroutineArgs::new(
+                            interner,
+                            CoroutineArgsParts {
+                                parent_args: args.as_coroutine_closure().parent_args(),
+                                kind_ty: unit_ty,
+                                resume_ty: unit_ty,
+                                yield_ty: unit_ty,
+                                return_ty: sig.return_ty,
+                                // FIXME: Deduce this from the coroutine closure's upvars.
+                                tupled_upvars_ty: unit_ty,
+                            },
+                        )
+                        .args,
+                    );
+                    FnSig {
+                        inputs_and_output: Tys::new_from_iter(
+                            interner,
+                            sig.tupled_inputs_ty
+                                .tuple_fields()
+                                .iter()
+                                .chain(std::iter::once(return_ty)),
+                        ),
+                        c_variadic: sig.c_variadic,
+                        safety: sig.safety,
+                        abi: sig.abi,
+                    }
+                }))
+            }
             _ => None,
         }
     }
@@ -535,40 +565,21 @@
             TyKind::Alias(AliasTyKind::Opaque, opaque_ty) => {
                 match db.lookup_intern_impl_trait_id(opaque_ty.def_id.expect_opaque_ty()) {
                     ImplTraitId::ReturnTypeImplTrait(func, idx) => {
-                        db.return_type_impl_traits_ns(func).map(|it| {
-                            let data = (*it).as_ref().map_bound(|rpit| {
-                                &rpit.impl_traits[idx.to_nextsolver(interner)].predicates
-                            });
+                        db.return_type_impl_traits(func).map(|it| {
+                            let data =
+                                (*it).as_ref().map_bound(|rpit| &rpit.impl_traits[idx].predicates);
                             data.iter_instantiated_copied(interner, opaque_ty.args.as_slice())
                                 .collect()
                         })
                     }
                     ImplTraitId::TypeAliasImplTrait(alias, idx) => {
-                        db.type_alias_impl_traits_ns(alias).map(|it| {
-                            let data = (*it).as_ref().map_bound(|rpit| {
-                                &rpit.impl_traits[idx.to_nextsolver(interner)].predicates
-                            });
+                        db.type_alias_impl_traits(alias).map(|it| {
+                            let data =
+                                (*it).as_ref().map_bound(|rpit| &rpit.impl_traits[idx].predicates);
                             data.iter_instantiated_copied(interner, opaque_ty.args.as_slice())
                                 .collect()
                         })
                     }
-                    ImplTraitId::AsyncBlockTypeImplTrait(def, _) => {
-                        let krate = def.module(db).krate();
-                        if let Some(future_trait) = LangItem::Future.resolve_trait(db, krate) {
-                            // This is only used by type walking.
-                            // Parameters will be walked outside, and projection predicate is not used.
-                            // So just provide the Future trait.
-                            let impl_bound = TraitRef::new(
-                                interner,
-                                future_trait.into(),
-                                GenericArgs::new_from_iter(interner, []),
-                            )
-                            .upcast(interner);
-                            Some(vec![impl_bound])
-                        } else {
-                            None
-                        }
-                    }
                 }
             }
             TyKind::Param(param) => {
@@ -579,7 +590,7 @@
                     TypeOrConstParamData::TypeParamData(p) => match p.provenance {
                         TypeParamProvenance::ArgumentImplTrait => {
                             let predicates = db
-                                .generic_predicates_ns(param.id.parent())
+                                .generic_predicates(param.id.parent())
                                 .instantiate_identity()
                                 .into_iter()
                                 .flatten()
@@ -598,6 +609,24 @@
                     _ => None,
                 }
             }
+            TyKind::Coroutine(coroutine_id, _args) => {
+                let InternedCoroutine(owner, _) = coroutine_id.0.loc(db);
+                let krate = owner.module(db).krate();
+                if let Some(future_trait) = LangItem::Future.resolve_trait(db, krate) {
+                    // This is only used by type walking.
+                    // Parameters will be walked outside, and projection predicate is not used.
+                    // So just provide the Future trait.
+                    let impl_bound = TraitRef::new(
+                        interner,
+                        future_trait.into(),
+                        GenericArgs::new_from_iter(interner, []),
+                    )
+                    .upcast(interner);
+                    Some(vec![impl_bound])
+                } else {
+                    None
+                }
+            }
             _ => None,
         }
     }
@@ -899,27 +928,28 @@
         Ty::new(interner, TyKind::Placeholder(param))
     }
 
-    fn new_bound(
-        interner: DbInterner<'db>,
-        debruijn: rustc_type_ir::DebruijnIndex,
-        var: BoundTy,
-    ) -> Self {
-        Ty::new(interner, TyKind::Bound(debruijn, var))
+    fn new_bound(interner: DbInterner<'db>, debruijn: DebruijnIndex, var: BoundTy) -> Self {
+        Ty::new(interner, TyKind::Bound(BoundVarIndexKind::Bound(debruijn), var))
     }
 
-    fn new_anon_bound(
-        interner: DbInterner<'db>,
-        debruijn: rustc_type_ir::DebruijnIndex,
-        var: BoundVar,
-    ) -> Self {
-        Ty::new(interner, TyKind::Bound(debruijn, BoundTy { var, kind: BoundTyKind::Anon }))
+    fn new_anon_bound(interner: DbInterner<'db>, debruijn: DebruijnIndex, var: BoundVar) -> Self {
+        Ty::new(
+            interner,
+            TyKind::Bound(
+                BoundVarIndexKind::Bound(debruijn),
+                BoundTy { var, kind: BoundTyKind::Anon },
+            ),
+        )
     }
 
-    fn new_alias(
-        interner: DbInterner<'db>,
-        kind: rustc_type_ir::AliasTyKind,
-        alias_ty: rustc_type_ir::AliasTy<DbInterner<'db>>,
-    ) -> Self {
+    fn new_canonical_bound(interner: DbInterner<'db>, var: BoundVar) -> Self {
+        Ty::new(
+            interner,
+            TyKind::Bound(BoundVarIndexKind::Canonical, BoundTy { var, kind: BoundTyKind::Anon }),
+        )
+    }
+
+    fn new_alias(interner: DbInterner<'db>, kind: AliasTyKind, alias_ty: AliasTy<'db>) -> Self {
         Ty::new(interner, TyKind::Alias(kind, alias_ty))
     }
 
@@ -929,7 +959,7 @@
 
     fn new_adt(
         interner: DbInterner<'db>,
-        adt_def: <DbInterner<'db> as rustc_type_ir::Interner>::AdtDef,
+        adt_def: <DbInterner<'db> as Interner>::AdtDef,
         args: GenericArgs<'db>,
     ) -> Self {
         Ty::new(interner, TyKind::Adt(adt_def, args))
@@ -941,8 +971,8 @@
 
     fn new_dynamic(
         interner: DbInterner<'db>,
-        preds: <DbInterner<'db> as rustc_type_ir::Interner>::BoundExistentialPredicates,
-        region: <DbInterner<'db> as rustc_type_ir::Interner>::Region,
+        preds: <DbInterner<'db> as Interner>::BoundExistentialPredicates,
+        region: <DbInterner<'db> as Interner>::Region,
     ) -> Self {
         Ty::new(interner, TyKind::Dynamic(preds, region))
     }
@@ -950,7 +980,7 @@
     fn new_coroutine(
         interner: DbInterner<'db>,
         def_id: CoroutineIdWrapper,
-        args: <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs,
+        args: <DbInterner<'db> as Interner>::GenericArgs,
     ) -> Self {
         Ty::new(interner, TyKind::Coroutine(def_id, args))
     }
@@ -958,7 +988,7 @@
     fn new_coroutine_closure(
         interner: DbInterner<'db>,
         def_id: CoroutineIdWrapper,
-        args: <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs,
+        args: <DbInterner<'db> as Interner>::GenericArgs,
     ) -> Self {
         Ty::new(interner, TyKind::CoroutineClosure(def_id, args))
     }
@@ -966,7 +996,7 @@
     fn new_closure(
         interner: DbInterner<'db>,
         def_id: ClosureIdWrapper,
-        args: <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs,
+        args: <DbInterner<'db> as Interner>::GenericArgs,
     ) -> Self {
         Ty::new(interner, TyKind::Closure(def_id, args))
     }
@@ -974,7 +1004,7 @@
     fn new_coroutine_witness(
         interner: DbInterner<'db>,
         def_id: CoroutineIdWrapper,
-        args: <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs,
+        args: <DbInterner<'db> as Interner>::GenericArgs,
     ) -> Self {
         Ty::new(interner, TyKind::CoroutineWitness(def_id, args))
     }
@@ -982,7 +1012,7 @@
     fn new_coroutine_witness_for_coroutine(
         interner: DbInterner<'db>,
         def_id: CoroutineIdWrapper,
-        coroutine_args: <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs,
+        coroutine_args: <DbInterner<'db> as Interner>::GenericArgs,
     ) -> Self {
         // HACK: Coroutine witness types are lifetime erased, so they
         // never reference any lifetime args from the coroutine. We erase
@@ -1010,7 +1040,7 @@
 
     fn new_ref(
         interner: DbInterner<'db>,
-        region: <DbInterner<'db> as rustc_type_ir::Interner>::Region,
+        region: <DbInterner<'db> as Interner>::Region,
         ty: Self,
         mutbl: rustc_ast_ir::Mutability,
     ) -> Self {
@@ -1020,7 +1050,7 @@
     fn new_array_with_const_len(
         interner: DbInterner<'db>,
         ty: Self,
-        len: <DbInterner<'db> as rustc_type_ir::Interner>::Const,
+        len: <DbInterner<'db> as Interner>::Const,
     ) -> Self {
         Ty::new(interner, TyKind::Array(ty, len))
     }
@@ -1029,10 +1059,7 @@
         Ty::new(interner, TyKind::Slice(ty))
     }
 
-    fn new_tup(
-        interner: DbInterner<'db>,
-        tys: &[<DbInterner<'db> as rustc_type_ir::Interner>::Ty],
-    ) -> Self {
+    fn new_tup(interner: DbInterner<'db>, tys: &[<DbInterner<'db> as Interner>::Ty]) -> Self {
         Ty::new(interner, TyKind::Tuple(Tys::new_from_iter(interner, tys.iter().cloned())))
     }
 
@@ -1047,7 +1074,7 @@
     fn new_fn_def(
         interner: DbInterner<'db>,
         def_id: CallableIdWrapper,
-        args: <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs,
+        args: <DbInterner<'db> as Interner>::GenericArgs,
     ) -> Self {
         Ty::new(interner, TyKind::FnDef(def_id, args))
     }
@@ -1063,12 +1090,19 @@
     fn new_pat(
         interner: DbInterner<'db>,
         ty: Self,
-        pat: <DbInterner<'db> as rustc_type_ir::Interner>::Pat,
+        pat: <DbInterner<'db> as Interner>::Pat,
     ) -> Self {
         Ty::new(interner, TyKind::Pat(ty, pat))
     }
 
-    fn tuple_fields(self) -> <DbInterner<'db> as rustc_type_ir::Interner>::Tys {
+    fn new_unsafe_binder(
+        interner: DbInterner<'db>,
+        ty: rustc_type_ir::Binder<DbInterner<'db>, <DbInterner<'db> as Interner>::Ty>,
+    ) -> Self {
+        Ty::new(interner, TyKind::UnsafeBinder(ty.into()))
+    }
+
+    fn tuple_fields(self) -> <DbInterner<'db> as Interner>::Tys {
         match self.kind() {
             TyKind::Tuple(args) => args,
             _ => panic!("tuple_fields called on non-tuple: {self:?}"),
@@ -1115,10 +1149,11 @@
         }
     }
 
-    fn discriminant_ty(
-        self,
-        interner: DbInterner<'db>,
-    ) -> <DbInterner<'db> as rustc_type_ir::Interner>::Ty {
+    fn has_unsafe_fields(self) -> bool {
+        false
+    }
+
+    fn discriminant_ty(self, interner: DbInterner<'db>) -> <DbInterner<'db> as Interner>::Ty {
         match self.kind() {
             TyKind::Adt(adt, _) if adt.is_enum() => adt.repr().discr_type().to_ty(interner),
             TyKind::Coroutine(_, args) => args.as_coroutine().discr_ty(interner),
@@ -1172,20 +1207,6 @@
             TyKind::UnsafeBinder(..) => unimplemented!(),
         }
     }
-
-    fn new_unsafe_binder(
-        interner: DbInterner<'db>,
-        ty: rustc_type_ir::Binder<
-            DbInterner<'db>,
-            <DbInterner<'db> as rustc_type_ir::Interner>::Ty,
-        >,
-    ) -> Self {
-        Ty::new(interner, TyKind::UnsafeBinder(ty.into()))
-    }
-
-    fn has_unsafe_fields(self) -> bool {
-        false
-    }
 }
 
 interned_vec_db!(Tys, Ty);
@@ -1197,14 +1218,14 @@
 }
 
 impl<'db> rustc_type_ir::inherent::Tys<DbInterner<'db>> for Tys<'db> {
-    fn inputs(self) -> <DbInterner<'db> as rustc_type_ir::Interner>::FnInputTys {
+    fn inputs(self) -> <DbInterner<'db> as Interner>::FnInputTys {
         Tys::new_from_iter(
             DbInterner::conjure(),
             self.as_slice().split_last().unwrap().1.iter().copied(),
         )
     }
 
-    fn output(self) -> <DbInterner<'db> as rustc_type_ir::Interner>::Ty {
+    fn output(self) -> <DbInterner<'db> as Interner>::Ty {
         *self.as_slice().split_last().unwrap().0
     }
 }
@@ -1222,7 +1243,7 @@
 
 impl ParamTy {
     pub fn to_ty<'db>(self, interner: DbInterner<'db>) -> Ty<'db> {
-        Ty::new_param(interner, self.id, self.index, sym::MISSING_NAME.clone())
+        Ty::new_param(interner, self.id, self.index)
     }
 }
 
@@ -1269,11 +1290,11 @@
 impl<'db> TypeFoldable<DbInterner<'db>> for ErrorGuaranteed {
     fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
         self,
-        folder: &mut F,
+        _folder: &mut F,
     ) -> Result<Self, F::Error> {
         Ok(self)
     }
-    fn fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self {
+    fn fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(self, _folder: &mut F) -> Self {
         self
     }
 }
diff --git a/crates/hir-ty/src/next_solver/util.rs b/crates/hir-ty/src/next_solver/util.rs
index ae240a9..d113f76 100644
--- a/crates/hir-ty/src/next_solver/util.rs
+++ b/crates/hir-ty/src/next_solver/util.rs
@@ -1,50 +1,40 @@
 //! Various utilities for the next-trait-solver.
 
-use std::iter;
-use std::ops::{self, ControlFlow};
+use std::{
+    iter,
+    ops::{self, ControlFlow},
+};
 
 use base_db::Crate;
-use hir_def::lang_item::LangItem;
-use hir_def::{BlockId, HasModule, ItemContainerId, Lookup};
-use intern::sym;
+use hir_def::{BlockId, HasModule, lang_item::LangItem};
 use la_arena::Idx;
 use rustc_abi::{Float, HasDataLayout, Integer, IntegerType, Primitive, ReprOptions};
-use rustc_type_ir::data_structures::IndexMap;
-use rustc_type_ir::inherent::{
-    AdtDef, Const as _, GenericArg as _, GenericArgs as _, ParamEnv as _, Region as _, SliceLike,
-    Ty as _,
-};
-use rustc_type_ir::lang_items::SolverTraitLangItem;
-use rustc_type_ir::solve::SizedTraitKind;
 use rustc_type_ir::{
-    BoundVar, Canonical, DebruijnIndex, GenericArgKind, INNERMOST, Interner, PredicatePolarity,
-    TypeFlags, TypeVisitable, TypeVisitableExt,
+    ConstKind, CoroutineArgs, DebruijnIndex, FloatTy, INNERMOST, IntTy, Interner,
+    PredicatePolarity, RegionKind, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable,
+    TypeVisitableExt, TypeVisitor, UintTy, UniverseIndex,
+    inherent::{
+        AdtDef, GenericArg as _, GenericArgs as _, IntoKind, ParamEnv as _, SliceLike, Ty as _,
+    },
+    lang_items::SolverTraitLangItem,
+    solve::SizedTraitKind,
 };
-use rustc_type_ir::{
-    ConstKind, CoroutineArgs, FloatTy, IntTy, RegionKind, TypeFolder, TypeSuperFoldable,
-    TypeSuperVisitable, TypeVisitor, UintTy, UniverseIndex, inherent::IntoKind,
-};
-use rustc_type_ir::{InferCtxtLike, TypeFoldable};
 
-use crate::lower_nextsolver::{LifetimeElisionKind, TyLoweringContext};
-use crate::next_solver::infer::InferCtxt;
-use crate::next_solver::{
-    BoundConst, CanonicalVarKind, FxIndexMap, ParamEnv, Placeholder, PlaceholderConst,
-    PlaceholderRegion, TypingMode,
-};
 use crate::{
     db::HirDatabase,
-    from_foreign_def_id,
+    lower::{LifetimeElisionKind, TyLoweringContext},
     method_resolution::{TraitImpls, TyFingerprint},
+    next_solver::{
+        BoundConst, FxIndexMap, ParamEnv, Placeholder, PlaceholderConst, PlaceholderRegion,
+        infer::InferCtxt,
+    },
 };
 
-use super::fold::{BoundVarReplacer, FnMutDelegate};
-use super::generics::generics;
 use super::{
-    AliasTerm, AliasTy, Binder, BoundRegion, BoundTy, BoundTyKind, BoundVarKind, BoundVarKinds,
-    CanonicalVars, Clause, ClauseKind, Clauses, Const, DbInterner, EarlyBinder, GenericArg,
-    GenericArgs, Predicate, PredicateKind, ProjectionPredicate, Region, SolverContext, SolverDefId,
-    Term, TraitPredicate, TraitRef, Ty, TyKind,
+    Binder, BoundRegion, BoundTy, Clause, ClauseKind, Clauses, Const, DbInterner, EarlyBinder,
+    GenericArgs, Predicate, PredicateKind, Region, SolverDefId, TraitPredicate, TraitRef, Ty,
+    TyKind,
+    fold::{BoundVarReplacer, FnMutDelegate},
 };
 
 #[derive(Clone, Debug)]
@@ -514,151 +504,6 @@
     b.skip_binder().fold_with(&mut instantiate)
 }
 
-pub(crate) fn mini_canonicalize<'db, T: TypeFoldable<DbInterner<'db>>>(
-    mut context: SolverContext<'db>,
-    val: T,
-) -> Canonical<DbInterner<'db>, T> {
-    let mut canon = MiniCanonicalizer {
-        context: &mut context,
-        db: DebruijnIndex::ZERO,
-        vars: IndexMap::default(),
-    };
-    let canon_val = val.fold_with(&mut canon);
-    let vars = canon.vars;
-    Canonical {
-        value: canon_val,
-        max_universe: UniverseIndex::from_u32(1),
-        variables: CanonicalVars::new_from_iter(
-            context.cx(),
-            vars.iter().enumerate().map(|(idx, (k, v))| match (*k).kind() {
-                GenericArgKind::Type(ty) => match ty.kind() {
-                    TyKind::Int(..) | TyKind::Uint(..) => rustc_type_ir::CanonicalVarKind::Int,
-                    TyKind::Float(..) => rustc_type_ir::CanonicalVarKind::Float,
-                    _ => rustc_type_ir::CanonicalVarKind::Ty {
-                        ui: UniverseIndex::ZERO,
-                        sub_root: BoundVar::from_usize(idx),
-                    },
-                },
-                GenericArgKind::Lifetime(_) => {
-                    rustc_type_ir::CanonicalVarKind::Region(UniverseIndex::ZERO)
-                }
-                GenericArgKind::Const(_) => {
-                    rustc_type_ir::CanonicalVarKind::Const(UniverseIndex::ZERO)
-                }
-            }),
-        ),
-    }
-}
-
-struct MiniCanonicalizer<'a, 'db> {
-    context: &'a mut SolverContext<'db>,
-    db: DebruijnIndex,
-    vars: IndexMap<GenericArg<'db>, usize>,
-}
-
-impl<'db> TypeFolder<DbInterner<'db>> for MiniCanonicalizer<'_, 'db> {
-    fn cx(&self) -> DbInterner<'db> {
-        self.context.cx()
-    }
-
-    fn fold_binder<T: TypeFoldable<DbInterner<'db>>>(
-        &mut self,
-        t: rustc_type_ir::Binder<DbInterner<'db>, T>,
-    ) -> rustc_type_ir::Binder<DbInterner<'db>, T> {
-        self.db.shift_in(1);
-        let res = t.map_bound(|t| t.fold_with(self));
-        self.db.shift_out(1);
-        res
-    }
-
-    fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> {
-        match t.kind() {
-            rustc_type_ir::TyKind::Bound(db, _) => {
-                if db >= self.db {
-                    panic!("Unexpected bound var");
-                }
-                t
-            }
-            rustc_type_ir::TyKind::Infer(infer) => {
-                let t = match infer {
-                    rustc_type_ir::InferTy::TyVar(vid) => {
-                        self.context.opportunistic_resolve_ty_var(vid)
-                    }
-                    rustc_type_ir::InferTy::IntVar(vid) => {
-                        self.context.opportunistic_resolve_int_var(vid)
-                    }
-                    rustc_type_ir::InferTy::FloatVar(vid) => {
-                        self.context.opportunistic_resolve_float_var(vid)
-                    }
-                    _ => t,
-                };
-                let len = self.vars.len();
-                let var = *self.vars.entry(t.into()).or_insert(len);
-                Ty::new(
-                    self.cx(),
-                    TyKind::Bound(
-                        self.db,
-                        BoundTy { kind: super::BoundTyKind::Anon, var: BoundVar::from_usize(var) },
-                    ),
-                )
-            }
-            _ => t.super_fold_with(self),
-        }
-    }
-
-    fn fold_region(
-        &mut self,
-        r: <DbInterner<'db> as rustc_type_ir::Interner>::Region,
-    ) -> <DbInterner<'db> as rustc_type_ir::Interner>::Region {
-        match r.kind() {
-            RegionKind::ReBound(db, _) => {
-                if db >= self.db {
-                    panic!("Unexpected bound var");
-                }
-                r
-            }
-            RegionKind::ReVar(vid) => {
-                let len = self.vars.len();
-                let var = *self.vars.entry(r.into()).or_insert(len);
-                Region::new(
-                    self.cx(),
-                    RegionKind::ReBound(
-                        self.db,
-                        BoundRegion {
-                            kind: super::BoundRegionKind::Anon,
-                            var: BoundVar::from_usize(var),
-                        },
-                    ),
-                )
-            }
-            _ => r,
-        }
-    }
-
-    fn fold_const(
-        &mut self,
-        c: <DbInterner<'db> as rustc_type_ir::Interner>::Const,
-    ) -> <DbInterner<'db> as rustc_type_ir::Interner>::Const {
-        match c.kind() {
-            ConstKind::Bound(db, _) => {
-                if db >= self.db {
-                    panic!("Unexpected bound var");
-                }
-                c
-            }
-            ConstKind::Infer(infer) => {
-                let len = self.vars.len();
-                let var = *self.vars.entry(c.into()).or_insert(len);
-                Const::new(
-                    self.cx(),
-                    ConstKind::Bound(self.db, BoundConst { var: BoundVar::from_usize(var) }),
-                )
-            }
-            _ => c.super_fold_with(self),
-        }
-    }
-}
-
 pub fn explicit_item_bounds<'db>(
     interner: DbInterner<'db>,
     def_id: SolverDefId,
@@ -666,14 +511,8 @@
     let db = interner.db();
     match def_id {
         SolverDefId::TypeAliasId(type_alias) => {
-            let trait_ = match type_alias.lookup(db).container {
-                ItemContainerId::TraitId(t) => t,
-                _ => panic!("associated type not in trait"),
-            };
-
             // Lower bounds -- we could/should maybe move this to a separate query in `lower`
             let type_alias_data = db.type_alias_signature(type_alias);
-            let generic_params = generics(db, type_alias.into());
             let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db);
             let mut ctx = TyLoweringContext::new(
                 db,
@@ -723,7 +562,7 @@
             match full_id {
                 crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => {
                     let datas = db
-                        .return_type_impl_traits_ns(func)
+                        .return_type_impl_traits(func)
                         .expect("impl trait id without impl traits");
                     let datas = (*datas).as_ref().skip_binder();
                     let data = &datas.impl_traits[Idx::from_raw(idx.into_raw())];
@@ -731,104 +570,15 @@
                 }
                 crate::ImplTraitId::TypeAliasImplTrait(alias, idx) => {
                     let datas = db
-                        .type_alias_impl_traits_ns(alias)
+                        .type_alias_impl_traits(alias)
                         .expect("impl trait id without impl traits");
                     let datas = (*datas).as_ref().skip_binder();
                     let data = &datas.impl_traits[Idx::from_raw(idx.into_raw())];
                     EarlyBinder::bind(Clauses::new_from_iter(interner, data.predicates.clone()))
                 }
-                crate::ImplTraitId::AsyncBlockTypeImplTrait(..) => {
-                    if let Some((future_trait, future_output)) = LangItem::Future
-                        .resolve_trait(db, interner.krate.expect("Must have interner.krate"))
-                        .and_then(|trait_| {
-                            let alias = trait_.trait_items(db).associated_type_by_name(
-                                &hir_expand::name::Name::new_symbol_root(sym::Output.clone()),
-                            )?;
-                            Some((trait_, alias))
-                        })
-                    {
-                        let args = GenericArgs::identity_for_item(interner, def_id);
-                        let out = args.as_slice()[0];
-                        let mut predicates = vec![];
-
-                        let item_ty = Ty::new_alias(
-                            interner,
-                            rustc_type_ir::AliasTyKind::Opaque,
-                            AliasTy::new_from_args(interner, def_id, args),
-                        );
-
-                        let kind = PredicateKind::Clause(ClauseKind::Trait(TraitPredicate {
-                            polarity: rustc_type_ir::PredicatePolarity::Positive,
-                            trait_ref: TraitRef::new_from_args(
-                                interner,
-                                future_trait.into(),
-                                GenericArgs::new_from_iter(interner, [item_ty.into()]),
-                            ),
-                        }));
-                        predicates.push(Clause(Predicate::new(
-                            interner,
-                            Binder::bind_with_vars(
-                                kind,
-                                BoundVarKinds::new_from_iter(
-                                    interner,
-                                    [BoundVarKind::Ty(BoundTyKind::Anon)],
-                                ),
-                            ),
-                        )));
-                        let sized_trait = LangItem::Sized
-                            .resolve_trait(db, interner.krate.expect("Must have interner.krate"));
-                        if let Some(sized_trait_) = sized_trait {
-                            let kind = PredicateKind::Clause(ClauseKind::Trait(TraitPredicate {
-                                polarity: rustc_type_ir::PredicatePolarity::Positive,
-                                trait_ref: TraitRef::new_from_args(
-                                    interner,
-                                    sized_trait_.into(),
-                                    GenericArgs::new_from_iter(interner, [item_ty.into()]),
-                                ),
-                            }));
-                            predicates.push(Clause(Predicate::new(
-                                interner,
-                                Binder::bind_with_vars(
-                                    kind,
-                                    BoundVarKinds::new_from_iter(
-                                        interner,
-                                        [BoundVarKind::Ty(BoundTyKind::Anon)],
-                                    ),
-                                ),
-                            )));
-                        }
-                        let kind =
-                            PredicateKind::Clause(ClauseKind::Projection(ProjectionPredicate {
-                                projection_term: AliasTerm::new_from_args(
-                                    interner,
-                                    future_output.into(),
-                                    GenericArgs::new_from_iter(interner, [item_ty.into()]),
-                                ),
-                                term: match out.kind() {
-                                    GenericArgKind::Lifetime(lt) => panic!(),
-                                    GenericArgKind::Type(ty) => Term::Ty(ty),
-                                    GenericArgKind::Const(const_) => Term::Const(const_),
-                                },
-                            }));
-                        predicates.push(Clause(Predicate::new(
-                            interner,
-                            Binder::bind_with_vars(
-                                kind,
-                                BoundVarKinds::new_from_iter(
-                                    interner,
-                                    [BoundVarKind::Ty(BoundTyKind::Anon)],
-                                ),
-                            ),
-                        )));
-                        EarlyBinder::bind(Clauses::new_from_iter(interner, predicates))
-                    } else {
-                        // If failed to find Symbol’s value as variable is void: Future::Output, return empty bounds as fallback.
-                        EarlyBinder::bind(Clauses::new_from_iter(interner, []))
-                    }
-                }
             }
         }
-        _ => panic!("Unexpected GeneridDefId"),
+        _ => panic!("Unexpected GenericDefId"),
     }
 }
 
@@ -993,26 +743,6 @@
     }
 }
 
-pub(crate) fn needs_normalization<'db, T: TypeVisitable<DbInterner<'db>>>(
-    infcx: &InferCtxt<'db>,
-    value: &T,
-) -> bool {
-    let mut flags = TypeFlags::HAS_ALIAS;
-
-    // Opaques are treated as rigid outside of `TypingMode::PostAnalysis`,
-    // so we can ignore those.
-    match infcx.typing_mode() {
-        // FIXME(#132279): We likely want to reveal opaques during post borrowck analysis
-        TypingMode::Coherence
-        | TypingMode::Analysis { .. }
-        | TypingMode::Borrowck { .. }
-        | TypingMode::PostBorrowckAnalysis { .. } => flags.remove(TypeFlags::HAS_TY_OPAQUE),
-        TypingMode::PostAnalysis => {}
-    }
-
-    value.has_type_flags(flags)
-}
-
 pub fn sizedness_fast_path<'db>(
     tcx: DbInterner<'db>,
     predicate: Predicate<'db>,
diff --git a/crates/hir-ty/src/primitive.rs b/crates/hir-ty/src/primitive.rs
index d2901f7..9ffb112 100644
--- a/crates/hir-ty/src/primitive.rs
+++ b/crates/hir-ty/src/primitive.rs
@@ -1,7 +1,7 @@
 //! A few helper functions for dealing with primitives.
 
-pub use chalk_ir::{FloatTy, IntTy, UintTy};
 pub use hir_def::builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint};
+pub use rustc_type_ir::{FloatTy, IntTy, UintTy};
 
 pub fn int_ty_to_string(ty: IntTy) -> &'static str {
     match ty {
@@ -33,68 +33,3 @@
         FloatTy::F128 => "f128",
     }
 }
-
-pub fn int_ty_to_string_ns(ty: rustc_type_ir::IntTy) -> &'static str {
-    use rustc_type_ir::IntTy;
-    match ty {
-        IntTy::Isize => "isize",
-        IntTy::I8 => "i8",
-        IntTy::I16 => "i16",
-        IntTy::I32 => "i32",
-        IntTy::I64 => "i64",
-        IntTy::I128 => "i128",
-    }
-}
-
-pub fn uint_ty_to_string_ns(ty: rustc_type_ir::UintTy) -> &'static str {
-    use rustc_type_ir::UintTy;
-    match ty {
-        UintTy::Usize => "usize",
-        UintTy::U8 => "u8",
-        UintTy::U16 => "u16",
-        UintTy::U32 => "u32",
-        UintTy::U64 => "u64",
-        UintTy::U128 => "u128",
-    }
-}
-
-pub fn float_ty_to_string_ns(ty: rustc_type_ir::FloatTy) -> &'static str {
-    use rustc_type_ir::FloatTy;
-    match ty {
-        FloatTy::F16 => "f16",
-        FloatTy::F32 => "f32",
-        FloatTy::F64 => "f64",
-        FloatTy::F128 => "f128",
-    }
-}
-
-pub(super) fn int_ty_from_builtin(t: BuiltinInt) -> IntTy {
-    match t {
-        BuiltinInt::Isize => IntTy::Isize,
-        BuiltinInt::I8 => IntTy::I8,
-        BuiltinInt::I16 => IntTy::I16,
-        BuiltinInt::I32 => IntTy::I32,
-        BuiltinInt::I64 => IntTy::I64,
-        BuiltinInt::I128 => IntTy::I128,
-    }
-}
-
-pub(super) fn uint_ty_from_builtin(t: BuiltinUint) -> UintTy {
-    match t {
-        BuiltinUint::Usize => UintTy::Usize,
-        BuiltinUint::U8 => UintTy::U8,
-        BuiltinUint::U16 => UintTy::U16,
-        BuiltinUint::U32 => UintTy::U32,
-        BuiltinUint::U64 => UintTy::U64,
-        BuiltinUint::U128 => UintTy::U128,
-    }
-}
-
-pub(super) fn float_ty_from_builtin(t: BuiltinFloat) -> FloatTy {
-    match t {
-        BuiltinFloat::F16 => FloatTy::F16,
-        BuiltinFloat::F32 => FloatTy::F32,
-        BuiltinFloat::F64 => FloatTy::F64,
-        BuiltinFloat::F128 => FloatTy::F128,
-    }
-}
diff --git a/crates/hir-ty/src/specialization.rs b/crates/hir-ty/src/specialization.rs
new file mode 100644
index 0000000..611947b
--- /dev/null
+++ b/crates/hir-ty/src/specialization.rs
@@ -0,0 +1,150 @@
+//! Impl specialization related things
+
+use hir_def::{ImplId, nameres::crate_def_map};
+use intern::sym;
+use tracing::debug;
+
+use crate::{
+    db::HirDatabase,
+    next_solver::{
+        DbInterner, TypingMode,
+        infer::{
+            DbInternerInferExt,
+            traits::{Obligation, ObligationCause},
+        },
+        obligation_ctxt::ObligationCtxt,
+    },
+};
+
+// rustc does not have a cycle handling for the `specializes` query, meaning a cycle is a bug,
+// and indeed I was unable to cause cycles even with erroneous code. However, in r-a we can
+// create a cycle if there is an error in the impl's where clauses. I believe well formed code
+// cannot create a cycle, but a cycle handler is required nevertheless.
+fn specializes_cycle(
+    _db: &dyn HirDatabase,
+    _specializing_impl_def_id: ImplId,
+    _parent_impl_def_id: ImplId,
+) -> bool {
+    false
+}
+
+/// Is `specializing_impl_def_id` a specialization of `parent_impl_def_id`?
+///
+/// For every type that could apply to `specializing_impl_def_id`, we prove that
+/// the `parent_impl_def_id` also applies (i.e. it has a valid impl header and
+/// its where-clauses hold).
+///
+/// For the purposes of const traits, we also check that the specializing
+/// impl is not more restrictive than the parent impl. That is, if the
+/// `parent_impl_def_id` is a const impl (conditionally based off of some `[const]`
+/// bounds), then `specializing_impl_def_id` must also be const for the same
+/// set of types.
+#[salsa::tracked(cycle_result = specializes_cycle)]
+pub(crate) fn specializes(
+    db: &dyn HirDatabase,
+    specializing_impl_def_id: ImplId,
+    parent_impl_def_id: ImplId,
+) -> bool {
+    let module = specializing_impl_def_id.loc(db).container;
+
+    // We check that the specializing impl comes from a crate that has specialization enabled.
+    //
+    // We don't really care if the specialized impl (the parent) is in a crate that has
+    // specialization enabled, since it's not being specialized.
+    //
+    // rustc also checks whether the specializing impls comes from a macro marked
+    // `#[allow_internal_unstable(specialization)]`, but `#[allow_internal_unstable]`
+    // is an internal feature, std is not using it for specialization nor is likely to
+    // ever use it, and we don't have the span information necessary to replicate that.
+    let def_map = crate_def_map(db, module.krate());
+    if !def_map.is_unstable_feature_enabled(&sym::specialization)
+        && !def_map.is_unstable_feature_enabled(&sym::min_specialization)
+    {
+        return false;
+    }
+
+    let interner = DbInterner::new_with(db, Some(module.krate()), module.containing_block());
+
+    let specializing_impl_signature = db.impl_signature(specializing_impl_def_id);
+    let parent_impl_signature = db.impl_signature(parent_impl_def_id);
+
+    // We determine whether there's a subset relationship by:
+    //
+    // - replacing bound vars with placeholders in impl1,
+    // - assuming the where clauses for impl1,
+    // - instantiating impl2 with fresh inference variables,
+    // - unifying,
+    // - attempting to prove the where clauses for impl2
+    //
+    // The last three steps are encapsulated in `fulfill_implication`.
+    //
+    // See RFC 1210 for more details and justification.
+
+    // Currently we do not allow e.g., a negative impl to specialize a positive one
+    if specializing_impl_signature.is_negative() != parent_impl_signature.is_negative() {
+        return false;
+    }
+
+    // create a parameter environment corresponding to an identity instantiation of the specializing impl,
+    // i.e. the most generic instantiation of the specializing impl.
+    let param_env = db.trait_environment(specializing_impl_def_id.into()).env;
+
+    // Create an infcx, taking the predicates of the specializing impl as assumptions:
+    let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis());
+
+    let specializing_impl_trait_ref =
+        db.impl_trait(specializing_impl_def_id).unwrap().instantiate_identity();
+    let cause = &ObligationCause::dummy();
+    debug!(
+        "fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)",
+        param_env, specializing_impl_trait_ref, parent_impl_def_id
+    );
+
+    // Attempt to prove that the parent impl applies, given all of the above.
+
+    let mut ocx = ObligationCtxt::new(&infcx);
+
+    let parent_args = infcx.fresh_args_for_item(parent_impl_def_id.into());
+    let parent_impl_trait_ref = db
+        .impl_trait(parent_impl_def_id)
+        .expect("expected source impl to be a trait impl")
+        .instantiate(interner, parent_args);
+
+    // do the impls unify? If not, no specialization.
+    let Ok(()) = ocx.eq(cause, param_env, specializing_impl_trait_ref, parent_impl_trait_ref)
+    else {
+        return false;
+    };
+
+    // Now check that the source trait ref satisfies all the where clauses of the target impl.
+    // This is not just for correctness; we also need this to constrain any params that may
+    // only be referenced via projection predicates.
+    if let Some(predicates) =
+        db.generic_predicates(parent_impl_def_id.into()).instantiate(interner, parent_args)
+    {
+        ocx.register_obligations(
+            predicates
+                .map(|predicate| Obligation::new(interner, cause.clone(), param_env, predicate)),
+        );
+    }
+
+    let errors = ocx.evaluate_obligations_error_on_ambiguity();
+    if !errors.is_empty() {
+        // no dice!
+        debug!(
+            "fulfill_implication: for impls on {:?} and {:?}, \
+                 could not fulfill: {:?} given {:?}",
+            specializing_impl_trait_ref, parent_impl_trait_ref, errors, param_env
+        );
+        return false;
+    }
+
+    // FIXME: Check impl constness (when we implement const impls).
+
+    debug!(
+        "fulfill_implication: an impl for {:?} specializes {:?}",
+        specializing_impl_trait_ref, parent_impl_trait_ref
+    );
+
+    true
+}
diff --git a/crates/hir-ty/src/tests/incremental.rs b/crates/hir-ty/src/tests/incremental.rs
index 76cd5f7..bc47019 100644
--- a/crates/hir-ty/src/tests/incremental.rs
+++ b/crates/hir-ty/src/tests/incremental.rs
@@ -44,7 +44,7 @@
                 "body_shim",
                 "body_with_source_map_shim",
                 "trait_environment_shim",
-                "return_type_impl_traits_ns_shim",
+                "return_type_impl_traits_shim",
                 "expr_scopes_shim",
                 "lang_item",
                 "crate_lang_items",
@@ -131,7 +131,7 @@
                 "body_shim",
                 "body_with_source_map_shim",
                 "trait_environment_shim",
-                "return_type_impl_traits_ns_shim",
+                "return_type_impl_traits_shim",
                 "expr_scopes_shim",
                 "lang_item",
                 "crate_lang_items",
@@ -143,7 +143,7 @@
                 "body_shim",
                 "body_with_source_map_shim",
                 "trait_environment_shim",
-                "return_type_impl_traits_ns_shim",
+                "return_type_impl_traits_shim",
                 "expr_scopes_shim",
                 "infer_shim",
                 "function_signature_shim",
@@ -151,7 +151,7 @@
                 "body_shim",
                 "body_with_source_map_shim",
                 "trait_environment_shim",
-                "return_type_impl_traits_ns_shim",
+                "return_type_impl_traits_shim",
                 "expr_scopes_shim",
             ]
         "#]],
@@ -585,8 +585,8 @@
                 "crate_lang_items",
                 "attrs_shim",
                 "attrs_shim",
-                "generic_predicates_ns_shim",
-                "return_type_impl_traits_ns_shim",
+                "generic_predicates_shim",
+                "return_type_impl_traits_shim",
                 "infer_shim",
                 "function_signature_shim",
                 "function_signature_with_source_map_shim",
@@ -594,7 +594,7 @@
                 "expr_scopes_shim",
                 "struct_signature_shim",
                 "struct_signature_with_source_map_shim",
-                "generic_predicates_ns_shim",
+                "generic_predicates_shim",
                 "value_ty_shim",
                 "VariantFields::firewall_",
                 "VariantFields::query_",
@@ -608,9 +608,9 @@
                 "trait_impls_in_crate_shim",
                 "impl_trait_with_diagnostics_shim",
                 "impl_self_ty_with_diagnostics_shim",
-                "generic_predicates_ns_shim",
+                "generic_predicates_shim",
                 "value_ty_shim",
-                "generic_predicates_ns_shim",
+                "generic_predicates_shim",
             ]
         "#]],
     );
@@ -682,13 +682,13 @@
                 "attrs_shim",
                 "attrs_shim",
                 "attrs_shim",
-                "generic_predicates_ns_shim",
-                "return_type_impl_traits_ns_shim",
+                "generic_predicates_shim",
+                "return_type_impl_traits_shim",
                 "infer_shim",
                 "function_signature_with_source_map_shim",
                 "expr_scopes_shim",
                 "struct_signature_with_source_map_shim",
-                "generic_predicates_ns_shim",
+                "generic_predicates_shim",
                 "VariantFields::query_",
                 "inherent_impls_in_crate_shim",
                 "impl_signature_with_source_map_shim",
@@ -697,8 +697,8 @@
                 "trait_impls_in_crate_shim",
                 "impl_trait_with_diagnostics_shim",
                 "impl_self_ty_with_diagnostics_shim",
-                "generic_predicates_ns_shim",
-                "generic_predicates_ns_shim",
+                "generic_predicates_shim",
+                "generic_predicates_shim",
             ]
         "#]],
     );
diff --git a/crates/hir-ty/src/tests/regression/new_solver.rs b/crates/hir-ty/src/tests/regression/new_solver.rs
index 5983ec7..f8b73cd 100644
--- a/crates/hir-ty/src/tests/regression/new_solver.rs
+++ b/crates/hir-ty/src/tests/regression/new_solver.rs
@@ -472,3 +472,55 @@
 "#,
     );
 }
+
+#[test]
+fn regression_16282() {
+    check_infer(
+        r#"
+//- minicore: coerce_unsized, dispatch_from_dyn
+trait MapLookup<Q> {
+    type MapValue;
+}
+
+impl<K> MapLookup<K> for K {
+    type MapValue = K;
+}
+
+trait Map: MapLookup<<Self as Map>::Key> {
+    type Key;
+}
+
+impl<K> Map for K {
+    type Key = K;
+}
+
+
+fn main() {
+    let _ = &()
+        as &dyn Map<Key=u32,MapValue=u32>;
+}
+"#,
+        expect![[r#"
+            210..272 '{     ...32>; }': ()
+            220..221 '_': &'? (dyn Map<MapValue = u32, Key = u32> + '?)
+            224..227 '&()': &'? ()
+            224..269 '&()   ...e=u32>': &'? (dyn Map<MapValue = u32, Key = u32> + 'static)
+            225..227 '()': ()
+        "#]],
+    );
+}
+
+#[test]
+fn regression_18692() {
+    check_no_mismatches(
+        r#"
+//- minicore: coerce_unsized, dispatch_from_dyn, send
+trait Trait: Send {}
+
+fn f(_: *const (dyn Trait + Send)) {}
+fn g(it: *const (dyn Trait)) {
+    f(it);
+}
+"#,
+    );
+}
diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs
index 38af7cb..c2392b3 100644
--- a/crates/hir-ty/src/tests/simple.rs
+++ b/crates/hir-ty/src/tests/simple.rs
@@ -3856,9 +3856,9 @@
             74..75 'f': F
             80..82 '{}': ()
             94..191 '{     ... }); }': ()
-            100..113 'async_closure': fn async_closure<impl FnOnce(i32)>(impl FnOnce(i32))
+            100..113 'async_closure': fn async_closure<impl AsyncFnOnce(i32)>(impl AsyncFnOnce(i32))
             100..147 'async_...    })': ()
-            114..146 'async ...     }': impl FnOnce(i32)
+            114..146 'async ...     }': impl AsyncFnOnce(i32)
             121..124 'arg': i32
             126..146 '{     ...     }': ()
             136..139 'arg': i32
diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs
index 0cf723e..f72ca22 100644
--- a/crates/hir-ty/src/tests/traits.rs
+++ b/crates/hir-ty/src/tests/traits.rs
@@ -85,7 +85,6 @@
 }
 
 #[test]
-#[ignore = "FIXME(next-solver): fix async closures"]
 fn infer_async_closure() {
     check_types(
         r#"
@@ -93,7 +92,7 @@
 async fn test() {
     let f = async move |x: i32| x + 42;
     f;
-//  ^ impl Fn(i32) -> impl Future<Output = i32>
+//  ^ impl AsyncFn(i32) -> i32
     let a = f(4);
     a;
 //  ^ impl Future<Output = i32>
@@ -102,7 +101,7 @@
 //  ^ i32
     let f = async move || 42;
     f;
-//  ^ impl Fn() -> impl Future<Output = i32>
+//  ^ impl AsyncFn() -> i32
     let a = f();
     a;
 //  ^ impl Future<Output = i32>
@@ -119,7 +118,7 @@
     };
     let _: Option<u64> = c().await;
     c;
-//  ^ impl Fn() -> impl Future<Output = Option<u64>>
+//  ^ impl AsyncFn() -> Option<u64>
 }
 "#,
     );
@@ -4930,7 +4929,6 @@
 
 #[test]
 fn async_fn_return_type() {
-    // FIXME(next-solver): Async closures are lowered as closures currently. We should fix that.
     check_infer(
         r#"
 //- minicore: async_fn
@@ -4948,9 +4946,9 @@
             46..53 'loop {}': !
             51..53 '{}': ()
             67..97 '{     ...()); }': ()
-            73..76 'foo': fn foo<impl Fn(), ()>(impl Fn())
+            73..76 'foo': fn foo<impl AsyncFn(), ()>(impl AsyncFn())
             73..94 'foo(as...|| ())': ()
-            77..93 'async ... || ()': impl Fn()
+            77..93 'async ... || ()': impl AsyncFn()
             91..93 '()': ()
         "#]],
     );
diff --git a/crates/hir-ty/src/tls.rs b/crates/hir-ty/src/tls.rs
deleted file mode 100644
index fe4cf7a..0000000
--- a/crates/hir-ty/src/tls.rs
+++ /dev/null
@@ -1,155 +0,0 @@
-//! Implementation of Chalk debug helper functions using TLS.
-use std::fmt::{self, Display};
-
-use itertools::Itertools;
-use span::Edition;
-
-use crate::{
-    CallableDefId, Interner, ProjectionTyExt, chalk_db, db::HirDatabase, from_assoc_type_id,
-    from_chalk_trait_id, mapping::from_chalk,
-};
-use hir_def::{AdtId, ItemContainerId, Lookup, TypeAliasId};
-
-#[allow(unused)]
-pub(crate) use unsafe_tls::{set_current_program, with_current_program};
-
-pub(crate) struct DebugContext<'a>(&'a dyn HirDatabase);
-
-impl DebugContext<'_> {
-    pub(crate) fn debug_struct_id(
-        &self,
-        id: chalk_db::AdtId,
-        f: &mut fmt::Formatter<'_>,
-    ) -> Result<(), fmt::Error> {
-        let name = match id.0 {
-            AdtId::StructId(it) => self.0.struct_signature(it).name.clone(),
-            AdtId::UnionId(it) => self.0.union_signature(it).name.clone(),
-            AdtId::EnumId(it) => self.0.enum_signature(it).name.clone(),
-        };
-        name.display(self.0, Edition::LATEST).fmt(f)?;
-        Ok(())
-    }
-
-    pub(crate) fn debug_trait_id(
-        &self,
-        id: chalk_db::TraitId,
-        f: &mut fmt::Formatter<'_>,
-    ) -> Result<(), fmt::Error> {
-        let trait_: hir_def::TraitId = from_chalk_trait_id(id);
-        let trait_data = self.0.trait_signature(trait_);
-        trait_data.name.display(self.0, Edition::LATEST).fmt(f)?;
-        Ok(())
-    }
-
-    pub(crate) fn debug_assoc_type_id(
-        &self,
-        id: chalk_db::AssocTypeId,
-        fmt: &mut fmt::Formatter<'_>,
-    ) -> Result<(), fmt::Error> {
-        let type_alias: TypeAliasId = from_assoc_type_id(id);
-        let type_alias_data = self.0.type_alias_signature(type_alias);
-        let trait_ = match type_alias.lookup(self.0).container {
-            ItemContainerId::TraitId(t) => t,
-            _ => panic!("associated type not in trait"),
-        };
-        let trait_data = self.0.trait_signature(trait_);
-        write!(
-            fmt,
-            "{}::{}",
-            trait_data.name.display(self.0, Edition::LATEST),
-            type_alias_data.name.display(self.0, Edition::LATEST)
-        )?;
-        Ok(())
-    }
-
-    pub(crate) fn debug_projection_ty(
-        &self,
-        projection_ty: &chalk_ir::ProjectionTy<Interner>,
-        fmt: &mut fmt::Formatter<'_>,
-    ) -> Result<(), fmt::Error> {
-        let type_alias = from_assoc_type_id(projection_ty.associated_ty_id);
-        let type_alias_data = self.0.type_alias_signature(type_alias);
-        let trait_ = match type_alias.lookup(self.0).container {
-            ItemContainerId::TraitId(t) => t,
-            _ => panic!("associated type not in trait"),
-        };
-        let trait_name = &self.0.trait_signature(trait_).name;
-        let trait_ref = projection_ty.trait_ref(self.0);
-        let trait_params = trait_ref.substitution.as_slice(Interner);
-        let self_ty = trait_ref.self_type_parameter(Interner);
-        write!(fmt, "<{self_ty:?} as {}", trait_name.display(self.0, Edition::LATEST))?;
-        if trait_params.len() > 1 {
-            write!(
-                fmt,
-                "<{}>",
-                trait_params[1..].iter().format_with(", ", |x, f| f(&format_args!("{x:?}"))),
-            )?;
-        }
-        write!(fmt, ">::{}", type_alias_data.name.display(self.0, Edition::LATEST))?;
-
-        let proj_params = &projection_ty.substitution.as_slice(Interner)[trait_params.len()..];
-        if !proj_params.is_empty() {
-            write!(
-                fmt,
-                "<{}>",
-                proj_params.iter().format_with(", ", |x, f| f(&format_args!("{x:?}"))),
-            )?;
-        }
-
-        Ok(())
-    }
-
-    pub(crate) fn debug_fn_def_id(
-        &self,
-        fn_def_id: chalk_ir::FnDefId<Interner>,
-        fmt: &mut fmt::Formatter<'_>,
-    ) -> Result<(), fmt::Error> {
-        let def: CallableDefId = from_chalk(self.0, fn_def_id);
-        let name = match def {
-            CallableDefId::FunctionId(ff) => self.0.function_signature(ff).name.clone(),
-            CallableDefId::StructId(s) => self.0.struct_signature(s).name.clone(),
-            CallableDefId::EnumVariantId(e) => {
-                let loc = e.lookup(self.0);
-                loc.parent.enum_variants(self.0).variants[loc.index as usize].1.clone()
-            }
-        };
-        match def {
-            CallableDefId::FunctionId(_) => {
-                write!(fmt, "{{fn {}}}", name.display(self.0, Edition::LATEST))
-            }
-            CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {
-                write!(fmt, "{{ctor {}}}", name.display(self.0, Edition::LATEST))
-            }
-        }
-    }
-}
-
-mod unsafe_tls {
-    use super::DebugContext;
-    use crate::db::HirDatabase;
-    use scoped_tls::scoped_thread_local;
-
-    scoped_thread_local!(static PROGRAM: DebugContext<'_>);
-
-    pub(crate) fn with_current_program<R>(
-        op: impl for<'a> FnOnce(Option<&'a DebugContext<'a>>) -> R,
-    ) -> R {
-        if PROGRAM.is_set() { PROGRAM.with(|prog| op(Some(prog))) } else { op(None) }
-    }
-
-    #[allow(dead_code)]
-    pub(crate) fn set_current_program<OP, R>(p: &dyn HirDatabase, op: OP) -> R
-    where
-        OP: FnOnce() -> R,
-    {
-        let ctx = DebugContext(p);
-        // we're transmuting the lifetime in the DebugContext to static. This is
-        // fine because we only keep the reference for the lifetime of this
-        // function, *and* the only way to access the context is through
-        // `with_current_program`, which hides the lifetime through the `for`
-        // type.
-        let static_p: &DebugContext<'static> =
-            unsafe { std::mem::transmute::<&DebugContext<'_>, &DebugContext<'static>>(&ctx) };
-        PROGRAM.set(static_p, op)
-    }
-}
diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs
index cd125f3..7f6d4ff 100644
--- a/crates/hir-ty/src/traits.rs
+++ b/crates/hir-ty/src/traits.rs
@@ -3,35 +3,26 @@
 use core::fmt;
 use std::hash::Hash;
 
-use chalk_ir::{DebruijnIndex, GoalData, fold::TypeFoldable};
-
 use base_db::Crate;
 use hir_def::{BlockId, TraitId, lang_item::LangItem};
 use hir_expand::name::Name;
 use intern::sym;
 use rustc_next_trait_solver::solve::{HasChanged, SolverDelegateEvalExt};
 use rustc_type_ir::{
-    InferCtxtLike, TypingMode,
-    inherent::{IntoKind, SliceLike, Span as _, Ty as _},
+    TypingMode,
+    inherent::{IntoKind, Span as _},
     solve::Certainty,
 };
-use span::Edition;
-use stdx::never;
 use triomphe::Arc;
 
 use crate::{
-    AliasEq, AliasTy, Canonical, DomainGoal, Goal, InEnvironment, Interner, ProjectionTy,
-    ProjectionTyExt, TraitRefExt, Ty, TyKind, TypeFlags, WhereClause,
     db::HirDatabase,
-    from_assoc_type_id,
     next_solver::{
-        DbInterner, GenericArg, ParamEnv, Predicate, SolverContext, Span,
+        Canonical, DbInterner, GenericArgs, Goal, ParamEnv, Predicate, SolverContext, Span, Ty,
+        TyKind,
         infer::{DbInternerInferExt, InferCtxt, traits::ObligationCause},
-        mapping::{ChalkToNextSolver, NextSolverToChalk, convert_canonical_args_for_result},
         obligation_ctxt::ObligationCtxt,
-        util::mini_canonicalize,
     },
-    utils::UnevaluatedConstEvaluatorFolder,
 };
 
 /// A set of clauses that we assume to be true. E.g. if we are inside this function:
@@ -44,7 +35,7 @@
     pub krate: Crate,
     pub block: Option<BlockId>,
     // FIXME make this a BTreeMap
-    traits_from_clauses: Box<[(crate::next_solver::Ty<'db>, TraitId)]>,
+    traits_from_clauses: Box<[(Ty<'db>, TraitId)]>,
     pub env: ParamEnv<'db>,
 }
 
@@ -61,7 +52,7 @@
     pub fn new(
         krate: Crate,
         block: Option<BlockId>,
-        traits_from_clauses: Box<[(crate::next_solver::Ty<'db>, TraitId)]>,
+        traits_from_clauses: Box<[(Ty<'db>, TraitId)]>,
         env: ParamEnv<'db>,
     ) -> Arc<Self> {
         Arc::new(TraitEnvironment { krate, block, traits_from_clauses, env })
@@ -72,10 +63,7 @@
         Arc::make_mut(this).block = Some(block);
     }
 
-    pub fn traits_in_scope_from_clauses(
-        &self,
-        ty: crate::next_solver::Ty<'db>,
-    ) -> impl Iterator<Item = TraitId> + '_ {
+    pub fn traits_in_scope_from_clauses(&self, ty: Ty<'db>) -> impl Iterator<Item = TraitId> + '_ {
         self.traits_from_clauses
             .iter()
             .filter_map(move |(self_ty, trait_id)| (*self_ty == ty).then_some(*trait_id))
@@ -85,172 +73,19 @@
 /// This should be used in `hir` only.
 pub fn structurally_normalize_ty<'db>(
     infcx: &InferCtxt<'db>,
-    ty: crate::next_solver::Ty<'db>,
+    ty: Ty<'db>,
     env: Arc<TraitEnvironment<'db>>,
-) -> crate::next_solver::Ty<'db> {
-    let crate::next_solver::TyKind::Alias(..) = ty.kind() else { return ty };
+) -> Ty<'db> {
+    let TyKind::Alias(..) = ty.kind() else { return ty };
     let mut ocx = ObligationCtxt::new(infcx);
     let ty = ocx.structurally_normalize_ty(&ObligationCause::dummy(), env.env, ty).unwrap_or(ty);
     ty.replace_infer_with_error(infcx.interner)
 }
 
-pub(crate) fn normalize_projection_query<'db>(
-    db: &'db dyn HirDatabase,
-    projection: ProjectionTy,
-    env: Arc<TraitEnvironment<'db>>,
-) -> Ty {
-    if projection.substitution.iter(Interner).any(|arg| {
-        arg.ty(Interner)
-            .is_some_and(|ty| ty.data(Interner).flags.intersects(TypeFlags::HAS_TY_INFER))
-    }) {
-        never!(
-            "Invoking `normalize_projection_query` with a projection type containing inference var"
-        );
-        return TyKind::Error.intern(Interner);
-    }
-
-    let interner = DbInterner::new_with(db, Some(env.krate), env.block);
-    // FIXME(next-solver): I believe this should use `PostAnalysis` (this is only used for IDE things),
-    // but this causes some bug because of our incorrect impl of `type_of_opaque_hir_typeck()` for TAIT
-    // and async blocks.
-    let infcx = interner.infer_ctxt().build(TypingMode::Analysis {
-        defining_opaque_types_and_generators: crate::next_solver::SolverDefIds::new_from_iter(
-            interner,
-            [],
-        ),
-    });
-    let alias_ty = crate::next_solver::Ty::new_alias(
-        interner,
-        rustc_type_ir::AliasTyKind::Projection,
-        crate::next_solver::AliasTy::new(
-            interner,
-            from_assoc_type_id(projection.associated_ty_id).into(),
-            <crate::Substitution as ChalkToNextSolver<crate::next_solver::GenericArgs<'_>>>::to_nextsolver(&projection.substitution, interner),
-        ),
-    );
-    let mut ctxt = crate::next_solver::obligation_ctxt::ObligationCtxt::new(&infcx);
-    let normalized = ctxt
-        .structurally_normalize_ty(&ObligationCause::dummy(), env.env, alias_ty)
-        .unwrap_or(alias_ty);
-    normalized.replace_infer_with_error(interner).to_chalk(interner)
-}
-
-fn identity_subst(
-    binders: chalk_ir::CanonicalVarKinds<Interner>,
-) -> chalk_ir::Canonical<chalk_ir::Substitution<Interner>> {
-    let identity_subst = chalk_ir::Substitution::from_iter(
-        Interner,
-        binders.iter(Interner).enumerate().map(|(index, c)| {
-            let index_db = chalk_ir::BoundVar::new(DebruijnIndex::INNERMOST, index);
-            match &c.kind {
-                chalk_ir::VariableKind::Ty(_) => {
-                    chalk_ir::GenericArgData::Ty(TyKind::BoundVar(index_db).intern(Interner))
-                        .intern(Interner)
-                }
-                chalk_ir::VariableKind::Lifetime => chalk_ir::GenericArgData::Lifetime(
-                    chalk_ir::LifetimeData::BoundVar(index_db).intern(Interner),
-                )
-                .intern(Interner),
-                chalk_ir::VariableKind::Const(ty) => chalk_ir::GenericArgData::Const(
-                    chalk_ir::ConstData {
-                        ty: ty.clone(),
-                        value: chalk_ir::ConstValue::BoundVar(index_db),
-                    }
-                    .intern(Interner),
-                )
-                .intern(Interner),
-            }
-        }),
-    );
-    chalk_ir::Canonical { binders, value: identity_subst }
-}
-
-/// Solve a trait goal using next trait solver.
-pub(crate) fn trait_solve_query(
-    db: &dyn HirDatabase,
-    krate: Crate,
-    block: Option<BlockId>,
-    goal: Canonical<InEnvironment<Goal>>,
-) -> NextTraitSolveResult {
-    let _p = tracing::info_span!("trait_solve_query", detail = ?match &goal.value.goal.data(Interner) {
-        GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => db
-            .trait_signature(it.hir_trait_id())
-            .name
-            .display(db, Edition::LATEST)
-            .to_string(),
-        GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_owned(),
-        _ => "??".to_owned(),
-    })
-    .entered();
-
-    if let GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
-        alias: AliasTy::Projection(projection_ty),
-        ..
-    }))) = &goal.value.goal.data(Interner)
-        && let TyKind::BoundVar(_) = projection_ty.self_type_parameter(db).kind(Interner)
-    {
-        // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
-        return NextTraitSolveResult::Uncertain(identity_subst(goal.binders.clone()));
-    }
-
-    // Chalk see `UnevaluatedConst` as a unique concrete value, but we see it as an alias for another const. So
-    // we should get rid of it when talking to chalk.
-    let goal = goal
-        .try_fold_with(&mut UnevaluatedConstEvaluatorFolder { db }, DebruijnIndex::INNERMOST)
-        .unwrap();
-
-    // We currently don't deal with universes (I think / hope they're not yet
-    // relevant for our use cases?)
-    next_trait_solve(db, krate, block, goal)
-}
-
-fn solve_nextsolver<'db>(
-    db: &'db dyn HirDatabase,
-    krate: Crate,
-    block: Option<BlockId>,
-    goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>>,
-) -> Result<
-    (HasChanged, Certainty, rustc_type_ir::Canonical<DbInterner<'db>, Vec<GenericArg<'db>>>),
-    rustc_type_ir::solve::NoSolution,
-> {
-    // FIXME: should use analysis_in_body, but that needs GenericDefId::Block
-    let context = SolverContext(
-        DbInterner::new_with(db, Some(krate), block)
-            .infer_ctxt()
-            .build(TypingMode::non_body_analysis()),
-    );
-
-    match goal.canonical.value.goal.data(Interner) {
-        // FIXME: args here should be...what? not empty
-        GoalData::All(goals) if goals.is_empty(Interner) => {
-            return Ok((HasChanged::No, Certainty::Yes, mini_canonicalize(context, vec![])));
-        }
-        _ => {}
-    }
-
-    let goal = goal.canonical.to_nextsolver(context.cx());
-    tracing::info!(?goal);
-
-    let (goal, var_values) = context.instantiate_canonical(&goal);
-    tracing::info!(?var_values);
-
-    let res = context.evaluate_root_goal(goal, Span::dummy(), None);
-
-    let vars =
-        var_values.var_values.iter().map(|g| context.0.resolve_vars_if_possible(g)).collect();
-    let canonical_var_values = mini_canonicalize(context, vars);
-
-    let res = res.map(|r| (r.has_changed, r.certainty, canonical_var_values));
-
-    tracing::debug!("solve_nextsolver({:?}) => {:?}", goal, res);
-
-    res
-}
-
 #[derive(Clone, Debug, PartialEq)]
 pub enum NextTraitSolveResult {
-    Certain(chalk_ir::Canonical<chalk_ir::ConstrainedSubst<Interner>>),
-    Uncertain(chalk_ir::Canonical<chalk_ir::Substitution<Interner>>),
+    Certain,
+    Uncertain,
     NoSolution,
 }
 
@@ -260,75 +95,17 @@
     }
 
     pub fn certain(&self) -> bool {
-        matches!(self, NextTraitSolveResult::Certain(..))
+        matches!(self, NextTraitSolveResult::Certain)
     }
 
     pub fn uncertain(&self) -> bool {
-        matches!(self, NextTraitSolveResult::Uncertain(..))
-    }
-}
-
-pub fn next_trait_solve(
-    db: &dyn HirDatabase,
-    krate: Crate,
-    block: Option<BlockId>,
-    goal: Canonical<InEnvironment<Goal>>,
-) -> NextTraitSolveResult {
-    let detail = match &goal.value.goal.data(Interner) {
-        GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => {
-            db.trait_signature(it.hir_trait_id()).name.display(db, Edition::LATEST).to_string()
-        }
-        GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_owned(),
-        _ => "??".to_owned(),
-    };
-    let _p = tracing::info_span!("next_trait_solve", ?detail).entered();
-    tracing::info!("next_trait_solve({:?})", goal.value.goal);
-
-    if let GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
-        alias: AliasTy::Projection(projection_ty),
-        ..
-    }))) = &goal.value.goal.data(Interner)
-        && let TyKind::BoundVar(_) = projection_ty.self_type_parameter(db).kind(Interner)
-    {
-        // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
-        // FIXME
-        return NextTraitSolveResult::Uncertain(identity_subst(goal.binders.clone()));
-    }
-
-    // Chalk see `UnevaluatedConst` as a unique concrete value, but we see it as an alias for another const. So
-    // we should get rid of it when talking to chalk.
-    let goal = goal
-        .try_fold_with(&mut UnevaluatedConstEvaluatorFolder { db }, DebruijnIndex::INNERMOST)
-        .unwrap();
-
-    // We currently don't deal with universes (I think / hope they're not yet
-    // relevant for our use cases?)
-    let u_canonical = chalk_ir::UCanonical { canonical: goal, universes: 1 };
-    tracing::info!(?u_canonical);
-
-    let next_solver_res = solve_nextsolver(db, krate, block, &u_canonical);
-
-    match next_solver_res {
-        Err(_) => NextTraitSolveResult::NoSolution,
-        Ok((_, Certainty::Yes, args)) => NextTraitSolveResult::Certain(
-            convert_canonical_args_for_result(DbInterner::new_with(db, Some(krate), block), args),
-        ),
-        Ok((_, Certainty::Maybe { .. }, args)) => {
-            let subst = convert_canonical_args_for_result(
-                DbInterner::new_with(db, Some(krate), block),
-                args,
-            );
-            NextTraitSolveResult::Uncertain(chalk_ir::Canonical {
-                binders: subst.binders,
-                value: subst.value.subst,
-            })
-        }
+        matches!(self, NextTraitSolveResult::Uncertain)
     }
 }
 
 pub fn next_trait_solve_canonical_in_ctxt<'db>(
     infer_ctxt: &InferCtxt<'db>,
-    goal: crate::next_solver::Canonical<'db, crate::next_solver::Goal<'db, Predicate<'db>>>,
+    goal: Canonical<'db, Goal<'db, Predicate<'db>>>,
 ) -> NextTraitSolveResult {
     let context = SolverContext(infer_ctxt.clone());
 
@@ -339,33 +116,21 @@
 
     let res = context.evaluate_root_goal(goal, Span::dummy(), None);
 
-    let vars =
-        var_values.var_values.iter().map(|g| context.0.resolve_vars_if_possible(g)).collect();
-    let canonical_var_values = mini_canonicalize(context, vars);
-
-    let res = res.map(|r| (r.has_changed, r.certainty, canonical_var_values));
+    let res = res.map(|r| (r.has_changed, r.certainty));
 
     tracing::debug!("solve_nextsolver({:?}) => {:?}", goal, res);
 
     match res {
         Err(_) => NextTraitSolveResult::NoSolution,
-        Ok((_, Certainty::Yes, args)) => NextTraitSolveResult::Certain(
-            convert_canonical_args_for_result(infer_ctxt.interner, args),
-        ),
-        Ok((_, Certainty::Maybe { .. }, args)) => {
-            let subst = convert_canonical_args_for_result(infer_ctxt.interner, args);
-            NextTraitSolveResult::Uncertain(chalk_ir::Canonical {
-                binders: subst.binders,
-                value: subst.value.subst,
-            })
-        }
+        Ok((_, Certainty::Yes)) => NextTraitSolveResult::Certain,
+        Ok((_, Certainty::Maybe { .. })) => NextTraitSolveResult::Uncertain,
     }
 }
 
 /// Solve a trait goal using next trait solver.
 pub fn next_trait_solve_in_ctxt<'db, 'a>(
     infer_ctxt: &'a InferCtxt<'db>,
-    goal: crate::next_solver::Goal<'db, crate::next_solver::Predicate<'db>>,
+    goal: Goal<'db, Predicate<'db>>,
 ) -> Result<(HasChanged, Certainty), rustc_type_ir::solve::NoSolution> {
     tracing::info!(?goal);
 
@@ -459,7 +224,7 @@
 
 /// This should not be used in `hir-ty`, only in `hir`.
 pub fn implements_trait_unique<'db>(
-    ty: crate::next_solver::Ty<'db>,
+    ty: Ty<'db>,
     db: &'db dyn HirDatabase,
     env: Arc<TraitEnvironment<'db>>,
     trait_: TraitId,
@@ -474,7 +239,7 @@
     db: &'db dyn HirDatabase,
     env: Arc<TraitEnvironment<'db>>,
     trait_: TraitId,
-    args: crate::next_solver::GenericArgs<'db>,
+    args: GenericArgs<'db>,
 ) -> bool {
     implements_trait_unique_impl(db, env, trait_, &mut |_| args)
 }
@@ -483,7 +248,7 @@
     db: &'db dyn HirDatabase,
     env: Arc<TraitEnvironment<'db>>,
     trait_: TraitId,
-    create_args: &mut dyn FnMut(&InferCtxt<'db>) -> crate::next_solver::GenericArgs<'db>,
+    create_args: &mut dyn FnMut(&InferCtxt<'db>) -> GenericArgs<'db>,
 ) -> bool {
     let interner = DbInterner::new_with(db, Some(env.krate), env.block);
     // FIXME(next-solver): I believe this should be `PostAnalysis`.
@@ -491,7 +256,7 @@
 
     let args = create_args(&infcx);
     let trait_ref = rustc_type_ir::TraitRef::new_from_args(interner, trait_.into(), args);
-    let goal = crate::next_solver::Goal::new(interner, env.env, trait_ref);
+    let goal = Goal::new(interner, env.env, trait_ref);
 
     let result = crate::traits::next_trait_solve_in_ctxt(&infcx, goal);
     matches!(result, Ok((_, Certainty::Yes)))
diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs
index e989e4c..ca5e33f 100644
--- a/crates/hir-ty/src/utils.rs
+++ b/crates/hir-ty/src/utils.rs
@@ -1,41 +1,30 @@
 //! Helper functions for working with def, which don't need to be a separate
 //! query, but can't be computed directly from `*Data` (ie, which need a `db`).
 
-use std::{cell::LazyCell, iter};
+use std::cell::LazyCell;
 
 use base_db::{
     Crate,
     target::{self, TargetData},
 };
-use chalk_ir::{DebruijnIndex, fold::FallibleTypeFolder};
 use hir_def::{
-    EnumId, EnumVariantId, FunctionId, Lookup, TraitId, TypeAliasId, TypeOrConstParamId,
+    EnumId, EnumVariantId, FunctionId, Lookup, TraitId,
     db::DefDatabase,
     hir::generics::WherePredicate,
     lang_item::LangItem,
     resolver::{HasResolver, TypeNs},
     type_ref::{TraitBoundModifier, TypeRef},
 };
-use hir_expand::name::Name;
 use intern::sym;
 use rustc_abi::TargetDataLayout;
-use rustc_hash::FxHashSet;
-use rustc_type_ir::inherent::{IntoKind, SliceLike};
 use smallvec::{SmallVec, smallvec};
 use span::Edition;
 
 use crate::{
-    ChalkTraitId, Const, ConstScalar, Interner, Substitution, TargetFeatures, TraitRef,
-    TraitRefExt, Ty,
-    consteval::unknown_const,
+    TargetFeatures,
     db::HirDatabase,
     layout::{Layout, TagEncoding},
     mir::pad16,
-    next_solver::{
-        DbInterner,
-        mapping::{ChalkToNextSolver, NextSolverToChalk, convert_args_for_result},
-    },
-    to_chalk_trait_id,
 };
 
 pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: Crate) -> impl Iterator<Item = TraitId> + '_ {
@@ -76,49 +65,6 @@
     result
 }
 
-/// Given a trait ref (`Self: Trait`), builds all the implied trait refs for
-/// super traits. The original trait ref will be included. So the difference to
-/// `all_super_traits` is that we keep track of type parameters; for example if
-/// we have `Self: Trait<u32, i32>` and `Trait<T, U>: OtherTrait<U>` we'll get
-/// `Self: OtherTrait<i32>`.
-pub(super) fn all_super_trait_refs<T>(
-    db: &dyn HirDatabase,
-    trait_ref: TraitRef,
-    cb: impl FnMut(TraitRef) -> Option<T>,
-) -> Option<T> {
-    let seen = iter::once(trait_ref.trait_id).collect();
-    SuperTraits { db, seen, stack: vec![trait_ref] }.find_map(cb)
-}
-
-struct SuperTraits<'a> {
-    db: &'a dyn HirDatabase,
-    stack: Vec<TraitRef>,
-    seen: FxHashSet<ChalkTraitId>,
-}
-
-impl SuperTraits<'_> {
-    fn elaborate(&mut self, trait_ref: &TraitRef) {
-        direct_super_trait_refs(self.db, trait_ref, |trait_ref| {
-            if !self.seen.contains(&trait_ref.trait_id) {
-                self.stack.push(trait_ref);
-            }
-        });
-    }
-}
-
-impl Iterator for SuperTraits<'_> {
-    type Item = TraitRef;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        if let Some(next) = self.stack.pop() {
-            self.elaborate(&next);
-            Some(next)
-        } else {
-            None
-        }
-    }
-}
-
 fn direct_super_traits_cb(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) {
     let resolver = LazyCell::new(|| trait_.resolver(db));
     let (generic_params, store) = db.generic_params_and_store(trait_.into());
@@ -149,62 +95,6 @@
         .for_each(cb);
 }
 
-fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef, cb: impl FnMut(TraitRef)) {
-    let interner = DbInterner::new_with(db, None, None);
-    let generic_params = db.generic_params(trait_ref.hir_trait_id().into());
-    let trait_self = match generic_params.trait_self_param() {
-        Some(p) => TypeOrConstParamId { parent: trait_ref.hir_trait_id().into(), local_id: p },
-        None => return,
-    };
-    let trait_ref_args: crate::next_solver::GenericArgs<'_> =
-        trait_ref.substitution.to_nextsolver(interner);
-    db.generic_predicates_for_param_ns(trait_self.parent, trait_self, None)
-        .iter()
-        .filter_map(|pred| {
-            let pred = pred.kind();
-            // FIXME: how to correctly handle higher-ranked bounds here?
-            let pred = pred.no_bound_vars().expect("FIXME unexpected higher-ranked trait bound");
-            match pred {
-                rustc_type_ir::ClauseKind::Trait(t) => {
-                    let t =
-                        rustc_type_ir::EarlyBinder::bind(t).instantiate(interner, trait_ref_args);
-                    let trait_id = to_chalk_trait_id(t.def_id().0);
-
-                    let substitution =
-                        convert_args_for_result(interner, t.trait_ref.args.as_slice());
-                    let tr = chalk_ir::TraitRef { trait_id, substitution };
-                    Some(tr)
-                }
-                _ => None,
-            }
-        })
-        .for_each(cb);
-}
-
-pub(super) fn associated_type_by_name_including_super_traits(
-    db: &dyn HirDatabase,
-    trait_ref: TraitRef,
-    name: &Name,
-) -> Option<(TraitRef, TypeAliasId)> {
-    all_super_trait_refs(db, trait_ref, |t| {
-        let assoc_type = t.hir_trait_id().trait_items(db).associated_type_by_name(name)?;
-        Some((t, assoc_type))
-    })
-}
-
-pub(crate) struct ClosureSubst<'a>(pub(crate) &'a Substitution);
-
-impl<'a> ClosureSubst<'a> {
-    pub(crate) fn sig_ty(&self, db: &dyn HirDatabase) -> Ty {
-        let interner = DbInterner::new_with(db, None, None);
-        let subst =
-            <Substitution as ChalkToNextSolver<crate::next_solver::GenericArgs<'_>>>::to_nextsolver(
-                self.0, interner,
-            );
-        subst.split_closure_args_untupled().closure_sig_as_fn_ptr_ty.to_chalk(interner)
-    }
-}
-
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 pub enum Unsafety {
     Safe,
@@ -277,41 +167,6 @@
     }
 }
 
-pub(crate) struct UnevaluatedConstEvaluatorFolder<'a> {
-    pub(crate) db: &'a dyn HirDatabase,
-}
-
-impl FallibleTypeFolder<Interner> for UnevaluatedConstEvaluatorFolder<'_> {
-    type Error = ();
-
-    fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder<Interner, Error = ()> {
-        self
-    }
-
-    fn interner(&self) -> Interner {
-        Interner
-    }
-
-    fn try_fold_const(
-        &mut self,
-        constant: Const,
-        _outer_binder: DebruijnIndex,
-    ) -> Result<Const, Self::Error> {
-        if let chalk_ir::ConstValue::Concrete(c) = &constant.data(Interner).value
-            && let ConstScalar::UnevaluatedConst(id, subst) = &c.interned
-        {
-            let interner = DbInterner::conjure();
-            if let Ok(eval) = self.db.const_eval(*id, subst.to_nextsolver(interner), None) {
-                return Ok(eval.to_chalk(interner));
-            } else {
-                return Ok(unknown_const(constant.data(Interner).ty.to_nextsolver(interner))
-                    .to_chalk(interner));
-            }
-        }
-        Ok(constant)
-    }
-}
-
 pub(crate) fn detect_variant_from_bytes<'a>(
     layout: &'a Layout,
     db: &dyn HirDatabase,
diff --git a/crates/hir-ty/src/variance.rs b/crates/hir-ty/src/variance.rs
index 0ff1101..b57bf03 100644
--- a/crates/hir-ty/src/variance.rs
+++ b/crates/hir-ty/src/variance.rs
@@ -13,43 +13,45 @@
 //! by the next salsa version. If not, we will likely have to adapt and go with the rustc approach
 //! while installing firewall per item queries to prevent invalidation issues.
 
-use crate::db::HirDatabase;
-use crate::generics::{Generics, generics};
-use crate::next_solver::DbInterner;
-use crate::next_solver::mapping::{ChalkToNextSolver, NextSolverToChalk};
-use crate::{
-    AliasTy, Const, ConstScalar, DynTyExt, GenericArg, GenericArgData, Interner, Lifetime,
-    LifetimeData, Ty, TyKind,
+use hir_def::{AdtId, GenericDefId, GenericParamId, VariantId, signatures::StructFlags};
+use rustc_ast_ir::Mutability;
+use rustc_type_ir::{
+    Variance,
+    inherent::{AdtDef, IntoKind, SliceLike},
 };
-use chalk_ir::Mutability;
-use hir_def::signatures::StructFlags;
-use hir_def::{AdtId, GenericDefId, GenericParamId, VariantId};
-use std::fmt;
-use std::ops::Not;
 use stdx::never;
-use triomphe::Arc;
 
-pub(crate) fn variances_of(db: &dyn HirDatabase, def: GenericDefId) -> Option<Arc<[Variance]>> {
+use crate::{
+    db::HirDatabase,
+    generics::{Generics, generics},
+    next_solver::{
+        Const, ConstKind, DbInterner, ExistentialPredicate, GenericArg, GenericArgs, Region,
+        RegionKind, Term, Ty, TyKind, VariancesOf,
+    },
+};
+
+pub(crate) fn variances_of(db: &dyn HirDatabase, def: GenericDefId) -> VariancesOf<'_> {
     tracing::debug!("variances_of(def={:?})", def);
+    let interner = DbInterner::new_with(db, None, None);
     match def {
         GenericDefId::FunctionId(_) => (),
         GenericDefId::AdtId(adt) => {
             if let AdtId::StructId(id) = adt {
                 let flags = &db.struct_signature(id).flags;
                 if flags.contains(StructFlags::IS_UNSAFE_CELL) {
-                    return Some(Arc::from_iter(vec![Variance::Invariant; 1]));
+                    return VariancesOf::new_from_iter(interner, [Variance::Invariant]);
                 } else if flags.contains(StructFlags::IS_PHANTOM_DATA) {
-                    return Some(Arc::from_iter(vec![Variance::Covariant; 1]));
+                    return VariancesOf::new_from_iter(interner, [Variance::Covariant]);
                 }
             }
         }
-        _ => return None,
+        _ => return VariancesOf::new_from_iter(interner, []),
     }
 
     let generics = generics(db, def);
     let count = generics.len();
     if count == 0 {
-        return None;
+        return VariancesOf::new_from_iter(interner, []);
     }
     let mut variances =
         Context { generics, variances: vec![Variance::Bivariant; count], db }.solve();
@@ -69,7 +71,7 @@
         }
     }
 
-    variances.is_empty().not().then(|| Arc::from_iter(variances))
+    VariancesOf::new_from_iter(interner, variances)
 }
 
 // pub(crate) fn variances_of_cycle_fn(
@@ -81,130 +83,36 @@
 //     salsa::CycleRecoveryAction::Iterate
 // }
 
+fn glb(v1: Variance, v2: Variance) -> Variance {
+    // Greatest lower bound of the variance lattice as defined in The Paper:
+    //
+    //       *
+    //    -     +
+    //       o
+    match (v1, v2) {
+        (Variance::Invariant, _) | (_, Variance::Invariant) => Variance::Invariant,
+
+        (Variance::Covariant, Variance::Contravariant) => Variance::Invariant,
+        (Variance::Contravariant, Variance::Covariant) => Variance::Invariant,
+
+        (Variance::Covariant, Variance::Covariant) => Variance::Covariant,
+
+        (Variance::Contravariant, Variance::Contravariant) => Variance::Contravariant,
+
+        (x, Variance::Bivariant) | (Variance::Bivariant, x) => x,
+    }
+}
+
 pub(crate) fn variances_of_cycle_initial(
     db: &dyn HirDatabase,
     def: GenericDefId,
-) -> Option<Arc<[Variance]>> {
+) -> VariancesOf<'_> {
+    let interner = DbInterner::new_with(db, None, None);
     let generics = generics(db, def);
     let count = generics.len();
 
-    if count == 0 {
-        return None;
-    }
     // FIXME(next-solver): Returns `Invariance` and not `Bivariance` here, see the comment in the main query.
-    Some(Arc::from(vec![Variance::Invariant; count]))
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
-pub enum Variance {
-    Covariant,     // T<A> <: T<B> iff A <: B -- e.g., function return type
-    Invariant,     // T<A> <: T<B> iff B == A -- e.g., type of mutable cell
-    Contravariant, // T<A> <: T<B> iff B <: A -- e.g., function param type
-    Bivariant,     // T<A> <: T<B>            -- e.g., unused type parameter
-}
-
-impl fmt::Display for Variance {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            Variance::Covariant => write!(f, "covariant"),
-            Variance::Invariant => write!(f, "invariant"),
-            Variance::Contravariant => write!(f, "contravariant"),
-            Variance::Bivariant => write!(f, "bivariant"),
-        }
-    }
-}
-
-impl Variance {
-    /// `a.xform(b)` combines the variance of a context with the
-    /// variance of a type with the following meaning. If we are in a
-    /// context with variance `a`, and we encounter a type argument in
-    /// a position with variance `b`, then `a.xform(b)` is the new
-    /// variance with which the argument appears.
-    ///
-    /// Example 1:
-    /// ```ignore (illustrative)
-    /// *mut Vec<i32>
-    /// ```
-    /// Here, the "ambient" variance starts as covariant. `*mut T` is
-    /// invariant with respect to `T`, so the variance in which the
-    /// `Vec<i32>` appears is `Covariant.xform(Invariant)`, which
-    /// yields `Invariant`. Now, the type `Vec<T>` is covariant with
-    /// respect to its type argument `T`, and hence the variance of
-    /// the `i32` here is `Invariant.xform(Covariant)`, which results
-    /// (again) in `Invariant`.
-    ///
-    /// Example 2:
-    /// ```ignore (illustrative)
-    /// fn(*const Vec<i32>, *mut Vec<i32)
-    /// ```
-    /// The ambient variance is covariant. A `fn` type is
-    /// contravariant with respect to its parameters, so the variance
-    /// within which both pointer types appear is
-    /// `Covariant.xform(Contravariant)`, or `Contravariant`. `*const
-    /// T` is covariant with respect to `T`, so the variance within
-    /// which the first `Vec<i32>` appears is
-    /// `Contravariant.xform(Covariant)` or `Contravariant`. The same
-    /// is true for its `i32` argument. In the `*mut T` case, the
-    /// variance of `Vec<i32>` is `Contravariant.xform(Invariant)`,
-    /// and hence the outermost type is `Invariant` with respect to
-    /// `Vec<i32>` (and its `i32` argument).
-    ///
-    /// Source: Figure 1 of "Taming the Wildcards:
-    /// Combining Definition- and Use-Site Variance" published in PLDI'11.
-    fn xform(self, v: Variance) -> Variance {
-        match (self, v) {
-            // Figure 1, column 1.
-            (Variance::Covariant, Variance::Covariant) => Variance::Covariant,
-            (Variance::Covariant, Variance::Contravariant) => Variance::Contravariant,
-            (Variance::Covariant, Variance::Invariant) => Variance::Invariant,
-            (Variance::Covariant, Variance::Bivariant) => Variance::Bivariant,
-
-            // Figure 1, column 2.
-            (Variance::Contravariant, Variance::Covariant) => Variance::Contravariant,
-            (Variance::Contravariant, Variance::Contravariant) => Variance::Covariant,
-            (Variance::Contravariant, Variance::Invariant) => Variance::Invariant,
-            (Variance::Contravariant, Variance::Bivariant) => Variance::Bivariant,
-
-            // Figure 1, column 3.
-            (Variance::Invariant, _) => Variance::Invariant,
-
-            // Figure 1, column 4.
-            (Variance::Bivariant, _) => Variance::Bivariant,
-        }
-    }
-
-    fn glb(self, v: Variance) -> Variance {
-        // Greatest lower bound of the variance lattice as
-        // defined in The Paper:
-        //
-        //       *
-        //    -     +
-        //       o
-        match (self, v) {
-            (Variance::Invariant, _) | (_, Variance::Invariant) => Variance::Invariant,
-
-            (Variance::Covariant, Variance::Contravariant) => Variance::Invariant,
-            (Variance::Contravariant, Variance::Covariant) => Variance::Invariant,
-
-            (Variance::Covariant, Variance::Covariant) => Variance::Covariant,
-
-            (Variance::Contravariant, Variance::Contravariant) => Variance::Contravariant,
-
-            (x, Variance::Bivariant) | (Variance::Bivariant, x) => x,
-        }
-    }
-
-    pub fn invariant(self) -> Self {
-        self.xform(Variance::Invariant)
-    }
-
-    pub fn covariant(self) -> Self {
-        self.xform(Variance::Covariant)
-    }
-
-    pub fn contravariant(self) -> Self {
-        self.xform(Variance::Contravariant)
-    }
+    VariancesOf::new_from_iter(interner, std::iter::repeat_n(Variance::Invariant, count))
 }
 
 struct Context<'db> {
@@ -213,17 +121,16 @@
     variances: Vec<Variance>,
 }
 
-impl Context<'_> {
+impl<'db> Context<'db> {
     fn solve(mut self) -> Vec<Variance> {
         tracing::debug!("solve(generics={:?})", self.generics);
         match self.generics.def() {
             GenericDefId::AdtId(adt) => {
                 let db = self.db;
                 let mut add_constraints_from_variant = |variant| {
-                    let subst = self.generics.placeholder_subst(db);
                     for (_, field) in db.field_types(variant).iter() {
                         self.add_constraints_from_ty(
-                            &field.clone().substitute(Interner, &subst),
+                            field.instantiate_identity(),
                             Variance::Covariant,
                         );
                     }
@@ -239,16 +146,9 @@
                 }
             }
             GenericDefId::FunctionId(f) => {
-                let subst = self.generics.placeholder_subst(self.db);
-                let interner = DbInterner::new_with(self.db, None, None);
-                let args: crate::next_solver::GenericArgs<'_> = subst.to_nextsolver(interner);
-                let sig = self
-                    .db
-                    .callable_item_signature(f.into())
-                    .instantiate(interner, args)
-                    .skip_binder()
-                    .to_chalk(interner);
-                self.add_constraints_from_sig(sig.params_and_return.iter(), Variance::Covariant);
+                let sig =
+                    self.db.callable_item_signature(f.into()).instantiate_identity().skip_binder();
+                self.add_constraints_from_sig(sig.inputs_and_output.iter(), Variance::Covariant);
             }
             _ => {}
         }
@@ -276,122 +176,102 @@
     /// Adds constraints appropriate for an instance of `ty` appearing
     /// in a context with the generics defined in `generics` and
     /// ambient variance `variance`
-    fn add_constraints_from_ty(&mut self, ty: &Ty, variance: Variance) {
+    fn add_constraints_from_ty(&mut self, ty: Ty<'db>, variance: Variance) {
         tracing::debug!("add_constraints_from_ty(ty={:?}, variance={:?})", ty, variance);
-        match ty.kind(Interner) {
-            TyKind::Scalar(_) | TyKind::Never | TyKind::Str | TyKind::Foreign(..) => {
+        match ty.kind() {
+            TyKind::Int(_)
+            | TyKind::Uint(_)
+            | TyKind::Float(_)
+            | TyKind::Char
+            | TyKind::Bool
+            | TyKind::Never
+            | TyKind::Str
+            | TyKind::Foreign(..) => {
                 // leaf type -- noop
             }
-            TyKind::FnDef(..) | TyKind::Coroutine(..) | TyKind::Closure(..) => {
+            TyKind::FnDef(..)
+            | TyKind::Coroutine(..)
+            | TyKind::CoroutineClosure(..)
+            | TyKind::Closure(..) => {
                 never!("Unexpected unnameable type in variance computation: {:?}", ty);
             }
-            TyKind::Ref(mutbl, lifetime, ty) => {
+            TyKind::Ref(lifetime, ty, mutbl) => {
                 self.add_constraints_from_region(lifetime, variance);
-                self.add_constraints_from_mt(ty, *mutbl, variance);
+                self.add_constraints_from_mt(ty, mutbl, variance);
             }
             TyKind::Array(typ, len) => {
-                self.add_constraints_from_const(len, variance);
+                self.add_constraints_from_const(len);
                 self.add_constraints_from_ty(typ, variance);
             }
             TyKind::Slice(typ) => {
                 self.add_constraints_from_ty(typ, variance);
             }
-            TyKind::Raw(mutbl, ty) => {
-                self.add_constraints_from_mt(ty, *mutbl, variance);
+            TyKind::RawPtr(ty, mutbl) => {
+                self.add_constraints_from_mt(ty, mutbl, variance);
             }
-            TyKind::Tuple(_, subtys) => {
-                for subty in subtys.type_parameters(Interner) {
-                    self.add_constraints_from_ty(&subty, variance);
+            TyKind::Tuple(subtys) => {
+                for subty in subtys {
+                    self.add_constraints_from_ty(subty, variance);
                 }
             }
             TyKind::Adt(def, args) => {
-                self.add_constraints_from_args(def.0.into(), args.as_slice(Interner), variance);
+                self.add_constraints_from_args(def.def_id().0.into(), args, variance);
             }
-            TyKind::Alias(AliasTy::Opaque(opaque)) => {
-                self.add_constraints_from_invariant_args(
-                    opaque.substitution.as_slice(Interner),
-                    variance,
-                );
+            TyKind::Alias(_, alias) => {
+                // FIXME: Probably not correct wrt. opaques.
+                self.add_constraints_from_invariant_args(alias.args);
             }
-            TyKind::Alias(AliasTy::Projection(proj)) => {
-                self.add_constraints_from_invariant_args(
-                    proj.substitution.as_slice(Interner),
-                    variance,
-                );
-            }
-            // FIXME: check this
-            TyKind::AssociatedType(_, subst) => {
-                self.add_constraints_from_invariant_args(subst.as_slice(Interner), variance);
-            }
-            // FIXME: check this
-            TyKind::OpaqueType(_, subst) => {
-                self.add_constraints_from_invariant_args(subst.as_slice(Interner), variance);
-            }
-            TyKind::Dyn(it) => {
+            TyKind::Dynamic(bounds, region) => {
                 // The type `dyn Trait<T> +'a` is covariant w/r/t `'a`:
-                self.add_constraints_from_region(&it.lifetime, variance);
+                self.add_constraints_from_region(region, variance);
 
-                if let Some(trait_ref) = it.principal() {
-                    // Trait are always invariant so we can take advantage of that.
-                    self.add_constraints_from_invariant_args(
-                        trait_ref
-                            .map(|it| it.map(|it| it.substitution.clone()))
-                            .substitute(
-                                Interner,
-                                &[GenericArg::new(
-                                    Interner,
-                                    chalk_ir::GenericArgData::Ty(TyKind::Error.intern(Interner)),
-                                )],
-                            )
-                            .skip_binders()
-                            .as_slice(Interner),
-                        variance,
-                    );
+                for bound in bounds {
+                    match bound.skip_binder() {
+                        ExistentialPredicate::Trait(trait_ref) => {
+                            self.add_constraints_from_invariant_args(trait_ref.args)
+                        }
+                        ExistentialPredicate::Projection(projection) => {
+                            self.add_constraints_from_invariant_args(projection.args);
+                            match projection.term {
+                                Term::Ty(ty) => {
+                                    self.add_constraints_from_ty(ty, Variance::Invariant)
+                                }
+                                Term::Const(konst) => self.add_constraints_from_const(konst),
+                            }
+                        }
+                        ExistentialPredicate::AutoTrait(_) => {}
+                    }
                 }
-
-                // FIXME
-                // for projection in data.projection_bounds() {
-                //     match projection.skip_binder().term.unpack() {
-                //         TyKind::TermKind::Ty(ty) => {
-                //             self.add_constraints_from_ty( ty, self.invariant);
-                //         }
-                //         TyKind::TermKind::Const(c) => {
-                //             self.add_constraints_from_const( c, self.invariant)
-                //         }
-                //     }
-                // }
             }
 
             // Chalk has no params, so use placeholders for now?
-            TyKind::Placeholder(index) => {
-                let idx = crate::from_placeholder_idx(self.db, *index).0;
-                let index = self.generics.type_or_const_param_idx(idx).unwrap();
-                self.constrain(index, variance);
+            TyKind::Param(param) => self.constrain(param.index as usize, variance),
+            TyKind::FnPtr(sig, _) => {
+                self.add_constraints_from_sig(sig.skip_binder().inputs_and_output.iter(), variance);
             }
-            TyKind::Function(f) => {
-                self.add_constraints_from_sig(
-                    f.substitution.0.iter(Interner).filter_map(move |p| p.ty(Interner)),
-                    variance,
-                );
-            }
-            TyKind::Error => {
+            TyKind::Error(_) => {
                 // we encounter this when walking the trait references for object
                 // types, where we use Error as the Self type
             }
-            TyKind::CoroutineWitness(..) | TyKind::BoundVar(..) | TyKind::InferenceVar(..) => {
+            TyKind::Bound(..) => {}
+            TyKind::CoroutineWitness(..)
+            | TyKind::Placeholder(..)
+            | TyKind::Infer(..)
+            | TyKind::UnsafeBinder(..)
+            | TyKind::Pat(..) => {
                 never!("unexpected type encountered in variance inference: {:?}", ty)
             }
         }
     }
 
-    fn add_constraints_from_invariant_args(&mut self, args: &[GenericArg], variance: Variance) {
-        let variance_i = variance.invariant();
-
-        for k in args {
-            match k.data(Interner) {
-                GenericArgData::Lifetime(lt) => self.add_constraints_from_region(lt, variance_i),
-                GenericArgData::Ty(ty) => self.add_constraints_from_ty(ty, variance_i),
-                GenericArgData::Const(val) => self.add_constraints_from_const(val, variance_i),
+    fn add_constraints_from_invariant_args(&mut self, args: GenericArgs<'db>) {
+        for k in args.iter() {
+            match k {
+                GenericArg::Lifetime(lt) => {
+                    self.add_constraints_from_region(lt, Variance::Invariant)
+                }
+                GenericArg::Ty(ty) => self.add_constraints_from_ty(ty, Variance::Invariant),
+                GenericArg::Const(val) => self.add_constraints_from_const(val),
             }
         }
     }
@@ -401,51 +281,40 @@
     fn add_constraints_from_args(
         &mut self,
         def_id: GenericDefId,
-        args: &[GenericArg],
+        args: GenericArgs<'db>,
         variance: Variance,
     ) {
-        // We don't record `inferred_starts` entries for empty generics.
         if args.is_empty() {
             return;
         }
-        let Some(variances) = self.db.variances_of(def_id) else {
-            return;
-        };
+        let variances = self.db.variances_of(def_id);
 
-        for (i, k) in args.iter().enumerate() {
-            match k.data(Interner) {
-                GenericArgData::Lifetime(lt) => {
-                    self.add_constraints_from_region(lt, variance.xform(variances[i]))
-                }
-                GenericArgData::Ty(ty) => {
-                    self.add_constraints_from_ty(ty, variance.xform(variances[i]))
-                }
-                GenericArgData::Const(val) => self.add_constraints_from_const(val, variance),
+        for (k, v) in args.iter().zip(variances) {
+            match k {
+                GenericArg::Lifetime(lt) => self.add_constraints_from_region(lt, variance.xform(v)),
+                GenericArg::Ty(ty) => self.add_constraints_from_ty(ty, variance.xform(v)),
+                GenericArg::Const(val) => self.add_constraints_from_const(val),
             }
         }
     }
 
     /// Adds constraints appropriate for a const expression `val`
     /// in a context with ambient variance `variance`
-    fn add_constraints_from_const(&mut self, c: &Const, variance: Variance) {
-        match &c.data(Interner).value {
-            chalk_ir::ConstValue::Concrete(c) => {
-                if let ConstScalar::UnevaluatedConst(_, subst) = &c.interned {
-                    self.add_constraints_from_invariant_args(subst.as_slice(Interner), variance);
-                }
-            }
+    fn add_constraints_from_const(&mut self, c: Const<'db>) {
+        match c.kind() {
+            ConstKind::Unevaluated(c) => self.add_constraints_from_invariant_args(c.args),
             _ => {}
         }
     }
 
     /// Adds constraints appropriate for a function with signature
     /// `sig` appearing in a context with ambient variance `variance`
-    fn add_constraints_from_sig<'a>(
+    fn add_constraints_from_sig(
         &mut self,
-        mut sig_tys: impl DoubleEndedIterator<Item = &'a Ty>,
+        mut sig_tys: impl DoubleEndedIterator<Item = Ty<'db>>,
         variance: Variance,
     ) {
-        let contra = variance.contravariant();
+        let contra = variance.xform(Variance::Contravariant);
         let Some(output) = sig_tys.next_back() else {
             return never!("function signature has no return type");
         };
@@ -457,27 +326,26 @@
 
     /// Adds constraints appropriate for a region appearing in a
     /// context with ambient variance `variance`
-    fn add_constraints_from_region(&mut self, region: &Lifetime, variance: Variance) {
+    fn add_constraints_from_region(&mut self, region: Region<'db>, variance: Variance) {
         tracing::debug!(
             "add_constraints_from_region(region={:?}, variance={:?})",
             region,
             variance
         );
-        match region.data(Interner) {
-            LifetimeData::Placeholder(index) => {
-                let idx = crate::lt_from_placeholder_idx(self.db, *index).0;
-                let inferred = self.generics.lifetime_idx(idx).unwrap();
-                self.constrain(inferred, variance);
-            }
-            LifetimeData::Static => {}
-            LifetimeData::BoundVar(..) => {
+        match region.kind() {
+            RegionKind::ReEarlyParam(param) => self.constrain(param.index as usize, variance),
+            RegionKind::ReStatic => {}
+            RegionKind::ReBound(..) => {
                 // Either a higher-ranked region inside of a type or a
                 // late-bound function parameter.
                 //
                 // We do not compute constraints for either of these.
             }
-            LifetimeData::Error => {}
-            LifetimeData::Phantom(..) | LifetimeData::InferenceVar(..) | LifetimeData::Erased => {
+            RegionKind::ReError(_) => {}
+            RegionKind::ReLateParam(..)
+            | RegionKind::RePlaceholder(..)
+            | RegionKind::ReVar(..)
+            | RegionKind::ReErased => {
                 // We don't expect to see anything but 'static or bound
                 // regions when visiting member types or method types.
                 never!(
@@ -491,11 +359,11 @@
 
     /// Adds constraints appropriate for a mutability-type pair
     /// appearing in a context with ambient variance `variance`
-    fn add_constraints_from_mt(&mut self, ty: &Ty, mt: Mutability, variance: Variance) {
+    fn add_constraints_from_mt(&mut self, ty: Ty<'db>, mt: Mutability, variance: Variance) {
         self.add_constraints_from_ty(
             ty,
             match mt {
-                Mutability::Mut => variance.invariant(),
+                Mutability::Mut => Variance::Invariant,
                 Mutability::Not => variance,
             },
         );
@@ -508,7 +376,7 @@
             self.variances[index],
             variance
         );
-        self.variances[index] = self.variances[index].glb(variance);
+        self.variances[index] = glb(self.variances[index], variance);
     }
 }
 
@@ -519,6 +387,7 @@
         AdtId, GenericDefId, ModuleDefId, hir::generics::GenericParamDataRef, src::HasSource,
     };
     use itertools::Itertools;
+    use rustc_type_ir::{Variance, inherent::SliceLike};
     use stdx::format_to;
     use syntax::{AstNode, ast::HasName};
     use test_fixture::WithFixture;
@@ -1037,26 +906,21 @@
                                 let loc = it.lookup(&db);
                                 loc.source(&db).value.name().unwrap()
                             }
-                            GenericDefId::TraitId(it) => {
-                                let loc = it.lookup(&db);
-                                loc.source(&db).value.name().unwrap()
-                            }
-                            GenericDefId::TypeAliasId(it) => {
-                                let loc = it.lookup(&db);
-                                loc.source(&db).value.name().unwrap()
-                            }
-                            GenericDefId::ImplId(_) => return None,
-                            GenericDefId::ConstId(_) => return None,
-                            GenericDefId::StaticId(_) => return None,
+                            GenericDefId::TraitId(_)
+                            | GenericDefId::TypeAliasId(_)
+                            | GenericDefId::ImplId(_)
+                            | GenericDefId::ConstId(_)
+                            | GenericDefId::StaticId(_) => return None,
                         },
                     ))
                 })
                 .sorted_by_key(|(_, n)| n.syntax().text_range().start());
             let mut res = String::new();
             for (def, name) in defs {
-                let Some(variances) = db.variances_of(def) else {
+                let variances = db.variances_of(def);
+                if variances.is_empty() {
                     continue;
-                };
+                }
                 format_to!(
                     res,
                     "{name}[{}]\n",
@@ -1072,10 +936,16 @@
                                 &lifetime_param_data.name
                             }
                         })
-                        .zip_eq(&*variances)
+                        .zip_eq(variances)
                         .format_with(", ", |(name, var), f| f(&format_args!(
-                            "{}: {var}",
-                            name.as_str()
+                            "{}: {}",
+                            name.as_str(),
+                            match var {
+                                Variance::Covariant => "covariant",
+                                Variance::Invariant => "invariant",
+                                Variance::Contravariant => "contravariant",
+                                Variance::Bivariant => "bivariant",
+                            },
                         )))
                 );
             }
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index 49bf843..d61c2ec 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -11,14 +11,15 @@
     type_ref::{TypeBound, TypeRef, TypeRefId},
 };
 use hir_ty::{
-    AliasEq, AliasTy, Interner, ProjectionTyExt, TraitRefExt, TyBuilder, TyKind, WhereClause,
     db::HirDatabase,
     display::{
         HirDisplay, HirDisplayError, HirDisplayWithExpressionStore, HirFormatter, SizedByDefault,
         hir_display_with_store, write_bounds_like_dyn_trait_with_prefix, write_visibility,
     },
+    next_solver::ClauseKind,
 };
 use itertools::Itertools;
+use rustc_type_ir::inherent::IntoKind;
 
 use crate::{
     Adt, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Crate, Enum,
@@ -27,8 +28,8 @@
     TypeAlias, TypeNs, TypeOrConstParam, TypeParam, Union, Variant,
 };
 
-impl HirDisplay for Function {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Function {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         let db = f.db;
         let data = db.function_signature(self.id);
         let container = self.as_assoc_item(db).map(|it| it.container(db));
@@ -184,7 +185,10 @@
     }
 }
 
-fn write_impl_header(impl_: &Impl, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+fn write_impl_header<'db>(
+    impl_: &Impl,
+    f: &mut HirFormatter<'_, 'db>,
+) -> Result<(), HirDisplayError> {
     let db = f.db;
 
     f.write_str("impl")?;
@@ -202,8 +206,8 @@
     Ok(())
 }
 
-impl HirDisplay for SelfParam {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for SelfParam {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         let data = f.db.function_signature(self.func);
         let param = *data.params.first().unwrap();
         match &data.store[param] {
@@ -228,8 +232,8 @@
     }
 }
 
-impl HirDisplay for Adt {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Adt {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         match self {
             Adt::Struct(it) => it.hir_fmt(f),
             Adt::Union(it) => it.hir_fmt(f),
@@ -238,8 +242,8 @@
     }
 }
 
-impl HirDisplay for Struct {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Struct {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         let module_id = self.module(f.db).id;
         // FIXME: Render repr if its set explicitly?
         write_visibility(module_id, self.visibility(f.db), f)?;
@@ -279,8 +283,8 @@
     }
 }
 
-impl HirDisplay for Enum {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Enum {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
         f.write_str("enum ")?;
         write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?;
@@ -296,8 +300,8 @@
     }
 }
 
-impl HirDisplay for Union {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Union {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
         f.write_str("union ")?;
         write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?;
@@ -312,12 +316,12 @@
     }
 }
 
-fn write_fields(
+fn write_fields<'db>(
     fields: &[Field],
     has_where_clause: bool,
     limit: usize,
     in_line: bool,
-    f: &mut HirFormatter<'_>,
+    f: &mut HirFormatter<'_, 'db>,
 ) -> Result<(), HirDisplayError> {
     let count = fields.len().min(limit);
     let (indent, separator) = if in_line { ("", ' ') } else { ("    ", '\n') };
@@ -346,11 +350,11 @@
     Ok(())
 }
 
-fn write_variants(
+fn write_variants<'db>(
     variants: &[Variant],
     has_where_clause: bool,
     limit: usize,
-    f: &mut HirFormatter<'_>,
+    f: &mut HirFormatter<'_, 'db>,
 ) -> Result<(), HirDisplayError> {
     let count = variants.len().min(limit);
     f.write_char(if !has_where_clause { ' ' } else { '\n' })?;
@@ -386,23 +390,23 @@
     Ok(())
 }
 
-impl HirDisplay for Field {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Field {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         write_visibility(self.parent.module(f.db).id, self.visibility(f.db), f)?;
         write!(f, "{}: ", self.name(f.db).display(f.db, f.edition()))?;
         self.ty(f.db).hir_fmt(f)
     }
 }
 
-impl HirDisplay for TupleField {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for TupleField {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         write!(f, "pub {}: ", self.name().display(f.db, f.edition()))?;
         self.ty(f.db).hir_fmt(f)
     }
 }
 
-impl HirDisplay for Variant {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Variant {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?;
         let data = self.id.fields(f.db);
         match data.shape {
@@ -431,20 +435,20 @@
     }
 }
 
-impl HirDisplay for Type<'_> {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Type<'db> {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         self.ty.hir_fmt(f)
     }
 }
 
-impl HirDisplay for TypeNs<'_> {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for TypeNs<'db> {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         self.ty.hir_fmt(f)
     }
 }
 
-impl HirDisplay for ExternCrateDecl {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for ExternCrateDecl {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
         f.write_str("extern crate ")?;
         write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?;
@@ -455,8 +459,8 @@
     }
 }
 
-impl HirDisplay for GenericParam {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for GenericParam {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         match self {
             GenericParam::TypeParam(it) => it.hir_fmt(f),
             GenericParam::ConstParam(it) => it.hir_fmt(f),
@@ -465,8 +469,8 @@
     }
 }
 
-impl HirDisplay for TypeOrConstParam {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for TypeOrConstParam {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         match self.split(f.db) {
             either::Either::Left(it) => it.hir_fmt(f),
             either::Either::Right(it) => it.hir_fmt(f),
@@ -474,27 +478,22 @@
     }
 }
 
-impl HirDisplay for TypeParam {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for TypeParam {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         let params = f.db.generic_params(self.id.parent());
         let param_data = &params[self.id.local_id()];
-        let substs = TyBuilder::placeholder_subst(f.db, self.id.parent());
         let krate = self.id.parent().krate(f.db).id;
-        let ty = TyKind::Placeholder(hir_ty::to_placeholder_idx_no_index(f.db, self.id.into()))
-            .intern(Interner);
+        let ty = self.ty(f.db).ty;
         let predicates = f.db.generic_predicates(self.id.parent());
         let predicates = predicates
-            .iter()
-            .cloned()
-            .map(|pred| pred.substitute(Interner, &substs))
-            .filter(|wc| match wc.skip_binders() {
-                WhereClause::Implemented(tr) => tr.self_type_parameter(Interner) == ty,
-                WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(proj), ty: _ }) => {
-                    proj.self_type_parameter(f.db) == ty
-                }
-                WhereClause::AliasEq(_) => false,
-                WhereClause::TypeOutlives(to) => to.ty == ty,
-                WhereClause::LifetimeOutlives(_) => false,
+            .instantiate_identity()
+            .into_iter()
+            .flatten()
+            .filter(|wc| match wc.kind().skip_binder() {
+                ClauseKind::Trait(tr) => tr.self_ty() == ty,
+                ClauseKind::Projection(proj) => proj.self_ty() == ty,
+                ClauseKind::TypeOutlives(to) => to.0 == ty,
+                _ => false,
             })
             .collect::<Vec<_>>();
 
@@ -507,7 +506,7 @@
                     return write_bounds_like_dyn_trait_with_prefix(
                         f,
                         "impl",
-                        Either::Left(&ty),
+                        Either::Left(ty),
                         &predicates,
                         SizedByDefault::Sized { anchor: krate },
                     );
@@ -523,23 +522,18 @@
         }
 
         let sized_trait = LangItem::Sized.resolve_trait(f.db, krate);
-        let has_only_sized_bound = predicates.iter().all(move |pred| match pred.skip_binders() {
-            WhereClause::Implemented(it) => Some(it.hir_trait_id()) == sized_trait,
-            _ => false,
-        });
+        let has_only_sized_bound =
+            predicates.iter().all(move |pred| match pred.kind().skip_binder() {
+                ClauseKind::Trait(it) => Some(it.def_id().0) == sized_trait,
+                _ => false,
+            });
         let has_only_not_sized_bound = predicates.is_empty();
         if !has_only_sized_bound || has_only_not_sized_bound {
             let default_sized = SizedByDefault::Sized { anchor: krate };
             write_bounds_like_dyn_trait_with_prefix(
                 f,
                 ":",
-                Either::Left(
-                    &hir_ty::TyKind::Placeholder(hir_ty::to_placeholder_idx_no_index(
-                        f.db,
-                        self.id.into(),
-                    ))
-                    .intern(Interner),
-                ),
+                Either::Left(ty),
                 &predicates,
                 default_sized,
             )?;
@@ -548,22 +542,22 @@
     }
 }
 
-impl HirDisplay for LifetimeParam {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for LifetimeParam {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         write!(f, "{}", self.name(f.db).display(f.db, f.edition()))
     }
 }
 
-impl HirDisplay for ConstParam {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for ConstParam {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         write!(f, "const {}: ", self.name(f.db).display(f.db, f.edition()))?;
         self.ty(f.db).hir_fmt(f)
     }
 }
 
-fn write_generic_params(
+fn write_generic_params<'db>(
     def: GenericDefId,
-    f: &mut HirFormatter<'_>,
+    f: &mut HirFormatter<'_, 'db>,
 ) -> Result<(), HirDisplayError> {
     let (params, store) = f.db.generic_params_and_store(def);
     if params.iter_lt().next().is_none()
@@ -578,7 +572,7 @@
     f.write_char('<')?;
 
     let mut first = true;
-    let mut delim = |f: &mut HirFormatter<'_>| {
+    let mut delim = |f: &mut HirFormatter<'_, 'db>| {
         if first {
             first = false;
             Ok(())
@@ -622,9 +616,9 @@
     Ok(())
 }
 
-fn write_where_clause(
+fn write_where_clause<'db>(
     def: GenericDefId,
-    f: &mut HirFormatter<'_>,
+    f: &mut HirFormatter<'_, 'db>,
 ) -> Result<bool, HirDisplayError> {
     let (params, store) = f.db.generic_params_and_store(def);
     if !has_disaplayable_predicates(f.db, &params, &store) {
@@ -653,10 +647,10 @@
     })
 }
 
-fn write_where_predicates(
+fn write_where_predicates<'db>(
     params: &GenericParams,
     store: &ExpressionStore,
-    f: &mut HirFormatter<'_>,
+    f: &mut HirFormatter<'_, 'db>,
 ) -> Result<(), HirDisplayError> {
     use WherePredicate::*;
 
@@ -717,8 +711,8 @@
     Ok(())
 }
 
-impl HirDisplay for Const {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Const {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         let db = f.db;
         let container = self.as_assoc_item(db).map(|it| it.container(db));
         let mut module = self.module(db);
@@ -738,8 +732,8 @@
     }
 }
 
-impl HirDisplay for Static {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Static {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
         let data = f.db.static_signature(self.id);
         f.write_str("static ")?;
@@ -752,14 +746,14 @@
     }
 }
 
-impl HirDisplay for TraitRef<'_> {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for TraitRef<'db> {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         self.trait_ref.hir_fmt(f)
     }
 }
 
-impl HirDisplay for Trait {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Trait {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         // FIXME(trait-alias) needs special handling to print the equal sign
         write_trait_header(self, f)?;
         let def_id = GenericDefId::TraitId(self.id);
@@ -798,7 +792,10 @@
     }
 }
 
-fn write_trait_header(trait_: &Trait, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+fn write_trait_header<'db>(
+    trait_: &Trait,
+    f: &mut HirFormatter<'_, 'db>,
+) -> Result<(), HirDisplayError> {
     write_visibility(trait_.module(f.db).id, trait_.visibility(f.db), f)?;
     let data = f.db.trait_signature(trait_.id);
     if data.flags.contains(TraitFlags::UNSAFE) {
@@ -812,8 +809,8 @@
     Ok(())
 }
 
-impl HirDisplay for TypeAlias {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for TypeAlias {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
         let data = f.db.type_alias_signature(self.id);
         write!(f, "type {}", data.name.display(f.db, f.edition()))?;
@@ -835,8 +832,8 @@
     }
 }
 
-impl HirDisplay for Module {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Module {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         match self.parent(f.db) {
             Some(m) => write_visibility(m.id, self.visibility(f.db), f)?,
             None => {
@@ -853,8 +850,8 @@
     }
 }
 
-impl HirDisplay for Crate {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Crate {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         match self.display_name(f.db) {
             Some(name) => write!(f, "extern crate {name}"),
             None => f.write_str("extern crate {unknown}"),
@@ -862,8 +859,8 @@
     }
 }
 
-impl HirDisplay for Macro {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl<'db> HirDisplay<'db> for Macro {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
         match self.id {
             hir_def::MacroId::Macro2Id(_) => f.write_str("macro"),
             hir_def::MacroId::MacroRulesId(_) => f.write_str("macro_rules!"),
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 55da277..2bb2f80 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -36,6 +36,7 @@
 mod display;
 
 use std::{
+    fmt,
     mem::discriminant,
     ops::{ControlFlow, Not},
 };
@@ -74,7 +75,7 @@
     TraitEnvironment, TyDefId, TyLoweringDiagnostic, ValueTyDefId, all_super_traits, autoderef,
     check_orphan_rules,
     consteval::try_const_usize,
-    db::InternedClosureId,
+    db::{InternedClosureId, InternedCoroutineId},
     diagnostics::BodyValidationDiagnostic,
     direct_super_traits, known_const_to_ast,
     layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding},
@@ -91,7 +92,7 @@
 use rustc_hash::FxHashSet;
 use rustc_type_ir::{
     AliasTyKind, TypeSuperVisitable, TypeVisitable, TypeVisitor,
-    inherent::{AdtDef, IntoKind, SliceLike, Term as _, Ty as _},
+    inherent::{AdtDef, GenericArgs as _, IntoKind, SliceLike, Term as _, Ty as _},
 };
 use smallvec::SmallVec;
 use span::{AstIdNode, Edition, FileId};
@@ -160,7 +161,7 @@
     // FIXME: Properly encapsulate mir
     hir_ty::mir,
     hir_ty::{
-        CastError, FnAbi, PointerCast, Variance, attach_db, attach_db_allow_change,
+        CastError, FnAbi, PointerCast, attach_db, attach_db_allow_change,
         consteval::ConstEvalError,
         diagnostics::UnsafetyReason,
         display::{ClosureStyle, DisplayTarget, HirDisplay, HirDisplayError, HirWrite},
@@ -170,6 +171,7 @@
         method_resolution::TyFingerprint,
         mir::{MirEvalError, MirLowerError},
         next_solver::abi::Safety,
+        next_solver::clear_tls_solver_cache,
     },
     intern::{Symbol, sym},
 };
@@ -1270,7 +1272,7 @@
         let interner = DbInterner::new_with(db, Some(krate.base()), None);
 
         let var_id = self.inner.parent.into();
-        let field = db.field_types_ns(var_id)[self.inner.id];
+        let field = db.field_types(var_id)[self.inner.id];
         let ty = field.instantiate(interner, self.args);
         TypeNs::new(db, var_id, ty)
     }
@@ -1349,7 +1351,7 @@
     /// context of the field definition.
     pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> TypeNs<'db> {
         let var_id = self.parent.into();
-        let ty = db.field_types_ns(var_id)[self.id].skip_binder();
+        let ty = db.field_types(var_id)[self.id].skip_binder();
         TypeNs::new(db, var_id, ty)
     }
 
@@ -1367,7 +1369,7 @@
         };
         let interner = DbInterner::new_with(db, None, None);
         let args = generic_args_from_tys(interner, def_id.into(), generics.map(|ty| ty.ty));
-        let ty = db.field_types_ns(var_id)[self.id].instantiate(interner, args);
+        let ty = db.field_types(var_id)[self.id].instantiate(interner, args);
         Type::new(db, var_id, ty)
     }
 
@@ -1802,7 +1804,7 @@
         let env = db.trait_environment(self.into());
         let interner = DbInterner::new_with(db, Some(env.krate), env.block);
         let adt_id = AdtId::from(self);
-        let args = GenericArgs::for_item_with_defaults(interner, adt_id.into(), |_, _, id, _| {
+        let args = GenericArgs::for_item_with_defaults(interner, adt_id.into(), |_, id, _| {
             GenericArg::error_from_id(interner, id)
         });
         db.layout_of_adt(adt_id, args, env)
@@ -4110,7 +4112,39 @@
             GenericParam::ConstParam(_) => return None,
             GenericParam::LifetimeParam(it) => generics.lifetime_idx(it.id)?,
         };
-        db.variances_of(parent)?.get(index).copied()
+        db.variances_of(parent).get(index).map(Into::into)
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum Variance {
+    Bivariant,
+    Covariant,
+    Contravariant,
+    Invariant,
+}
+
+impl From<rustc_type_ir::Variance> for Variance {
+    #[inline]
+    fn from(value: rustc_type_ir::Variance) -> Self {
+        match value {
+            rustc_type_ir::Variance::Covariant => Variance::Covariant,
+            rustc_type_ir::Variance::Invariant => Variance::Invariant,
+            rustc_type_ir::Variance::Contravariant => Variance::Contravariant,
+            rustc_type_ir::Variance::Bivariant => Variance::Bivariant,
+        }
+    }
+}
+
+impl fmt::Display for Variance {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let description = match self {
+            Variance::Bivariant => "bivariant",
+            Variance::Covariant => "covariant",
+            Variance::Contravariant => "contravariant",
+            Variance::Invariant => "invariant",
+        };
+        f.pad(description)
     }
 }
 
@@ -4151,8 +4185,7 @@
         let resolver = self.id.parent().resolver(db);
         let interner = DbInterner::new_with(db, None, None);
         let index = hir_ty::param_idx(db, self.id.into()).unwrap();
-        let name = self.name(db).symbol().clone();
-        let ty = Ty::new_param(interner, self.id, index as u32, name);
+        let ty = Ty::new_param(interner, self.id, index as u32);
         Type::new_with_resolver_inner(db, &resolver, ty)
     }
 
@@ -4160,7 +4193,7 @@
     /// parameter, not additional bounds that might be added e.g. by a method if
     /// the parameter comes from an impl!
     pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> {
-        db.generic_predicates_for_param_ns(self.id.parent(), self.id.into(), None)
+        db.generic_predicates_for_param(self.id.parent(), self.id.into(), None)
             .iter()
             .filter_map(|pred| match &pred.kind().skip_binder() {
                 ClauseKind::Trait(trait_ref) => Some(Trait::from(trait_ref.def_id().0)),
@@ -4250,7 +4283,7 @@
 
 fn generic_arg_from_param(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option<GenericArg<'_>> {
     let local_idx = hir_ty::param_idx(db, id)?;
-    let defaults = db.generic_defaults_ns(id.parent);
+    let defaults = db.generic_defaults(id.parent);
     let ty = defaults.get(local_idx)?;
     // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s.
     Some(ty.instantiate_identity())
@@ -4525,16 +4558,27 @@
     }
 }
 
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+enum AnyClosureId {
+    ClosureId(InternedClosureId),
+    CoroutineClosureId(InternedCoroutineId),
+}
+
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 pub struct Closure<'db> {
-    id: InternedClosureId,
+    id: AnyClosureId,
     subst: GenericArgs<'db>,
 }
 
 impl<'db> Closure<'db> {
     fn as_ty(&self, db: &'db dyn HirDatabase) -> Ty<'db> {
         let interner = DbInterner::new_with(db, None, None);
-        Ty::new_closure(interner, self.id.into(), self.subst)
+        match self.id {
+            AnyClosureId::ClosureId(id) => Ty::new_closure(interner, id.into(), self.subst),
+            AnyClosureId::CoroutineClosureId(id) => {
+                Ty::new_coroutine_closure(interner, id.into(), self.subst)
+            }
+        }
     }
 
     pub fn display_with_id(&self, db: &dyn HirDatabase, display_target: DisplayTarget) -> String {
@@ -4552,20 +4596,28 @@
     }
 
     pub fn captured_items(&self, db: &'db dyn HirDatabase) -> Vec<ClosureCapture<'db>> {
-        let owner = db.lookup_intern_closure(self.id).0;
+        let AnyClosureId::ClosureId(id) = self.id else {
+            // FIXME: Infer coroutine closures' captures.
+            return Vec::new();
+        };
+        let owner = db.lookup_intern_closure(id).0;
         let infer = db.infer(owner);
-        let info = infer.closure_info(self.id);
+        let info = infer.closure_info(id);
         info.0
             .iter()
             .cloned()
-            .map(|capture| ClosureCapture { owner, closure: self.id, capture })
+            .map(|capture| ClosureCapture { owner, closure: id, capture })
             .collect()
     }
 
     pub fn capture_types(&self, db: &'db dyn HirDatabase) -> Vec<Type<'db>> {
-        let owner = db.lookup_intern_closure(self.id).0;
+        let AnyClosureId::ClosureId(id) = self.id else {
+            // FIXME: Infer coroutine closures' captures.
+            return Vec::new();
+        };
+        let owner = db.lookup_intern_closure(id).0;
         let infer = db.infer(owner);
-        let (captures, _) = infer.closure_info(self.id);
+        let (captures, _) = infer.closure_info(id);
         let env = db.trait_environment_for_body(owner);
         captures
             .iter()
@@ -4574,10 +4626,22 @@
     }
 
     pub fn fn_trait(&self, db: &dyn HirDatabase) -> FnTrait {
-        let owner = db.lookup_intern_closure(self.id).0;
-        let infer = db.infer(owner);
-        let info = infer.closure_info(self.id);
-        info.1
+        match self.id {
+            AnyClosureId::ClosureId(id) => {
+                let owner = db.lookup_intern_closure(id).0;
+                let infer = db.infer(owner);
+                let info = infer.closure_info(id);
+                info.1
+            }
+            AnyClosureId::CoroutineClosureId(_id) => {
+                // FIXME: Infer kind for coroutine closures.
+                match self.subst.as_coroutine_closure().kind() {
+                    rustc_type_ir::ClosureKind::Fn => FnTrait::AsyncFn,
+                    rustc_type_ir::ClosureKind::FnMut => FnTrait::AsyncFnMut,
+                    rustc_type_ir::ClosureKind::FnOnce => FnTrait::AsyncFnOnce,
+                }
+            }
+        }
     }
 }
 
@@ -4851,7 +4915,7 @@
                             if variant_data.fields().is_empty() {
                                 vec![]
                             } else {
-                                let field_types = self.interner.db().field_types_ns(id);
+                                let field_types = self.interner.db().field_types(id);
                                 variant_data
                                     .fields()
                                     .iter()
@@ -5091,28 +5155,14 @@
         let interner = DbInterner::new_with(db, None, None);
         let callee = match self.ty.kind() {
             TyKind::Closure(id, subst) => Callee::Closure(id.0, subst),
+            TyKind::CoroutineClosure(id, subst) => Callee::CoroutineClosure(id.0, subst),
             TyKind::FnPtr(..) => Callee::FnPtr,
             TyKind::FnDef(id, _) => Callee::Def(id.0),
-            kind => {
-                // This will happen when it implements fn or fn mut, since we add an autoborrow adjustment
-                let (ty, kind) = if let TyKind::Ref(_, ty, _) = kind {
-                    (ty, ty.kind())
-                } else {
-                    (self.ty, kind)
-                };
-                if let TyKind::Closure(closure, subst) = kind {
-                    let sig = subst
-                        .split_closure_args_untupled()
-                        .closure_sig_as_fn_ptr_ty
-                        .callable_sig(interner)?;
-                    return Some(Callable {
-                        ty: self.clone(),
-                        sig,
-                        callee: Callee::Closure(closure.0, subst),
-                        is_bound_method: false,
-                    });
-                }
-                let (fn_trait, sig) = hir_ty::callable_sig_from_fn_trait(ty, self.env.clone(), db)?;
+            // This will happen when it implements fn or fn mut, since we add an autoborrow adjustment
+            TyKind::Ref(_, inner_ty, _) => return self.derived(inner_ty).as_callable(db),
+            _ => {
+                let (fn_trait, sig) =
+                    hir_ty::callable_sig_from_fn_trait(self.ty, self.env.clone(), db)?;
                 return Some(Callable {
                     ty: self.clone(),
                     sig,
@@ -5132,7 +5182,12 @@
 
     pub fn as_closure(&self) -> Option<Closure<'db>> {
         match self.ty.kind() {
-            TyKind::Closure(id, subst) => Some(Closure { id: id.0, subst }),
+            TyKind::Closure(id, subst) => {
+                Some(Closure { id: AnyClosureId::ClosureId(id.0), subst })
+            }
+            TyKind::CoroutineClosure(id, subst) => {
+                Some(Closure { id: AnyClosureId::CoroutineClosureId(id.0), subst })
+            }
             _ => None,
         }
     }
@@ -5184,7 +5239,7 @@
             _ => return Vec::new(),
         };
 
-        db.field_types_ns(variant_id)
+        db.field_types(variant_id)
             .iter()
             .map(|(local_id, ty)| {
                 let def = Field { parent: variant_id.into(), id: local_id };
@@ -5791,6 +5846,7 @@
 enum Callee<'db> {
     Def(CallableDefId),
     Closure(InternedClosureId, GenericArgs<'db>),
+    CoroutineClosure(InternedCoroutineId, GenericArgs<'db>),
     FnPtr,
     FnImpl(FnTrait),
 }
@@ -5812,7 +5868,12 @@
             Callee::Def(CallableDefId::EnumVariantId(it)) => {
                 CallableKind::TupleEnumVariant(it.into())
             }
-            Callee::Closure(id, ref subst) => CallableKind::Closure(Closure { id, subst: *subst }),
+            Callee::Closure(id, subst) => {
+                CallableKind::Closure(Closure { id: AnyClosureId::ClosureId(id), subst })
+            }
+            Callee::CoroutineClosure(id, subst) => {
+                CallableKind::Closure(Closure { id: AnyClosureId::CoroutineClosureId(id), subst })
+            }
             Callee::FnPtr => CallableKind::FnPtr,
             Callee::FnImpl(fn_) => CallableKind::FnImpl(fn_),
         }
@@ -6405,7 +6466,7 @@
     args: impl IntoIterator<Item = Ty<'db>>,
 ) -> GenericArgs<'db> {
     let mut args = args.into_iter();
-    GenericArgs::for_item(interner, def_id, |_, _, id, _| {
+    GenericArgs::for_item(interner, def_id, |_, id, _| {
         if matches!(id, GenericParamId::TypeParamId(_))
             && let Some(arg) = args.next()
         {
@@ -6418,7 +6479,7 @@
 
 fn has_non_default_type_params(db: &dyn HirDatabase, generic_def: GenericDefId) -> bool {
     let params = db.generic_params(generic_def);
-    let defaults = db.generic_defaults_ns(generic_def);
+    let defaults = db.generic_defaults(generic_def);
     params
         .iter_type_or_consts()
         .filter(|(_, param)| matches!(param, TypeOrConstParamData::TypeParamData(_)))
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index eecca02..62ce3da 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -1657,14 +1657,11 @@
     ) -> Option<Function> {
         let interner = DbInterner::new_with(self.db, None, None);
         let mut subst = subst.into_iter();
-        let substs = hir_ty::next_solver::GenericArgs::for_item(
-            interner,
-            trait_.id.into(),
-            |_, _, id, _| {
+        let substs =
+            hir_ty::next_solver::GenericArgs::for_item(interner, trait_.id.into(), |_, id, _| {
                 assert!(matches!(id, hir_def::GenericParamId::TypeParamId(_)), "expected a type");
                 subst.next().expect("too few subst").ty.into()
-            },
-        );
+            });
         assert!(subst.next().is_none(), "too many subst");
         Some(self.db.lookup_impl_method(env.env, func.into(), substs).0.into())
     }
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 8d2ba7e..15eab14 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -712,8 +712,7 @@
         let variant = self.infer()?.variant_resolution_for_expr_or_pat(expr_id)?;
         let variant_data = variant.fields(db);
         let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? };
-        let field_ty =
-            (*db.field_types_ns(variant).get(field.local_id)?).instantiate(interner, subst);
+        let field_ty = (*db.field_types(variant).get(field.local_id)?).instantiate(interner, subst);
         Some((
             field.into(),
             local,
@@ -735,8 +734,7 @@
         let variant_data = variant.fields(db);
         let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? };
         let (adt, subst) = self.infer()?[pat_id.as_pat()?].as_adt()?;
-        let field_ty =
-            (*db.field_types_ns(variant).get(field.local_id)?).instantiate(interner, subst);
+        let field_ty = (*db.field_types(variant).get(field.local_id)?).instantiate(interner, subst);
         Some((
             field.into(),
             Type::new_with_resolver(db, &self.resolver, field_ty),
@@ -802,7 +800,7 @@
                 |variant: VariantId, subst: GenericArgs<'db>, container: &mut _| {
                     let fields = variant.fields(db);
                     let field = fields.field(&field_name.as_name())?;
-                    let field_types = db.field_types_ns(variant);
+                    let field_types = db.field_types(variant);
                     *container = Either::Right(field_types[field].instantiate(interner, subst));
                     let generic_def = match variant {
                         VariantId::EnumVariantId(it) => it.loc(db).parent.into(),
@@ -1255,7 +1253,7 @@
         missing_fields: Vec<LocalFieldId>,
     ) -> Vec<(Field, Type<'db>)> {
         let interner = DbInterner::new_with(db, None, None);
-        let field_types = db.field_types_ns(variant);
+        let field_types = db.field_types(variant);
 
         missing_fields
             .into_iter()
diff --git a/crates/ide-assists/src/handlers/add_braces.rs b/crates/ide-assists/src/handlers/add_braces.rs
index 5af622e..99ee50f 100644
--- a/crates/ide-assists/src/handlers/add_braces.rs
+++ b/crates/ide-assists/src/handlers/add_braces.rs
@@ -1,14 +1,15 @@
 use either::Either;
 use syntax::{
-    AstNode,
-    ast::{self, edit_in_place::Indent, syntax_factory::SyntaxFactory},
+    AstNode, T,
+    ast::{self, edit::AstNodeEdit, syntax_factory::SyntaxFactory},
+    match_ast,
 };
 
 use crate::{AssistContext, AssistId, Assists};
 
 // Assist: add_braces
 //
-// Adds braces to closure bodies and match arm expressions.
+// Adds braces to closure bodies, match arm expressions and assignment bodies.
 //
 // ```
 // fn foo(n: i32) -> i32 {
@@ -29,6 +30,20 @@
 //     }
 // }
 // ```
+// ---
+// ```
+// fn foo(n: i32) -> i32 {
+//     let x =$0 n + 2;
+// }
+// ```
+// ->
+// ```
+// fn foo(n: i32) -> i32 {
+//     let x = {
+//         n + 2
+//     };
+// }
+// ```
 pub(crate) fn add_braces(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     let (expr_type, expr) = get_replacement_node(ctx)?;
 
@@ -37,16 +52,17 @@
         match expr_type {
             ParentType::ClosureExpr => "Add braces to this closure body",
             ParentType::MatchArmExpr => "Add braces to this match arm expression",
+            ParentType::Assignment => "Add braces to this assignment expression",
         },
         expr.syntax().text_range(),
         |builder| {
             let make = SyntaxFactory::with_mappings();
             let mut editor = builder.make_editor(expr.syntax());
 
-            let block_expr = make.block_expr(None, Some(expr.clone()));
-            block_expr.indent(expr.indent_level());
+            let new_expr = expr.reset_indent().indent(1.into());
+            let block_expr = make.block_expr(None, Some(new_expr));
 
-            editor.replace(expr.syntax(), block_expr.syntax());
+            editor.replace(expr.syntax(), block_expr.indent(expr.indent_level()).syntax());
 
             editor.add_mappings(make.finish_with_mappings());
             builder.add_file_edits(ctx.vfs_file_id(), editor);
@@ -57,29 +73,38 @@
 enum ParentType {
     MatchArmExpr,
     ClosureExpr,
+    Assignment,
 }
 
 fn get_replacement_node(ctx: &AssistContext<'_>) -> Option<(ParentType, ast::Expr)> {
-    let node = ctx.find_node_at_offset::<Either<ast::MatchArm, ast::ClosureExpr>>()?;
-    if let Either::Left(match_arm) = &node {
+    let node = ctx.find_node_at_offset::<Either<ast::MatchArm, ast::ClosureExpr>>();
+    let (parent_type, body) = if let Some(eq_token) = ctx.find_token_syntax_at_offset(T![=]) {
+        let parent = eq_token.parent()?;
+        let body = match_ast! {
+            match parent {
+                ast::LetStmt(it) => it.initializer()?,
+                ast::LetExpr(it) => it.expr()?,
+                ast::Static(it) => it.body()?,
+                ast::Const(it) => it.body()?,
+                _ => return None,
+            }
+        };
+        (ParentType::Assignment, body)
+    } else if let Some(Either::Left(match_arm)) = &node {
         let match_arm_expr = match_arm.expr()?;
-
-        if matches!(match_arm_expr, ast::Expr::BlockExpr(_)) {
-            return None;
-        }
-
-        return Some((ParentType::MatchArmExpr, match_arm_expr));
-    } else if let Either::Right(closure_expr) = &node {
+        (ParentType::MatchArmExpr, match_arm_expr)
+    } else if let Some(Either::Right(closure_expr)) = &node {
         let body = closure_expr.body()?;
+        (ParentType::ClosureExpr, body)
+    } else {
+        return None;
+    };
 
-        if matches!(body, ast::Expr::BlockExpr(_)) {
-            return None;
-        }
-
-        return Some((ParentType::ClosureExpr, body));
+    if matches!(body, ast::Expr::BlockExpr(_)) {
+        return None;
     }
 
-    None
+    Some((parent_type, body))
 }
 
 #[cfg(test)]
@@ -135,6 +160,25 @@
     }
 
     #[test]
+    fn suggest_add_braces_for_assignment() {
+        check_assist(
+            add_braces,
+            r#"
+fn foo() {
+    let x =$0 n + 100;
+}
+"#,
+            r#"
+fn foo() {
+    let x = {
+        n + 100
+    };
+}
+"#,
+        );
+    }
+
+    #[test]
     fn no_assist_for_closures_with_braces() {
         check_assist_not_applicable(
             add_braces,
@@ -172,6 +216,41 @@
     }
 
     #[test]
+    fn multiple_indent() {
+        check_assist(
+            add_braces,
+            r#"
+fn foo() {
+    {
+        match n {
+            Some(n) $0=> foo(
+                29,
+                30,
+            ),
+            _ => ()
+        };
+    }
+}
+"#,
+            r#"
+fn foo() {
+    {
+        match n {
+            Some(n) => {
+                foo(
+                    29,
+                    30,
+                )
+            },
+            _ => ()
+        };
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
     fn no_assist_for_match_with_braces() {
         check_assist_not_applicable(
             add_braces,
diff --git a/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/crates/ide-assists/src/handlers/add_missing_match_arms.rs
index 8802a54..7843ab9 100644
--- a/crates/ide-assists/src/handlers/add_missing_match_arms.rs
+++ b/crates/ide-assists/src/handlers/add_missing_match_arms.rs
@@ -8,8 +8,7 @@
 use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast};
 use itertools::Itertools;
 use syntax::ToSmolStr;
-use syntax::ast::edit::IndentLevel;
-use syntax::ast::edit_in_place::Indent;
+use syntax::ast::edit::{AstNodeEdit, IndentLevel};
 use syntax::ast::syntax_factory::SyntaxFactory;
 use syntax::ast::{self, AstNode, MatchArmList, MatchExpr, Pat, make};
 
@@ -261,6 +260,7 @@
                         true
                     }
                 })
+                .map(|arm| arm.reset_indent().indent(IndentLevel(1)))
                 .collect();
 
             let first_new_arm_idx = arms.len();
@@ -300,7 +300,7 @@
             };
 
             let mut editor = builder.make_editor(&old_place);
-            new_match_arm_list.indent(IndentLevel::from_node(&old_place));
+            let new_match_arm_list = new_match_arm_list.indent(IndentLevel::from_node(&old_place));
             editor.replace(old_place, new_match_arm_list.syntax());
 
             if let Some(cap) = ctx.config.snippet_cap {
@@ -918,6 +918,39 @@
     }
 
     #[test]
+    fn partial_fill_option_with_indentation() {
+        check_assist(
+            add_missing_match_arms,
+            r#"
+//- minicore: option
+fn main() {
+    match None$0 {
+        None => {
+            foo(
+                "foo",
+                "bar",
+            );
+        }
+    }
+}
+"#,
+            r#"
+fn main() {
+    match None {
+        None => {
+            foo(
+                "foo",
+                "bar",
+            );
+        }
+        Some(${1:_}) => ${2:todo!()},$0
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
     fn partial_fill_or_pat() {
         check_assist(
             add_missing_match_arms,
diff --git a/crates/ide-assists/src/handlers/convert_closure_to_fn.rs b/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
index 2cda6d6..ca14233 100644
--- a/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
+++ b/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
@@ -805,7 +805,6 @@
         );
     }
 
-    #[ignore = "FIXME(next-solver): Fix async closures"]
     #[test]
     fn replaces_async_closure_with_async_fn() {
         check_assist(
diff --git a/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs b/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
index 8d27574..e518c39 100644
--- a/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
+++ b/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
@@ -187,6 +187,7 @@
         return None;
     }
 
+    // FIXME: Processing RecordPat and RecordExpr for unordered fields, and insert RestPat
     let parent = full_path.syntax().parent()?;
     match_ast! {
         match parent {
@@ -202,6 +203,9 @@
                             .record_pat_field_list()?
                             .fields()
                             .filter_map(|pat| pat.pat())
+                            .chain(record_struct_pat.record_pat_field_list()?
+                                .rest_pat()
+                                .map(Into::into))
                     )
                     .to_string()
                 );
@@ -347,6 +351,37 @@
     }
 
     #[test]
+    fn convert_struct_and_rest_pat() {
+        check_assist(
+            convert_named_struct_to_tuple_struct,
+            r#"
+struct Inner;
+struct A$0 { inner: Inner }
+fn foo(A { .. }: A) {}
+"#,
+            r#"
+struct Inner;
+struct A(Inner);
+fn foo(A(..): A) {}
+"#,
+        );
+
+        check_assist(
+            convert_named_struct_to_tuple_struct,
+            r#"
+struct Inner;
+struct A$0 { inner: Inner, extra: Inner }
+fn foo(A { inner, .. }: A) {}
+"#,
+            r#"
+struct Inner;
+struct A(Inner, Inner);
+fn foo(A(inner, ..): A) {}
+"#,
+        );
+    }
+
+    #[test]
     fn convert_simple_struct_cursor_on_visibility_keyword() {
         check_assist(
             convert_named_struct_to_tuple_struct,
diff --git a/crates/ide-assists/src/handlers/convert_to_guarded_return.rs b/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
index ae13f83..7f4fb4c 100644
--- a/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
+++ b/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
@@ -75,8 +75,8 @@
 
     let let_chains = flat_let_chain(cond);
 
-    let then_block = if_expr.then_branch()?;
-    let then_block = then_block.stmt_list()?;
+    let then_branch = if_expr.then_branch()?;
+    let then_block = then_branch.stmt_list()?;
 
     let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?;
 
@@ -84,17 +84,8 @@
         return None;
     }
 
-    // FIXME: This relies on untyped syntax tree and casts to much. It should be
-    // rewritten to use strongly-typed APIs.
-
     // check for early return and continue
-    let first_in_then_block = then_block.syntax().first_child()?;
-    if ast::ReturnExpr::can_cast(first_in_then_block.kind())
-        || ast::ContinueExpr::can_cast(first_in_then_block.kind())
-        || first_in_then_block
-            .children()
-            .any(|x| ast::ReturnExpr::can_cast(x.kind()) || ast::ContinueExpr::can_cast(x.kind()))
-    {
+    if is_early_block(&then_block) || is_never_block(&ctx.sema, &then_branch) {
         return None;
     }
 
@@ -255,20 +246,25 @@
 
 fn flat_let_chain(mut expr: ast::Expr) -> Vec<ast::Expr> {
     let mut chains = vec![];
+    let mut reduce_cond = |rhs| {
+        if !matches!(rhs, ast::Expr::LetExpr(_))
+            && let Some(last) = chains.pop_if(|last| !matches!(last, ast::Expr::LetExpr(_)))
+        {
+            chains.push(make::expr_bin_op(rhs, ast::BinaryOp::LogicOp(ast::LogicOp::And), last));
+        } else {
+            chains.push(rhs);
+        }
+    };
 
     while let ast::Expr::BinExpr(bin_expr) = &expr
         && bin_expr.op_kind() == Some(ast::BinaryOp::LogicOp(ast::LogicOp::And))
         && let (Some(lhs), Some(rhs)) = (bin_expr.lhs(), bin_expr.rhs())
     {
-        if let Some(last) = chains.pop_if(|last| !matches!(last, ast::Expr::LetExpr(_))) {
-            chains.push(make::expr_bin_op(rhs, ast::BinaryOp::LogicOp(ast::LogicOp::And), last));
-        } else {
-            chains.push(rhs);
-        }
+        reduce_cond(rhs);
         expr = lhs;
     }
 
-    chains.push(expr);
+    reduce_cond(expr);
     chains.reverse();
     chains
 }
@@ -284,6 +280,17 @@
     }
 }
 
+fn is_early_block(then_block: &ast::StmtList) -> bool {
+    let is_early_expr =
+        |expr| matches!(expr, ast::Expr::ReturnExpr(_) | ast::Expr::ContinueExpr(_));
+    let into_expr = |stmt| match stmt {
+        ast::Stmt::ExprStmt(expr_stmt) => expr_stmt.expr(),
+        _ => None,
+    };
+    then_block.tail_expr().is_some_and(is_early_expr)
+        || then_block.statements().filter_map(into_expr).any(is_early_expr)
+}
+
 #[cfg(test)]
 mod tests {
     use crate::tests::{check_assist, check_assist_not_applicable};
@@ -554,6 +561,93 @@
 }
 "#,
         );
+
+        check_assist(
+            convert_to_guarded_return,
+            r#"
+fn main() {
+    if$0 let Ok(x) = Err(92)
+        && let Ok(y) = Ok(37)
+        && x < 30
+        && let Some(y) = Some(8)
+    {
+        foo(x, y);
+    }
+}
+"#,
+            r#"
+fn main() {
+    let Ok(x) = Err(92) else { return };
+    let Ok(y) = Ok(37) else { return };
+    if x >= 30 {
+        return;
+    }
+    let Some(y) = Some(8) else { return };
+    foo(x, y);
+}
+"#,
+        );
+
+        check_assist(
+            convert_to_guarded_return,
+            r#"
+fn main() {
+    if$0 cond
+        && let Ok(x) = Err(92)
+        && let Ok(y) = Ok(37)
+        && x < 30
+        && let Some(y) = Some(8)
+    {
+        foo(x, y);
+    }
+}
+"#,
+            r#"
+fn main() {
+    if !cond {
+        return;
+    }
+    let Ok(x) = Err(92) else { return };
+    let Ok(y) = Ok(37) else { return };
+    if x >= 30 {
+        return;
+    }
+    let Some(y) = Some(8) else { return };
+    foo(x, y);
+}
+"#,
+        );
+
+        check_assist(
+            convert_to_guarded_return,
+            r#"
+fn main() {
+    if$0 cond
+        && foo()
+        && let Ok(x) = Err(92)
+        && let Ok(y) = Ok(37)
+        && x < 30
+        && let Some(y) = Some(8)
+    {
+        foo(x, y);
+    }
+}
+"#,
+            r#"
+fn main() {
+    if !(cond && foo()) {
+        return;
+    }
+    let Ok(x) = Err(92) else { return };
+    let Ok(y) = Ok(37) else { return };
+    if x >= 30 {
+        return;
+    }
+    let Some(y) = Some(8) else { return };
+    foo(x, y);
+}
+"#,
+        );
     }
 
     #[test]
diff --git a/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
index 3d78895..61d8449 100644
--- a/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
+++ b/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
@@ -154,14 +154,7 @@
                 ast::TupleStructPat(tuple_struct_pat) => {
                     Some(make.record_pat_with_fields(
                         tuple_struct_pat.path()?,
-                        ast::make::record_pat_field_list(tuple_struct_pat.fields().zip(names).map(
-                            |(pat, name)| {
-                                ast::make::record_pat_field(
-                                    ast::make::name_ref(&name.to_string()),
-                                    pat,
-                                )
-                            },
-                        ), None),
+                        generate_record_pat_list(&tuple_struct_pat, names),
                     ).syntax().clone())
                 },
                 // for tuple struct creations like Foo(42)
@@ -284,6 +277,24 @@
         .collect()
 }
 
+fn generate_record_pat_list(
+    pat: &ast::TupleStructPat,
+    names: &[ast::Name],
+) -> ast::RecordPatFieldList {
+    let pure_fields = pat.fields().filter(|p| !matches!(p, ast::Pat::RestPat(_)));
+    let rest_len = names.len().saturating_sub(pure_fields.clone().count());
+    let rest_pat = pat.fields().find_map(|p| ast::RestPat::cast(p.syntax().clone()));
+    let rest_idx =
+        pat.fields().position(|p| ast::RestPat::can_cast(p.syntax().kind())).unwrap_or(names.len());
+    let before_rest = pat.fields().zip(names).take(rest_idx);
+    let after_rest = pure_fields.zip(names.iter().skip(rest_len)).skip(rest_idx);
+
+    let fields = before_rest
+        .chain(after_rest)
+        .map(|(pat, name)| ast::make::record_pat_field(ast::make::name_ref(&name.text()), pat));
+    ast::make::record_pat_field_list(fields, rest_pat)
+}
+
 #[cfg(test)]
 mod tests {
     use crate::tests::{check_assist, check_assist_not_applicable};
@@ -359,6 +370,43 @@
     }
 
     #[test]
+    fn convert_struct_and_rest_pat() {
+        check_assist(
+            convert_tuple_struct_to_named_struct,
+            r#"
+struct Inner;
+struct A$0(Inner);
+fn foo(A(..): A) {}
+"#,
+            r#"
+struct Inner;
+struct A { field1: Inner }
+fn foo(A { .. }: A) {}
+"#,
+        );
+
+        check_assist(
+            convert_tuple_struct_to_named_struct,
+            r#"
+struct A;
+struct B;
+struct C;
+struct D;
+struct X$0(A, B, C, D);
+fn foo(X(a, .., d): X) {}
+"#,
+            r#"
+struct A;
+struct B;
+struct C;
+struct D;
+struct X { field1: A, field2: B, field3: C, field4: D }
+fn foo(X { field1: a, field4: d, .. }: X) {}
+"#,
+        );
+    }
+
+    #[test]
     fn convert_simple_struct_cursor_on_struct_keyword() {
         check_assist(
             convert_tuple_struct_to_named_struct,
diff --git a/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
index f09389f..e2afc0b 100644
--- a/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
+++ b/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
@@ -7,6 +7,7 @@
 };
 use itertools::Itertools;
 use syntax::{
+    T,
     ast::{self, AstNode, FieldExpr, HasName, IdentPat, make},
     ted,
 };
@@ -179,6 +180,11 @@
             .map(|name| ast::Pat::from(make::ident_pat(is_ref, is_mut, make::name(name))));
         make::tuple_pat(fields).clone_for_update()
     };
+    let is_shorthand_field = ident_pat
+        .name()
+        .as_ref()
+        .and_then(ast::RecordPatField::for_field_name)
+        .is_some_and(|field| field.colon_token().is_none());
 
     if let Some(cap) = ctx.config.snippet_cap {
         // place cursor on first tuple name
@@ -190,12 +196,13 @@
         }
     }
 
-    AssignmentEdit { ident_pat, tuple_pat, in_sub_pattern }
+    AssignmentEdit { ident_pat, tuple_pat, in_sub_pattern, is_shorthand_field }
 }
 struct AssignmentEdit {
     ident_pat: ast::IdentPat,
     tuple_pat: ast::TuplePat,
     in_sub_pattern: bool,
+    is_shorthand_field: bool,
 }
 
 impl AssignmentEdit {
@@ -203,6 +210,9 @@
         // with sub_pattern: keep original tuple and add subpattern: `tup @ (_0, _1)`
         if self.in_sub_pattern {
             self.ident_pat.set_pat(Some(self.tuple_pat.into()))
+        } else if self.is_shorthand_field {
+            ted::insert(ted::Position::after(self.ident_pat.syntax()), self.tuple_pat.syntax());
+            ted::insert_raw(ted::Position::after(self.ident_pat.syntax()), make::token(T![:]));
         } else {
             ted::replace(self.ident_pat.syntax(), self.tuple_pat.syntax())
         }
@@ -800,6 +810,48 @@
     }
 
     #[test]
+    fn in_record_shorthand_field() {
+        check_assist(
+            assist,
+            r#"
+struct S { field: (i32, i32) }
+fn main() {
+    let S { $0field } = S { field: (2, 3) };
+    let v = field.0 + field.1;
+}
+            "#,
+            r#"
+struct S { field: (i32, i32) }
+fn main() {
+    let S { field: ($0_0, _1) } = S { field: (2, 3) };
+    let v = _0 + _1;
+}
+            "#,
+        )
+    }
+
+    #[test]
+    fn in_record_field() {
+        check_assist(
+            assist,
+            r#"
+struct S { field: (i32, i32) }
+fn main() {
+    let S { field: $0t } = S { field: (2, 3) };
+    let v = t.0 + t.1;
+}
+            "#,
+            r#"
+struct S { field: (i32, i32) }
+fn main() {
+    let S { field: ($0_0, _1) } = S { field: (2, 3) };
+    let v = _0 + _1;
+}
+            "#,
+        )
+    }
+
+    #[test]
     fn in_nested_tuple() {
         check_assist(
             assist,
diff --git a/crates/ide-assists/src/handlers/extract_module.rs b/crates/ide-assists/src/handlers/extract_module.rs
index dad19bf..a17ae48 100644
--- a/crates/ide-assists/src/handlers/extract_module.rs
+++ b/crates/ide-assists/src/handlers/extract_module.rs
@@ -1,4 +1,4 @@
-use std::ops::RangeInclusive;
+use std::{iter::once, ops::RangeInclusive};
 
 use hir::{HasSource, ModuleSource};
 use ide_db::{
@@ -63,19 +63,6 @@
         syntax::NodeOrToken::Token(t) => t.parent()?,
     };
 
-    //If the selection is inside impl block, we need to place new module outside impl block,
-    //as impl blocks cannot contain modules
-
-    let mut impl_parent: Option<ast::Impl> = None;
-    let mut impl_child_count: usize = 0;
-    if let Some(parent_assoc_list) = node.parent()
-        && let Some(parent_impl) = parent_assoc_list.parent()
-        && let Some(impl_) = ast::Impl::cast(parent_impl)
-    {
-        impl_child_count = parent_assoc_list.children().count();
-        impl_parent = Some(impl_);
-    }
-
     let mut curr_parent_module: Option<ast::Module> = None;
     if let Some(mod_syn_opt) = node.ancestors().find(|it| ast::Module::can_cast(it.kind())) {
         curr_parent_module = ast::Module::cast(mod_syn_opt);
@@ -94,7 +81,22 @@
         return None;
     }
 
-    let old_item_indent = module.body_items[0].indent_level();
+    let mut old_item_indent = module.body_items[0].indent_level();
+    let old_items: Vec<_> = module.use_items.iter().chain(&module.body_items).cloned().collect();
+
+    // If the selection is inside impl block, we need to place new module outside impl block,
+    // as impl blocks cannot contain modules
+
+    let mut impl_parent: Option<ast::Impl> = None;
+    let mut impl_child_count: usize = 0;
+    if let Some(parent_assoc_list) = module.body_items[0].syntax().parent()
+        && let Some(parent_impl) = parent_assoc_list.parent()
+        && let Some(impl_) = ast::Impl::cast(parent_impl)
+    {
+        impl_child_count = parent_assoc_list.children().count();
+        old_item_indent = impl_.indent_level();
+        impl_parent = Some(impl_);
+    }
 
     acc.add(
         AssistId::refactor_extract("extract_module"),
@@ -127,7 +129,7 @@
             let import_items = module.resolve_imports(curr_parent_module, ctx);
             module.change_visibility(record_fields);
 
-            let module_def = generate_module_def(&impl_parent, module, old_item_indent).to_string();
+            let module_def = generate_module_def(&impl_parent, &module).indent(old_item_indent);
 
             let mut usages_to_be_processed_for_cur_file = vec![];
             for (file_id, usages) in usages_to_be_processed {
@@ -149,27 +151,32 @@
             if let Some(impl_) = impl_parent {
                 // Remove complete impl block if it has only one child (as such it will be empty
                 // after deleting that child)
-                let node_to_be_removed = if impl_child_count == 1 {
-                    impl_.syntax()
+                let nodes_to_be_removed = if impl_child_count == old_items.len() {
+                    vec![impl_.syntax()]
                 } else {
                     //Remove selected node
-                    &node
+                    old_items.iter().map(|it| it.syntax()).collect()
                 };
 
-                builder.delete(node_to_be_removed.text_range());
-                // Remove preceding indentation from node
-                if let Some(range) = indent_range_before_given_node(node_to_be_removed) {
-                    builder.delete(range);
+                for node_to_be_removed in nodes_to_be_removed {
+                    builder.delete(node_to_be_removed.text_range());
+                    // Remove preceding indentation from node
+                    if let Some(range) = indent_range_before_given_node(node_to_be_removed) {
+                        builder.delete(range);
+                    }
                 }
 
-                builder.insert(impl_.syntax().text_range().end(), format!("\n\n{module_def}"));
+                builder.insert(
+                    impl_.syntax().text_range().end(),
+                    format!("\n\n{old_item_indent}{module_def}"),
+                );
             } else {
                 for import_item in import_items {
                     if !module_text_range.contains_range(import_item) {
                         builder.delete(import_item);
                     }
                 }
-                builder.replace(module_text_range, module_def)
+                builder.replace(module_text_range, module_def.to_string())
             }
         },
     )
@@ -177,34 +184,35 @@
 
 fn generate_module_def(
     parent_impl: &Option<ast::Impl>,
-    module: Module,
-    old_indent: IndentLevel,
+    Module { name, body_items, use_items }: &Module,
 ) -> ast::Module {
-    let Module { name, body_items, use_items } = module;
-    let items = if let Some(self_ty) = parent_impl.as_ref().and_then(|imp| imp.self_ty()) {
+    let items: Vec<_> = if let Some(impl_) = parent_impl.as_ref()
+        && let Some(self_ty) = impl_.self_ty()
+    {
         let assoc_items = body_items
-            .into_iter()
+            .iter()
             .map(|item| item.syntax().clone())
             .filter_map(ast::AssocItem::cast)
             .map(|it| it.indent(IndentLevel(1)))
             .collect_vec();
-        let assoc_item_list = make::assoc_item_list(Some(assoc_items));
-        let impl_ = make::impl_(None, None, None, self_ty.clone(), None, Some(assoc_item_list));
+        let assoc_item_list = make::assoc_item_list(Some(assoc_items)).clone_for_update();
+        let impl_ = impl_.reset_indent();
+        ted::replace(impl_.get_or_create_assoc_item_list().syntax(), assoc_item_list.syntax());
         // Add the import for enum/struct corresponding to given impl block
         let use_impl = make_use_stmt_of_node_with_super(self_ty.syntax());
-        let mut module_body_items = use_items;
-        module_body_items.insert(0, use_impl);
-        module_body_items.push(ast::Item::Impl(impl_));
-        module_body_items
+        once(use_impl)
+            .chain(use_items.iter().cloned())
+            .chain(once(ast::Item::Impl(impl_)))
+            .collect()
     } else {
-        [use_items, body_items].concat()
+        use_items.iter().chain(body_items).cloned().collect()
     };
 
     let items = items.into_iter().map(|it| it.reset_indent().indent(IndentLevel(1))).collect_vec();
     let module_body = make::item_list(Some(items));
 
     let module_name = make::name(name);
-    make::mod_(module_name, Some(module_body)).indent(old_indent)
+    make::mod_(module_name, Some(module_body))
 }
 
 fn make_use_stmt_of_node_with_super(node_syntax: &SyntaxNode) -> ast::Item {
@@ -1400,28 +1408,54 @@
     fn test_if_inside_impl_block_generate_module_outside() {
         check_assist(
             extract_module,
-            r"
-            struct A {}
+            r"struct A {}
 
             impl A {
-$0fn foo() {}$0
+                $0fn foo() {}$0
                 fn bar() {}
             }
         ",
-            r"
-            struct A {}
+            r"struct A {}
 
             impl A {
                 fn bar() {}
             }
 
-mod modname {
-    use super::A;
+            mod modname {
+                use super::A;
 
-    impl A {
-        pub(crate) fn foo() {}
-    }
-}
+                impl A {
+                    pub(crate) fn foo() {}
+                }
+            }
+        ",
+        );
+
+        check_assist(
+            extract_module,
+            r"struct A {}
+
+            impl A {
+                $0fn foo() {}
+                fn bar() {}$0
+                fn baz() {}
+            }
+        ",
+            r"struct A {}
+
+            impl A {
+                fn baz() {}
+            }
+
+            mod modname {
+                use super::A;
+
+                impl A {
+                    pub(crate) fn foo() {}
+
+                    pub(crate) fn bar() {}
+                }
+            }
         ",
         )
     }
@@ -1430,27 +1464,25 @@
     fn test_if_inside_impl_block_generate_module_outside_but_impl_block_having_one_child() {
         check_assist(
             extract_module,
-            r"
-            struct A {}
+            r"struct A {}
             struct B {}
 
             impl A {
 $0fn foo(x: B) {}$0
             }
         ",
-            r"
-            struct A {}
+            r"struct A {}
             struct B {}
 
-mod modname {
-    use super::A;
+            mod modname {
+                use super::A;
 
-    use super::B;
+                use super::B;
 
-    impl A {
-        pub(crate) fn foo(x: B) {}
-    }
-}
+                impl A {
+                    pub(crate) fn foo(x: B) {}
+                }
+            }
         ",
         )
     }
diff --git a/crates/ide-assists/src/handlers/flip_binexpr.rs b/crates/ide-assists/src/handlers/flip_binexpr.rs
index 247e810..8f2306e 100644
--- a/crates/ide-assists/src/handlers/flip_binexpr.rs
+++ b/crates/ide-assists/src/handlers/flip_binexpr.rs
@@ -1,6 +1,7 @@
 use syntax::{
     SyntaxKind, T,
-    ast::{self, AstNode, BinExpr, syntax_factory::SyntaxFactory},
+    ast::{self, AstNode, BinExpr, RangeItem, syntax_factory::SyntaxFactory},
+    syntax_editor::Position,
 };
 
 use crate::{AssistContext, AssistId, Assists};
@@ -87,6 +88,74 @@
     }
 }
 
+// Assist: flip_range_expr
+//
+// Flips operands of a range expression.
+//
+// ```
+// fn main() {
+//     let _ = 90..$02;
+// }
+// ```
+// ->
+// ```
+// fn main() {
+//     let _ = 2..90;
+// }
+// ```
+// ---
+// ```
+// fn main() {
+//     let _ = 90..$0;
+// }
+// ```
+// ->
+// ```
+// fn main() {
+//     let _ = ..90;
+// }
+// ```
+pub(crate) fn flip_range_expr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+    let range_expr = ctx.find_node_at_offset::<ast::RangeExpr>()?;
+    let op = range_expr.op_token()?;
+    let start = range_expr.start();
+    let end = range_expr.end();
+
+    if !op.text_range().contains_range(ctx.selection_trimmed()) {
+        return None;
+    }
+    if start.is_none() && end.is_none() {
+        return None;
+    }
+
+    acc.add(
+        AssistId::refactor_rewrite("flip_range_expr"),
+        "Flip range expression",
+        op.text_range(),
+        |builder| {
+            let mut edit = builder.make_editor(range_expr.syntax());
+
+            match (start, end) {
+                (Some(start), Some(end)) => {
+                    edit.replace(start.syntax(), end.syntax());
+                    edit.replace(end.syntax(), start.syntax());
+                }
+                (Some(start), None) => {
+                    edit.delete(start.syntax());
+                    edit.insert(Position::after(&op), start.syntax().clone_for_update());
+                }
+                (None, Some(end)) => {
+                    edit.delete(end.syntax());
+                    edit.insert(Position::before(&op), end.syntax().clone_for_update());
+                }
+                (None, None) => (),
+            }
+
+            builder.add_file_edits(ctx.vfs_file_id(), edit);
+        },
+    )
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
diff --git a/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs b/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs
index 6c302a2..a1ec763 100644
--- a/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs
+++ b/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs
@@ -5,9 +5,10 @@
     RootDatabase, famous_defs::FamousDefs, helpers::mod_path_to_ast,
     imports::import_assets::item_for_path_search, use_trivial_constructor::use_trivial_constructor,
 };
+use syntax::syntax_editor::{Element, Position};
 use syntax::{
     TokenText,
-    ast::{self, AstNode, HasAttrs, HasGenericParams, HasName, edit, edit_in_place::Indent},
+    ast::{self, AstNode, HasAttrs, HasGenericParams, HasName, edit::AstNodeEdit},
 };
 
 use crate::{
@@ -111,9 +112,8 @@
                 false,
                 false,
             )
-            .clone_for_update();
+            .indent(1.into());
 
-            fn_.indent(1.into());
             let cfg_attrs = strukt
                 .attrs()
                 .filter(|attr| attr.as_simple_call().is_some_and(|(name, _arg)| name == "cfg"));
@@ -129,16 +129,25 @@
                 make::ty("From"),
                 ty.clone(),
                 None,
-                ty_where_clause.map(|wc| edit::AstNodeEdit::reset_indent(&wc)),
+                ty_where_clause.map(|wc| wc.reset_indent()),
                 None,
             )
             .clone_for_update();
 
             impl_.get_or_create_assoc_item_list().add_item(fn_.into());
+            let impl_ = impl_.indent(indent);
 
-            impl_.reindent_to(indent);
+            let mut edit = builder.make_editor(strukt.syntax());
 
-            builder.insert(strukt.syntax().text_range().end(), format!("\n\n{indent}{impl_}"));
+            edit.insert_all(
+                Position::after(strukt.syntax()),
+                vec![
+                    make::tokens::whitespace(&format!("\n\n{indent}")).syntax_element(),
+                    impl_.syntax().syntax_element(),
+                ],
+            );
+
+            builder.add_file_edits(ctx.vfs_file_id(), edit);
         },
     )
 }
diff --git a/crates/ide-assists/src/handlers/invert_if.rs b/crates/ide-assists/src/handlers/invert_if.rs
index 7576d2f..bf82d8d 100644
--- a/crates/ide-assists/src/handlers/invert_if.rs
+++ b/crates/ide-assists/src/handlers/invert_if.rs
@@ -27,7 +27,9 @@
 // }
 // ```
 pub(crate) fn invert_if(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
-    let if_keyword = ctx.find_token_syntax_at_offset(T![if])?;
+    let if_keyword = ctx
+        .find_token_syntax_at_offset(T![if])
+        .or_else(|| ctx.find_token_syntax_at_offset(T![else]))?;
     let expr = ast::IfExpr::cast(if_keyword.parent()?)?;
     let if_range = if_keyword.text_range();
     let cursor_in_range = if_range.contains_range(ctx.selection_trimmed());
@@ -112,6 +114,15 @@
     }
 
     #[test]
+    fn invert_if_on_else_keyword() {
+        check_assist(
+            invert_if,
+            "fn f() { if cond { 3 * 2 } e$0lse { 1 } }",
+            "fn f() { if !cond { 1 } else { 3 * 2 } }",
+        )
+    }
+
+    #[test]
     fn invert_if_doesnt_apply_with_cursor_not_on_if() {
         check_assist_not_applicable(invert_if, "fn f() { if !$0cond { 3 * 2 } else { 1 } }")
     }
diff --git a/crates/ide-assists/src/handlers/remove_else_branches.rs b/crates/ide-assists/src/handlers/remove_else_branches.rs
new file mode 100644
index 0000000..6a02c37
--- /dev/null
+++ b/crates/ide-assists/src/handlers/remove_else_branches.rs
@@ -0,0 +1,90 @@
+use syntax::{AstNode, SyntaxKind, T, TextRange, ast};
+
+use crate::{AssistContext, AssistId, Assists};
+
+// Assist: remove_else_branches
+//
+// Removes the `else` keyword and else branches.
+//
+// ```
+// fn main() {
+//     if true {
+//         let _ = 2;
+//     } $0else {
+//         unreachable!();
+//     }
+// }
+// ```
+// ->
+// ```
+// fn main() {
+//     if true {
+//         let _ = 2;
+//     }
+// }
+// ```
+// ---
+// ```
+// fn main() {
+//     let _x = 2 $0else { unreachable!() };
+// }
+// ```
+// ->
+// ```
+// fn main() {
+//     let _x = 2;
+// }
+// ```
+pub(crate) fn remove_else_branches(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+    let else_token = ctx.find_token_syntax_at_offset(T![else])?;
+    let else_branches = ctx
+        .find_node_at_range::<ast::IfExpr>()
+        .and_then(|if_expr| if_expr.else_branch()?.syntax().clone().into())
+        .or_else(|| {
+            ctx.find_node_at_range::<ast::LetStmt>()?
+                .let_else()?
+                .block_expr()?
+                .syntax()
+                .clone()
+                .into()
+        })?;
+
+    let target = TextRange::cover(else_token.text_range(), else_branches.text_range());
+    acc.add(
+        AssistId::refactor("remove_else_branches"),
+        "Remove `else` branches",
+        target,
+        |builder| {
+            let mut editor = builder.make_editor(&else_token.parent().unwrap());
+            match else_token.prev_token() {
+                Some(it) if it.kind() == SyntaxKind::WHITESPACE => editor.delete(it),
+                _ => (),
+            }
+            match else_token.next_token() {
+                Some(it) if it.kind() == SyntaxKind::WHITESPACE => editor.delete(it),
+                _ => (),
+            }
+            editor.delete(else_token);
+            editor.delete(else_branches);
+            builder.add_file_edits(ctx.vfs_file_id(), editor);
+        },
+    )
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::tests::check_assist_not_applicable;
+
+    #[test]
+    fn test_remove_else_branches_not_on_else_token() {
+        check_assist_not_applicable(
+            remove_else_branches,
+            r#"
+fn main() {
+    let _x = 2 else {$0 unreachable!() };
+}
+"#,
+        );
+    }
+}
diff --git a/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs b/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs
index f507cae..c57fd4d 100644
--- a/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs
+++ b/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs
@@ -1,7 +1,7 @@
 use ide_db::syntax_helpers::suggest_name;
 use syntax::ast::{self, AstNode, syntax_factory::SyntaxFactory};
 
-use crate::{AssistContext, AssistId, Assists};
+use crate::{AssistContext, AssistId, Assists, utils::cover_let_chain};
 
 // Assist: replace_is_some_with_if_let_some
 //
@@ -27,13 +27,11 @@
     let if_expr = ctx.find_node_at_offset::<ast::IfExpr>()?;
 
     let cond = if_expr.condition()?;
+    let cond = cover_let_chain(cond, ctx.selection_trimmed())?;
     let call_expr = match cond {
         ast::Expr::MethodCallExpr(call) => call,
         _ => return None,
     };
-    if ctx.offset() > if_expr.then_branch()?.stmt_list()?.l_curly_token()?.text_range().end() {
-        return None;
-    }
 
     let name_ref = call_expr.name_ref()?;
     match name_ref.text().as_str() {
@@ -196,6 +194,63 @@
     }
 
     #[test]
+    fn replace_is_some_with_if_let_some_in_let_chain() {
+        check_assist(
+            replace_is_method_with_if_let_method,
+            r#"
+fn main() {
+    let x = Some(1);
+    let cond = true;
+    if cond && x.is_som$0e() {}
+}
+"#,
+            r#"
+fn main() {
+    let x = Some(1);
+    let cond = true;
+    if cond && let Some(${0:x1}) = x {}
+}
+"#,
+        );
+
+        check_assist(
+            replace_is_method_with_if_let_method,
+            r#"
+fn main() {
+    let x = Some(1);
+    let cond = true;
+    if x.is_som$0e() && cond {}
+}
+"#,
+            r#"
+fn main() {
+    let x = Some(1);
+    let cond = true;
+    if let Some(${0:x1}) = x && cond {}
+}
+"#,
+        );
+
+        check_assist(
+            replace_is_method_with_if_let_method,
+            r#"
+fn main() {
+    let x = Some(1);
+    let cond = true;
+    if cond && x.is_som$0e() && cond {}
+}
+"#,
+            r#"
+fn main() {
+    let x = Some(1);
+    let cond = true;
+    if cond && let Some(${0:x1}) = x && cond {}
+}
+"#,
+        );
+    }
+
+    #[test]
     fn replace_is_some_with_if_let_some_not_applicable_after_l_curly() {
         check_assist_not_applicable(
             replace_is_method_with_if_let_method,
diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs
index 2977f8b..e9f2d68 100644
--- a/crates/ide-assists/src/lib.rs
+++ b/crates/ide-assists/src/lib.rs
@@ -201,6 +201,7 @@
     mod qualify_path;
     mod raw_string;
     mod remove_dbg;
+    mod remove_else_branches;
     mod remove_mut;
     mod remove_parentheses;
     mod remove_underscore;
@@ -284,6 +285,7 @@
             extract_type_alias::extract_type_alias,
             fix_visibility::fix_visibility,
             flip_binexpr::flip_binexpr,
+            flip_binexpr::flip_range_expr,
             flip_comma::flip_comma,
             flip_or_pattern::flip_or_pattern,
             flip_trait_bound::flip_trait_bound,
@@ -342,6 +344,7 @@
             raw_string::remove_hash,
             remove_dbg::remove_dbg,
             remove_mut::remove_mut,
+            remove_else_branches::remove_else_branches,
             remove_parentheses::remove_parentheses,
             remove_underscore::remove_underscore,
             remove_unused_imports::remove_unused_imports,
diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs
index c7ae441..a99fe8d 100644
--- a/crates/ide-assists/src/tests/generated.rs
+++ b/crates/ide-assists/src/tests/generated.rs
@@ -28,6 +28,25 @@
 }
 
 #[test]
+fn doctest_add_braces_1() {
+    check_doc_test(
+        "add_braces",
+        r#####"
+fn foo(n: i32) -> i32 {
+    let x =$0 n + 2;
+}
+"#####,
+        r#####"
+fn foo(n: i32) -> i32 {
+    let x = {
+        n + 2
+    };
+}
+"#####,
+    )
+}
+
+#[test]
 fn doctest_add_explicit_enum_discriminant() {
     check_doc_test(
         "add_explicit_enum_discriminant",
@@ -1333,6 +1352,40 @@
 }
 
 #[test]
+fn doctest_flip_range_expr() {
+    check_doc_test(
+        "flip_range_expr",
+        r#####"
+fn main() {
+    let _ = 90..$02;
+}
+"#####,
+        r#####"
+fn main() {
+    let _ = 2..90;
+}
+"#####,
+    )
+}
+
+#[test]
+fn doctest_flip_range_expr_1() {
+    check_doc_test(
+        "flip_range_expr",
+        r#####"
+fn main() {
+    let _ = 90..$0;
+}
+"#####,
+        r#####"
+fn main() {
+    let _ = ..90;
+}
+"#####,
+    )
+}
+
+#[test]
 fn doctest_flip_trait_bound() {
     check_doc_test(
         "flip_trait_bound",
@@ -2864,6 +2917,46 @@
 }
 
 #[test]
+fn doctest_remove_else_branches() {
+    check_doc_test(
+        "remove_else_branches",
+        r#####"
+fn main() {
+    if true {
+        let _ = 2;
+    } $0else {
+        unreachable!();
+    }
+}
+"#####,
+        r#####"
+fn main() {
+    if true {
+        let _ = 2;
+    }
+}
+"#####,
+    )
+}
+
+#[test]
+fn doctest_remove_else_branches_1() {
+    check_doc_test(
+        "remove_else_branches",
+        r#####"
+fn main() {
+    let _x = 2 $0else { unreachable!() };
+}
+"#####,
+        r#####"
+fn main() {
+    let _x = 2;
+}
+"#####,
+    )
+}
+
+#[test]
 fn doctest_remove_hash() {
     check_doc_test(
         "remove_hash",
diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs
index 5a3c5a3..e43516f 100644
--- a/crates/ide-assists/src/utils.rs
+++ b/crates/ide-assists/src/utils.rs
@@ -1133,6 +1133,28 @@
     tt_stack.pop().expect("parent token tree was closed before it was completed").1
 }
 
+pub(crate) fn cover_let_chain(mut expr: ast::Expr, range: TextRange) -> Option<ast::Expr> {
+    if !expr.syntax().text_range().contains_range(range) {
+        return None;
+    }
+    loop {
+        let (chain_expr, rest) = if let ast::Expr::BinExpr(bin_expr) = &expr
+            && bin_expr.op_kind() == Some(ast::BinaryOp::LogicOp(ast::LogicOp::And))
+        {
+            (bin_expr.rhs(), bin_expr.lhs())
+        } else {
+            (Some(expr), None)
+        };
+
+        if let Some(chain_expr) = chain_expr
+            && chain_expr.syntax().text_range().contains_range(range)
+        {
+            break Some(chain_expr);
+        }
+        expr = rest?;
+    }
+}
+
 pub fn is_body_const(sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr) -> bool {
     let mut is_const = true;
     preorder_expr(expr, &mut |ev| {
diff --git a/crates/ide-completion/Cargo.toml b/crates/ide-completion/Cargo.toml
index 9bad21f..277d5df 100644
--- a/crates/ide-completion/Cargo.toml
+++ b/crates/ide-completion/Cargo.toml
@@ -28,6 +28,7 @@
 # completions crate should depend only on the top-level `hir` package. if you need
 # something from some `hir-xxx` subpackage, reexport the API via `hir`.
 hir.workspace = true
+macros.workspace = true
 
 [dev-dependencies]
 expect-test = "1.5.1"
diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs
index b822f53..abae3cb 100644
--- a/crates/ide-completion/src/completions.rs
+++ b/crates/ide-completion/src/completions.rs
@@ -16,6 +16,7 @@
 pub(crate) mod mod_;
 pub(crate) mod pattern;
 pub(crate) mod postfix;
+pub(crate) mod ra_fixture;
 pub(crate) mod record;
 pub(crate) mod snippet;
 pub(crate) mod r#type;
@@ -74,6 +75,10 @@
         self.buf.push(item)
     }
 
+    fn add_many(&mut self, items: impl IntoIterator<Item = CompletionItem>) {
+        self.buf.extend(items)
+    }
+
     fn add_opt(&mut self, item: Option<CompletionItem>) {
         if let Some(item) = item {
             self.buf.push(item)
@@ -106,6 +111,13 @@
         }
     }
 
+    pub(crate) fn add_type_keywords(&mut self, ctx: &CompletionContext<'_>) {
+        self.add_keyword_snippet(ctx, "fn", "fn($1)");
+        self.add_keyword_snippet(ctx, "dyn", "dyn $0");
+        self.add_keyword_snippet(ctx, "impl", "impl $0");
+        self.add_keyword_snippet(ctx, "for", "for<$1>");
+    }
+
     pub(crate) fn add_super_keyword(
         &mut self,
         ctx: &CompletionContext<'_>,
diff --git a/crates/ide-completion/src/completions/attribute.rs b/crates/ide-completion/src/completions/attribute.rs
index e174b0c..297ce33 100644
--- a/crates/ide-completion/src/completions/attribute.rs
+++ b/crates/ide-completion/src/completions/attribute.rs
@@ -231,7 +231,7 @@
 macro_rules! attrs {
     // attributes applicable to all items
     [@ { item $($tt:tt)* } {$($acc:tt)*}] => {
-        attrs!(@ { $($tt)* } { $($acc)*, "deprecated", "doc", "dochidden", "docalias", "must_use", "no_mangle" })
+        attrs!(@ { $($tt)* } { $($acc)*, "deprecated", "doc", "dochidden", "docalias", "docinclude", "must_use", "no_mangle" })
     };
     // attributes applicable to all adts
     [@ { adt $($tt:tt)* } {$($acc:tt)*}] => {
@@ -345,6 +345,7 @@
     attr(r#"doc = "…""#, Some("doc"), Some(r#"doc = "${0:docs}""#)),
     attr(r#"doc(alias = "…")"#, Some("docalias"), Some(r#"doc(alias = "${0:docs}")"#)),
     attr(r#"doc(hidden)"#, Some("dochidden"), Some(r#"doc(hidden)"#)),
+    attr(r#"doc = include_str!("…")"#, Some("docinclude"), Some(r#"doc = include_str!("$0")"#)),
     attr("expect(…)", Some("expect"), Some("expect(${0:lint})")),
     attr(
         r#"export_name = "…""#,
diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs
index 72b245c..511b593 100644
--- a/crates/ide-completion/src/completions/dot.rs
+++ b/crates/ide-completion/src/completions/dot.rs
@@ -25,9 +25,7 @@
         _ => return,
     };
 
-    let is_field_access = matches!(dot_access.kind, DotAccessKind::Field { .. });
-    let is_method_access_with_parens =
-        matches!(dot_access.kind, DotAccessKind::Method { has_parens: true });
+    let has_parens = matches!(dot_access.kind, DotAccessKind::Method);
     let traits_in_scope = ctx.traits_in_scope();
 
     // Suggest .await syntax for types that implement Future trait
@@ -48,7 +46,7 @@
                 DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
                     DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
                 }
-                it @ DotAccessKind::Method { .. } => *it,
+                it @ DotAccessKind::Method => *it,
             };
             let dot_access = DotAccess {
                 receiver: dot_access.receiver.clone(),
@@ -67,8 +65,7 @@
                     acc.add_field(ctx, &dot_access, Some(await_str.clone()), field, &ty)
                 },
                 |acc, field, ty| acc.add_tuple_field(ctx, Some(await_str.clone()), field, &ty),
-                is_field_access,
-                is_method_access_with_parens,
+                has_parens,
             );
             complete_methods(ctx, &future_output, &traits_in_scope, |func| {
                 acc.add_method(ctx, &dot_access, func, Some(await_str.clone()), None)
@@ -82,8 +79,7 @@
         receiver_ty,
         |acc, field, ty| acc.add_field(ctx, dot_access, None, field, &ty),
         |acc, field, ty| acc.add_tuple_field(ctx, None, field, &ty),
-        is_field_access,
-        is_method_access_with_parens,
+        has_parens,
     );
     complete_methods(ctx, receiver_ty, &traits_in_scope, |func| {
         acc.add_method(ctx, dot_access, func, None, None)
@@ -112,7 +108,7 @@
                 DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
                     DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
                 }
-                it @ DotAccessKind::Method { .. } => *it,
+                it @ DotAccessKind::Method => *it,
             };
             let dot_access = DotAccess {
                 receiver: dot_access.receiver.clone(),
@@ -173,7 +169,6 @@
             )
         },
         |acc, field, ty| acc.add_tuple_field(ctx, Some(SmolStr::new_static("self")), field, &ty),
-        true,
         false,
     );
     complete_methods(ctx, &ty, &ctx.traits_in_scope(), |func| {
@@ -182,7 +177,7 @@
             &DotAccess {
                 receiver: None,
                 receiver_ty: None,
-                kind: DotAccessKind::Method { has_parens: false },
+                kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal: false },
                 ctx: DotAccessExprCtx {
                     in_block_expr: expr_ctx.in_block_expr,
                     in_breakable: expr_ctx.in_breakable,
@@ -201,15 +196,13 @@
     receiver: &hir::Type<'_>,
     mut named_field: impl FnMut(&mut Completions, hir::Field, hir::Type<'_>),
     mut tuple_index: impl FnMut(&mut Completions, usize, hir::Type<'_>),
-    is_field_access: bool,
-    is_method_access_with_parens: bool,
+    has_parens: bool,
 ) {
     let mut seen_names = FxHashSet::default();
     for receiver in receiver.autoderef(ctx.db) {
         for (field, ty) in receiver.fields(ctx.db) {
             if seen_names.insert(field.name(ctx.db))
-                && (is_field_access
-                    || (is_method_access_with_parens && (ty.is_fn() || ty.is_closure())))
+                && (!has_parens || ty.is_fn() || ty.is_closure())
             {
                 named_field(acc, field, ty);
             }
@@ -218,8 +211,7 @@
             // Tuples are always the last type in a deref chain, so just check if the name is
             // already seen without inserting into the hashset.
             if !seen_names.contains(&hir::Name::new_tuple_field(i))
-                && (is_field_access
-                    || (is_method_access_with_parens && (ty.is_fn() || ty.is_closure())))
+                && (!has_parens || ty.is_fn() || ty.is_closure())
             {
                 // Tuple fields are always public (tuple struct fields are handled above).
                 tuple_index(acc, i, ty);
@@ -1364,18 +1356,71 @@
             r#"
 struct Foo { baz: fn() }
 impl Foo {
-    fn bar<T>(self, t: T): T { t }
+    fn bar<T>(self, t: T) -> T { t }
 }
 
 fn baz() {
     let foo = Foo{ baz: || {} };
-    foo.ba$0::<>;
+    foo.ba$0;
 }
 "#,
             expect![[r#"
-                me bar(…) fn(self, T)
+                fd baz                fn()
+                me bar(…) fn(self, T) -> T
             "#]],
         );
+
+        check_edit(
+            "baz",
+            r#"
+struct Foo { baz: fn() }
+impl Foo {
+    fn bar<T>(self, t: T) -> T { t }
+}
+
+fn baz() {
+    let foo = Foo{ baz: || {} };
+    foo.ba$0;
+}
+"#,
+            r#"
+struct Foo { baz: fn() }
+impl Foo {
+    fn bar<T>(self, t: T) -> T { t }
+}
+
+fn baz() {
+    let foo = Foo{ baz: || {} };
+    (foo.baz)();
+}
+"#,
+        );
+
+        check_edit(
+            "bar",
+            r#"
+struct Foo { baz: fn() }
+impl Foo {
+    fn bar<T>(self, t: T) -> T { t }
+}
+
+fn baz() {
+    let foo = Foo{ baz: || {} };
+    foo.ba$0;
+}
+"#,
+            r#"
+struct Foo { baz: fn() }
+impl Foo {
+    fn bar<T>(self, t: T) -> T { t }
+}
+
+fn baz() {
+    let foo = Foo{ baz: || {} };
+    foo.bar(${1:t})$0;
+}
+"#,
+        );
     }
 
     #[test]
diff --git a/crates/ide-completion/src/completions/pattern.rs b/crates/ide-completion/src/completions/pattern.rs
index 0ce81d0..dcddc24 100644
--- a/crates/ide-completion/src/completions/pattern.rs
+++ b/crates/ide-completion/src/completions/pattern.rs
@@ -42,6 +42,11 @@
         }
     }
 
+    if pattern_ctx.after_if_expr {
+        add_keyword("else", "else {\n    $0\n}");
+        add_keyword("else if", "else if $1 {\n    $0\n}");
+    }
+
     if pattern_ctx.record_pat.is_some() {
         return;
     }
diff --git a/crates/ide-completion/src/completions/postfix.rs b/crates/ide-completion/src/completions/postfix.rs
index 73cbe3f..ab3f619 100644
--- a/crates/ide-completion/src/completions/postfix.rs
+++ b/crates/ide-completion/src/completions/postfix.rs
@@ -43,7 +43,7 @@
                 DotAccessKind::Field { receiver_is_ambiguous_float_literal } => {
                     receiver_is_ambiguous_float_literal
                 }
-                DotAccessKind::Method { .. } => false,
+                DotAccessKind::Method => false,
             },
         ),
         _ => return,
@@ -460,6 +460,8 @@
                 ast::MatchGuard(guard) => guard.condition()? == *it,
                 ast::BinExpr(bin_expr) => (bin_expr.op_token()?.kind() == T![&&])
                     .then(|| is_in_condition(&bin_expr.into()))?,
+                ast::Expr(expr) => (expr.syntax().text_range().start() == it.syntax().text_range().start())
+                    .then(|| is_in_condition(&expr))?,
                 _ => return None,
             } })
         })
diff --git a/crates/ide-completion/src/completions/ra_fixture.rs b/crates/ide-completion/src/completions/ra_fixture.rs
new file mode 100644
index 0000000..b44c907
--- /dev/null
+++ b/crates/ide-completion/src/completions/ra_fixture.rs
@@ -0,0 +1,113 @@
+//! Injected completions for `#[rust_analyzer::rust_fixture]`.
+
+use hir::FilePositionWrapper;
+use ide_db::{
+    impl_empty_upmap_from_ra_fixture,
+    ra_fixture::{RaFixtureAnalysis, UpmapFromRaFixture},
+};
+use syntax::ast;
+
+use crate::{
+    CompletionItemKind, CompletionItemRefMode, CompletionRelevance, completions::Completions,
+    context::CompletionContext, item::CompletionItemLabel,
+};
+
+pub(crate) fn complete_ra_fixture(
+    acc: &mut Completions,
+    ctx: &CompletionContext<'_>,
+    original: &ast::String,
+    expanded: &ast::String,
+) -> Option<()> {
+    let analysis = RaFixtureAnalysis::analyze_ra_fixture(
+        &ctx.sema,
+        original.clone(),
+        expanded,
+        ctx.config.minicore,
+        &mut |_| {},
+    )?;
+    let (virtual_file_id, virtual_offset) = analysis.map_offset_down(ctx.position.offset)?;
+    let completions = hir::attach_db_allow_change(&analysis.db, || {
+        crate::completions(
+            &analysis.db,
+            ctx.config,
+            FilePositionWrapper { file_id: virtual_file_id, offset: virtual_offset },
+            ctx.trigger_character,
+        )
+    })?;
+    let completions =
+        completions.upmap_from_ra_fixture(&analysis, virtual_file_id, ctx.position.file_id).ok()?;
+    acc.add_many(completions);
+    Some(())
+}
+
+impl_empty_upmap_from_ra_fixture!(
+    CompletionItemLabel,
+    CompletionItemKind,
+    CompletionRelevance,
+    CompletionItemRefMode,
+);
+
+#[cfg(test)]
+mod tests {
+    use expect_test::expect;
+
+    use crate::tests::check;
+
+    #[test]
+    fn it_works() {
+        check(
+            r##"
+fn fixture(#[rust_analyzer::rust_fixture] ra_fixture: &str) {}
+
+fn foo() {
+    fixture(r#"
+fn complete_me() {}
+
+fn baz() {
+    let foo_bar_baz = 123;
+    f$0
+}
+    "#);
+}
+        "##,
+            expect![[r#"
+                fn baz()         fn()
+                fn complete_me() fn()
+                lc foo_bar_baz    i32
+                bt u32            u32
+                kw async
+                kw const
+                kw crate::
+                kw enum
+                kw extern
+                kw false
+                kw fn
+                kw for
+                kw if
+                kw if let
+                kw impl
+                kw impl for
+                kw let
+                kw letm
+                kw loop
+                kw match
+                kw mod
+                kw return
+                kw self::
+                kw static
+                kw struct
+                kw trait
+                kw true
+                kw type
+                kw union
+                kw unsafe
+                kw use
+                kw while
+                kw while let
+                sn macro_rules
+                sn pd
+                sn ppd
+            "#]],
+        );
+    }
+}
diff --git a/crates/ide-completion/src/completions/record.rs b/crates/ide-completion/src/completions/record.rs
index 28b324d..bfa5670 100644
--- a/crates/ide-completion/src/completions/record.rs
+++ b/crates/ide-completion/src/completions/record.rs
@@ -179,6 +179,33 @@
     }
 
     #[test]
+    fn literal_struct_completion_shorthand() {
+        check_edit(
+            "FooDesc{}",
+            r#"
+struct FooDesc { pub bar: bool, n: i32 }
+
+fn create_foo(foo_desc: &FooDesc) -> () { () }
+
+fn baz() {
+    let bar = true;
+    let foo = create_foo(&$0);
+}
+            "#,
+            r#"
+struct FooDesc { pub bar: bool, n: i32 }
+
+fn create_foo(foo_desc: &FooDesc) -> () { () }
+
+fn baz() {
+    let bar = true;
+    let foo = create_foo(&FooDesc { bar$1, n: ${2:()} }$0);
+}
+            "#,
+        )
+    }
+
+    #[test]
     fn enum_variant_no_snippets() {
         let conf = CompletionConfig { snippet_cap: SnippetCap::new(false), ..TEST_CONFIG };
         // tuple variant
diff --git a/crates/ide-completion/src/completions/type.rs b/crates/ide-completion/src/completions/type.rs
index 3112462..3465b73 100644
--- a/crates/ide-completion/src/completions/type.rs
+++ b/crates/ide-completion/src/completions/type.rs
@@ -205,6 +205,7 @@
             };
 
             acc.add_nameref_keywords_with_colon(ctx);
+            acc.add_type_keywords(ctx);
             ctx.process_all_names(&mut |name, def, doc_aliases| {
                 if scope_def_applicable(def) {
                     acc.add_path_resolution(ctx, path_ctx, name, def, doc_aliases);
diff --git a/crates/ide-completion/src/config.rs b/crates/ide-completion/src/config.rs
index b7367cb..5623257 100644
--- a/crates/ide-completion/src/config.rs
+++ b/crates/ide-completion/src/config.rs
@@ -6,13 +6,13 @@
 
 use hir::FindPathConfig;
 use ide_db::{
-    SnippetCap,
+    MiniCore, SnippetCap,
     imports::{import_assets::ImportPathConfig, insert_use::InsertUseConfig},
 };
 
 use crate::{CompletionFieldsToResolve, snippet::Snippet};
 
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug)]
 pub struct CompletionConfig<'a> {
     pub enable_postfix_completions: bool,
     pub enable_imports_on_the_fly: bool,
@@ -35,6 +35,7 @@
     pub fields_to_resolve: CompletionFieldsToResolve,
     pub exclude_flyimport: Vec<(String, AutoImportExclusionType)>,
     pub exclude_traits: &'a [String],
+    pub minicore: MiniCore<'a>,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs
index 4032329..2f166b7 100644
--- a/crates/ide-completion/src/context.rs
+++ b/crates/ide-completion/src/context.rs
@@ -279,6 +279,7 @@
     pub(crate) param_ctx: Option<ParamContext>,
     pub(crate) has_type_ascription: bool,
     pub(crate) should_suggest_name: bool,
+    pub(crate) after_if_expr: bool,
     pub(crate) parent_pat: Option<ast::Pat>,
     pub(crate) ref_token: Option<SyntaxToken>,
     pub(crate) mut_token: Option<SyntaxToken>,
@@ -405,9 +406,7 @@
         /// like `0.$0`
         receiver_is_ambiguous_float_literal: bool,
     },
-    Method {
-        has_parens: bool,
-    },
+    Method,
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -440,6 +439,7 @@
     pub(crate) config: &'a CompletionConfig<'a>,
     pub(crate) position: FilePosition,
 
+    pub(crate) trigger_character: Option<char>,
     /// The token before the cursor, in the original file.
     pub(crate) original_token: SyntaxToken,
     /// The token before the cursor, in the macro-expanded file.
@@ -703,6 +703,7 @@
         db: &'db RootDatabase,
         position @ FilePosition { file_id, offset }: FilePosition,
         config: &'db CompletionConfig<'db>,
+        trigger_character: Option<char>,
     ) -> Option<(CompletionContext<'db>, CompletionAnalysis<'db>)> {
         let _p = tracing::info_span!("CompletionContext::new").entered();
         let sema = Semantics::new(db);
@@ -871,6 +872,7 @@
             db,
             config,
             position,
+            trigger_character,
             original_token,
             token,
             krate,
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index 873ecef..b3d9ff0 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -891,44 +891,53 @@
         return Some(make_res(kind));
     }
 
+    let field_expr_handle = |receiver, node| {
+        let receiver = find_opt_node_in_file(original_file, receiver);
+        let receiver_is_ambiguous_float_literal = match &receiver {
+            Some(ast::Expr::Literal(l)) => matches! {
+                l.kind(),
+                ast::LiteralKind::FloatNumber { .. } if l.syntax().last_token().is_some_and(|it| it.text().ends_with('.'))
+            },
+            _ => false,
+        };
+
+        let receiver_is_part_of_indivisible_expression = match &receiver {
+            Some(ast::Expr::IfExpr(_)) => {
+                let next_token_kind =
+                    next_non_trivia_token(name_ref.syntax().clone()).map(|t| t.kind());
+                next_token_kind == Some(SyntaxKind::ELSE_KW)
+            }
+            _ => false,
+        };
+        if receiver_is_part_of_indivisible_expression {
+            return None;
+        }
+
+        let mut receiver_ty = receiver.as_ref().and_then(|it| sema.type_of_expr(it));
+        if receiver_is_ambiguous_float_literal {
+            // `123.|` is parsed as a float but should actually be an integer.
+            always!(receiver_ty.as_ref().is_none_or(|receiver_ty| receiver_ty.original.is_float()));
+            receiver_ty =
+                Some(TypeInfo { original: hir::BuiltinType::i32().ty(sema.db), adjusted: None });
+        }
+
+        let kind = NameRefKind::DotAccess(DotAccess {
+            receiver_ty,
+            kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal },
+            receiver,
+            ctx: DotAccessExprCtx {
+                in_block_expr: is_in_block(node),
+                in_breakable: is_in_breakable(node).unzip().0,
+            },
+        });
+        Some(make_res(kind))
+    };
+
     let segment = match_ast! {
         match parent {
             ast::PathSegment(segment) => segment,
             ast::FieldExpr(field) => {
-                let receiver = find_opt_node_in_file(original_file, field.expr());
-                let receiver_is_ambiguous_float_literal = match &receiver {
-                    Some(ast::Expr::Literal(l)) => matches! {
-                        l.kind(),
-                        ast::LiteralKind::FloatNumber { .. } if l.syntax().last_token().is_some_and(|it| it.text().ends_with('.'))
-                    },
-                    _ => false,
-                };
-
-                let receiver_is_part_of_indivisible_expression = match &receiver {
-                    Some(ast::Expr::IfExpr(_)) => {
-                        let next_token_kind = next_non_trivia_token(name_ref.syntax().clone()).map(|t| t.kind());
-                        next_token_kind == Some(SyntaxKind::ELSE_KW)
-                    },
-                    _ => false
-                };
-                if receiver_is_part_of_indivisible_expression {
-                    return None;
-                }
-
-                let mut receiver_ty = receiver.as_ref().and_then(|it| sema.type_of_expr(it));
-                if receiver_is_ambiguous_float_literal {
-                    // `123.|` is parsed as a float but should actually be an integer.
-                    always!(receiver_ty.as_ref().is_none_or(|receiver_ty| receiver_ty.original.is_float()));
-                    receiver_ty = Some(TypeInfo { original: hir::BuiltinType::i32().ty(sema.db), adjusted: None });
-                }
-
-                let kind = NameRefKind::DotAccess(DotAccess {
-                    receiver_ty,
-                    kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal },
-                    receiver,
-                    ctx: DotAccessExprCtx { in_block_expr: is_in_block(field.syntax()), in_breakable: is_in_breakable(field.syntax()).unzip().0 }
-                });
-                return Some(make_res(kind));
+                return field_expr_handle(field.expr(), field.syntax());
             },
             ast::ExternCrate(_) => {
                 let kind = NameRefKind::ExternCrate;
@@ -937,9 +946,12 @@
             ast::MethodCallExpr(method) => {
                 let receiver = find_opt_node_in_file(original_file, method.receiver());
                 let has_parens = has_parens(&method);
+                if !has_parens && let Some(res) = field_expr_handle(method.receiver(), method.syntax()) {
+                    return Some(res)
+                }
                 let kind = NameRefKind::DotAccess(DotAccess {
                     receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)),
-                    kind: DotAccessKind::Method { has_parens },
+                    kind: DotAccessKind::Method,
                     receiver,
                     ctx: DotAccessExprCtx { in_block_expr: is_in_block(method.syntax()), in_breakable: is_in_breakable(method.syntax()).unzip().0 }
                 });
@@ -987,10 +999,6 @@
             }
         }
     };
-    let after_if_expr = |node: SyntaxNode| {
-        let prev_expr = prev_expr(node);
-        matches!(prev_expr, Some(ast::Expr::IfExpr(_)))
-    };
     let after_incomplete_let = |node: SyntaxNode| {
         prev_expr(node).and_then(|it| it.syntax().parent()).and_then(ast::LetStmt::cast)
     };
@@ -1230,7 +1238,7 @@
         let it = expr.syntax();
         let in_block_expr = is_in_block(it);
         let (in_loop_body, innermost_breakable) = is_in_breakable(it).unzip();
-        let after_if_expr = after_if_expr(it.clone());
+        let after_if_expr = is_after_if_expr(it.clone());
         let ref_expr_parent =
             path.as_single_name_ref().and_then(|_| it.parent()).and_then(ast::RefExpr::cast);
         let after_amp = non_trivia_sibling(it.clone().into(), Direction::Prev)
@@ -1751,6 +1759,7 @@
         param_ctx,
         has_type_ascription,
         should_suggest_name,
+        after_if_expr: is_after_if_expr(pat.syntax().clone()),
         parent_pat: pat.syntax().parent().and_then(ast::Pat::cast),
         mut_token,
         ref_token,
@@ -1890,11 +1899,49 @@
 }
 
 fn is_in_block(node: &SyntaxNode) -> bool {
+    if has_in_newline_expr_first(node) {
+        return true;
+    };
     node.parent()
         .map(|node| ast::ExprStmt::can_cast(node.kind()) || ast::StmtList::can_cast(node.kind()))
         .unwrap_or(false)
 }
 
+/// Similar to `has_parens`, heuristic sensing incomplete statement before ambiguous `Expr`
+///
+/// Heuristic:
+///
+/// If the `PathExpr` is left part of the `Expr` and there is a newline after the `PathExpr`,
+/// it is considered that the `PathExpr` is not part of the `Expr`.
+fn has_in_newline_expr_first(node: &SyntaxNode) -> bool {
+    if ast::PathExpr::can_cast(node.kind())
+        && let Some(NodeOrToken::Token(next)) = node.next_sibling_or_token()
+        && next.kind() == SyntaxKind::WHITESPACE
+        && next.text().contains('\n')
+        && let Some(stmt_like) = node
+            .ancestors()
+            .take_while(|it| it.text_range().start() == node.text_range().start())
+            .filter_map(Either::<ast::ExprStmt, ast::Expr>::cast)
+            .last()
+    {
+        stmt_like.syntax().parent().and_then(ast::StmtList::cast).is_some()
+    } else {
+        false
+    }
+}
+
+fn is_after_if_expr(node: SyntaxNode) -> bool {
+    let node = match node.parent().and_then(Either::<ast::ExprStmt, ast::MatchArm>::cast) {
+        Some(stmt) => stmt.syntax().clone(),
+        None => node,
+    };
+    let prev_sibling =
+        non_trivia_sibling(node.into(), Direction::Prev).and_then(NodeOrToken::into_node);
+    iter::successors(prev_sibling, |it| it.last_child_or_token()?.into_node())
+        .find_map(ast::IfExpr::cast)
+        .is_some()
+}
+
 fn next_non_trivia_token(e: impl Into<SyntaxElement>) -> Option<SyntaxToken> {
     let mut token = match e.into() {
         SyntaxElement::Node(n) => n.last_token()?,
diff --git a/crates/ide-completion/src/context/tests.rs b/crates/ide-completion/src/context/tests.rs
index e798f3b..51d28bd 100644
--- a/crates/ide-completion/src/context/tests.rs
+++ b/crates/ide-completion/src/context/tests.rs
@@ -10,7 +10,7 @@
     let (db, pos) = position(ra_fixture);
     let config = TEST_CONFIG;
     let (completion_context, _analysis) =
-        hir::attach_db(&db, || CompletionContext::new(&db, pos, &config).unwrap());
+        hir::attach_db(&db, || CompletionContext::new(&db, pos, &config, None).unwrap());
 
     let ty = completion_context
         .expected_type
diff --git a/crates/ide-completion/src/item.rs b/crates/ide-completion/src/item.rs
index 5fb9dc9..303c712 100644
--- a/crates/ide-completion/src/item.rs
+++ b/crates/ide-completion/src/item.rs
@@ -9,6 +9,7 @@
     imports::import_assets::LocatedImport,
 };
 use itertools::Itertools;
+use macros::UpmapFromRaFixture;
 use smallvec::SmallVec;
 use stdx::{format_to, impl_from, never};
 use syntax::{Edition, SmolStr, TextRange, TextSize, format_smolstr};
@@ -23,7 +24,7 @@
 ///
 /// It is basically a POD with various properties. To construct a [`CompletionItem`],
 /// use [`Builder::new`] method and the [`Builder`] struct.
-#[derive(Clone)]
+#[derive(Clone, UpmapFromRaFixture)]
 #[non_exhaustive]
 pub struct CompletionItem {
     /// Label in the completion pop up which identifies completion.
diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs
index a70a113..8a0aaf3 100644
--- a/crates/ide-completion/src/lib.rs
+++ b/crates/ide-completion/src/lib.rs
@@ -187,7 +187,7 @@
     position: FilePosition,
     trigger_character: Option<char>,
 ) -> Option<Vec<CompletionItem>> {
-    let (ctx, analysis) = &CompletionContext::new(db, position, config)?;
+    let (ctx, analysis) = &CompletionContext::new(db, position, config, trigger_character)?;
     let mut completions = Completions::default();
 
     // prevent `(` from triggering unwanted completion noise
@@ -241,6 +241,7 @@
                 completions::extern_abi::complete_extern_abi(acc, ctx, expanded);
                 completions::format_string::format_string(acc, ctx, original, expanded);
                 completions::env_vars::complete_cargo_env_vars(acc, ctx, original, expanded);
+                completions::ra_fixture::complete_ra_fixture(acc, ctx, original, expanded);
             }
             CompletionAnalysis::UnexpandedAttrTT {
                 colon_prefix,
diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs
index 094e679..c0f09e1 100644
--- a/crates/ide-completion/src/render.rs
+++ b/crates/ide-completion/src/render.rs
@@ -171,8 +171,7 @@
             builder.insert(receiver.syntax().text_range().start(), "(".to_owned());
             builder.insert(ctx.source_range().end(), ")".to_owned());
 
-            let is_parens_needed =
-                !matches!(dot_access.kind, DotAccessKind::Method { has_parens: true });
+            let is_parens_needed = !matches!(dot_access.kind, DotAccessKind::Method);
 
             if is_parens_needed {
                 builder.insert(ctx.source_range().end(), "()".to_owned());
diff --git a/crates/ide-completion/src/render/function.rs b/crates/ide-completion/src/render/function.rs
index c466019..3235323 100644
--- a/crates/ide-completion/src/render/function.rs
+++ b/crates/ide-completion/src/render/function.rs
@@ -93,8 +93,8 @@
             has_call_parens,
             ..
         }) => (false, has_call_parens, ctx.completion.config.snippet_cap),
-        FuncKind::Method(&DotAccess { kind: DotAccessKind::Method { has_parens }, .. }, _) => {
-            (true, has_parens, ctx.completion.config.snippet_cap)
+        FuncKind::Method(&DotAccess { kind: DotAccessKind::Method, .. }, _) => {
+            (true, true, ctx.completion.config.snippet_cap)
         }
         FuncKind::Method(DotAccess { kind: DotAccessKind::Field { .. }, .. }, _) => {
             (true, false, ctx.completion.config.snippet_cap)
diff --git a/crates/ide-completion/src/render/variant.rs b/crates/ide-completion/src/render/variant.rs
index 42324b4..37d0fa1 100644
--- a/crates/ide-completion/src/render/variant.rs
+++ b/crates/ide-completion/src/render/variant.rs
@@ -26,14 +26,23 @@
         return RenderedLiteral { literal: path.to_owned(), detail: path.to_owned() };
     }
     let completions = fields.iter().enumerate().format_with(", ", |(idx, field), f| {
+        let mut fmt_field = |fill, tab| {
+            let field_name = field.name(ctx.db);
+
+            if let Some(local) = ctx.locals.get(&field_name)
+                && local
+                    .ty(ctx.db)
+                    .could_unify_with_deeply(ctx.db, &field.ty(ctx.db).to_type(ctx.db))
+            {
+                f(&format_args!("{}{tab}", field_name.display(ctx.db, ctx.edition)))
+            } else {
+                f(&format_args!("{}: {fill}", field_name.display(ctx.db, ctx.edition)))
+            }
+        };
         if snippet_cap.is_some() {
-            f(&format_args!(
-                "{}: ${{{}:()}}",
-                field.name(ctx.db).display(ctx.db, ctx.edition),
-                idx + 1
-            ))
+            fmt_field(format_args!("${{{}:()}}", idx + 1), format_args!("${}", idx + 1))
         } else {
-            f(&format_args!("{}: ()", field.name(ctx.db).display(ctx.db, ctx.edition)))
+            fmt_field(format_args!("()"), format_args!(""))
         }
     });
 
diff --git a/crates/ide-completion/src/tests.rs b/crates/ide-completion/src/tests.rs
index ec9cd9f..83606d2 100644
--- a/crates/ide-completion/src/tests.rs
+++ b/crates/ide-completion/src/tests.rs
@@ -29,7 +29,7 @@
 use hir::db::HirDatabase;
 use hir::{PrefixKind, setup_tracing};
 use ide_db::{
-    FilePosition, RootDatabase, SnippetCap,
+    FilePosition, MiniCore, RootDatabase, SnippetCap,
     imports::insert_use::{ImportGranularity, InsertUseConfig},
 };
 use itertools::Itertools;
@@ -90,6 +90,7 @@
     exclude_traits: &[],
     enable_auto_await: true,
     enable_auto_iter: true,
+    minicore: MiniCore::default(),
 };
 
 pub(crate) fn completion_list(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String {
@@ -245,11 +246,10 @@
     let (db, position) = position(ra_fixture_before);
     let completions: Vec<CompletionItem> =
         hir::attach_db(&db, || crate::completions(&db, &config, position, None).unwrap());
-    let (completion,) = completions
-        .iter()
-        .filter(|it| it.lookup() == what)
-        .collect_tuple()
-        .unwrap_or_else(|| panic!("can't find {what:?} completion in {completions:#?}"));
+    let Some((completion,)) = completions.iter().filter(|it| it.lookup() == what).collect_tuple()
+    else {
+        panic!("can't find {what:?} completion in {completions:#?}")
+    };
     let mut actual = db.file_text(position.file_id).text(&db).to_string();
 
     let mut combined_edit = completion.text_edit.clone();
diff --git a/crates/ide-completion/src/tests/attribute.rs b/crates/ide-completion/src/tests/attribute.rs
index 1d2a9c7..2a62389 100644
--- a/crates/ide-completion/src/tests/attribute.rs
+++ b/crates/ide-completion/src/tests/attribute.rs
@@ -33,6 +33,7 @@
             at diagnostic::do_not_recommend
             at diagnostic::on_unimplemented
             at doc = "…"
+            at doc = include_str!("…")
             at doc(alias = "…")
             at doc(hidden)
             at expect(…)
@@ -85,6 +86,7 @@
             at deprecated
             at derive(…)
             at doc = "…"
+            at doc = include_str!("…")
             at doc(alias = "…")
             at doc(hidden)
             at expect(…)
@@ -158,6 +160,7 @@
             at deny(…)
             at deprecated
             at doc = "…"
+            at doc = include_str!("…")
             at doc(alias = "…")
             at doc(hidden)
             at expect(…)
@@ -189,6 +192,7 @@
             at deny(…)
             at deprecated
             at doc = "…"
+            at doc = include_str!("…")
             at doc(alias = "…")
             at doc(hidden)
             at expect(…)
@@ -212,6 +216,7 @@
             at deny(…)
             at deprecated
             at doc = "…"
+            at doc = include_str!("…")
             at doc(alias = "…")
             at doc(hidden)
             at expect(…)
@@ -238,6 +243,7 @@
             at deny(…)
             at deprecated
             at doc = "…"
+            at doc = include_str!("…")
             at doc(alias = "…")
             at doc(hidden)
             at expect(…)
@@ -264,6 +270,7 @@
             at deny(…)
             at deprecated
             at doc = "…"
+            at doc = include_str!("…")
             at doc(alias = "…")
             at doc(hidden)
             at expect(…)
@@ -288,6 +295,7 @@
             at deny(…)
             at deprecated
             at doc = "…"
+            at doc = include_str!("…")
             at doc(alias = "…")
             at doc(hidden)
             at expect(…)
@@ -313,6 +321,7 @@
             at deny(…)
             at deprecated
             at doc = "…"
+            at doc = include_str!("…")
             at doc(alias = "…")
             at doc(hidden)
             at expect(…)
@@ -337,6 +346,7 @@
             at deny(…)
             at deprecated
             at doc = "…"
+            at doc = include_str!("…")
             at doc(alias = "…")
             at doc(hidden)
             at expect(…)
@@ -368,6 +378,7 @@
             at derive(…)
             at derive_const macro derive_const
             at doc = "…"
+            at doc = include_str!("…")
             at doc(alias = "…")
             at doc(hidden)
             at expect(…)
@@ -396,6 +407,7 @@
             at deprecated
             at derive(…)
             at doc = "…"
+            at doc = include_str!("…")
             at doc(alias = "…")
             at doc(hidden)
             at expect(…)
@@ -422,6 +434,7 @@
             at deny(…)
             at deprecated
             at doc = "…"
+            at doc = include_str!("…")
             at doc(alias = "…")
             at doc(hidden)
             at expect(…)
@@ -446,6 +459,7 @@
             at deny(…)
             at deprecated
             at doc = "…"
+            at doc = include_str!("…")
             at doc(alias = "…")
             at doc(hidden)
             at expect(…)
@@ -476,6 +490,7 @@
             at deprecated
             at diagnostic::on_unimplemented
             at doc = "…"
+            at doc = include_str!("…")
             at doc(alias = "…")
             at doc(hidden)
             at expect(…)
@@ -502,6 +517,7 @@
             at deprecated
             at diagnostic::do_not_recommend
             at doc = "…"
+            at doc = include_str!("…")
             at doc(alias = "…")
             at doc(hidden)
             at expect(…)
@@ -522,6 +538,7 @@
             at deny(…)
             at deprecated
             at doc = "…"
+            at doc = include_str!("…")
             at doc(alias = "…")
             at doc(hidden)
             at expect(…)
@@ -548,6 +565,7 @@
             at deprecated
             at do_not_recommend
             at doc = "…"
+            at doc = include_str!("…")
             at doc(alias = "…")
             at doc(hidden)
             at expect(…)
@@ -566,6 +584,7 @@
             at deny(…)
             at deprecated
             at doc = "…"
+            at doc = include_str!("…")
             at doc(alias = "…")
             at doc(hidden)
             at expect(…)
@@ -616,6 +635,7 @@
             at deny(…)
             at deprecated
             at doc = "…"
+            at doc = include_str!("…")
             at doc(alias = "…")
             at doc(hidden)
             at expect(…)
@@ -637,6 +657,7 @@
             at deny(…)
             at deprecated
             at doc = "…"
+            at doc = include_str!("…")
             at doc(alias = "…")
             at doc(hidden)
             at expect(…)
@@ -682,6 +703,7 @@
             at deny(…)
             at deprecated
             at doc = "…"
+            at doc = include_str!("…")
             at doc(alias = "…")
             at doc(hidden)
             at expect(…)
@@ -724,6 +746,7 @@
             at diagnostic::do_not_recommend
             at diagnostic::on_unimplemented
             at doc = "…"
+            at doc = include_str!("…")
             at doc(alias = "…")
             at doc(hidden)
             at expect(…)
diff --git a/crates/ide-completion/src/tests/expression.rs b/crates/ide-completion/src/tests/expression.rs
index 5363a68..4033aa5 100644
--- a/crates/ide-completion/src/tests/expression.rs
+++ b/crates/ide-completion/src/tests/expression.rs
@@ -1869,6 +1869,298 @@
             sn ppd
         "#]],
     );
+    check(
+        r#"
+fn foo() { [if foo {} $0]}
+"#,
+        expect![[r#"
+            fn foo()  fn()
+            bt u32     u32
+            kw async
+            kw const
+            kw crate::
+            kw else
+            kw else if
+            kw enum
+            kw extern
+            kw false
+            kw fn
+            kw for
+            kw if
+            kw if let
+            kw impl
+            kw impl for
+            kw let
+            kw letm
+            kw loop
+            kw match
+            kw mod
+            kw return
+            kw self::
+            kw static
+            kw struct
+            kw trait
+            kw true
+            kw type
+            kw union
+            kw unsafe
+            kw use
+            kw while
+            kw while let
+            sn macro_rules
+            sn pd
+            sn ppd
+        "#]],
+    );
+    check(
+        r#"
+fn foo() { [if foo {} el$0]}
+"#,
+        expect![[r#"
+            fn foo()  fn()
+            bt u32     u32
+            kw async
+            kw const
+            kw crate::
+            kw else
+            kw else if
+            kw enum
+            kw extern
+            kw false
+            kw fn
+            kw for
+            kw if
+            kw if let
+            kw impl
+            kw impl for
+            kw let
+            kw letm
+            kw loop
+            kw match
+            kw mod
+            kw return
+            kw self::
+            kw static
+            kw struct
+            kw trait
+            kw true
+            kw type
+            kw union
+            kw unsafe
+            kw use
+            kw while
+            kw while let
+            sn macro_rules
+            sn pd
+            sn ppd
+        "#]],
+    );
+    check(
+        r#"
+fn foo() { 2 + if foo {} $0 }
+"#,
+        expect![[r#"
+            fn foo()  fn()
+            bt u32     u32
+            kw async
+            kw const
+            kw crate::
+            kw else
+            kw else if
+            kw enum
+            kw extern
+            kw false
+            kw fn
+            kw for
+            kw if
+            kw if let
+            kw impl
+            kw impl for
+            kw let
+            kw letm
+            kw loop
+            kw match
+            kw mod
+            kw return
+            kw self::
+            kw static
+            kw struct
+            kw trait
+            kw true
+            kw type
+            kw union
+            kw unsafe
+            kw use
+            kw while
+            kw while let
+            sn macro_rules
+            sn pd
+            sn ppd
+        "#]],
+    );
+    check(
+        r#"
+fn foo() { -if foo {} $0 }
+"#,
+        expect![[r#"
+            fn foo()  fn()
+            bt u32     u32
+            kw async
+            kw const
+            kw crate::
+            kw else
+            kw else if
+            kw enum
+            kw extern
+            kw false
+            kw fn
+            kw for
+            kw if
+            kw if let
+            kw impl
+            kw impl for
+            kw let
+            kw letm
+            kw loop
+            kw match
+            kw mod
+            kw return
+            kw self::
+            kw static
+            kw struct
+            kw trait
+            kw true
+            kw type
+            kw union
+            kw unsafe
+            kw use
+            kw while
+            kw while let
+            sn macro_rules
+            sn pd
+            sn ppd
+        "#]],
+    );
+    check(
+        r#"
+fn foo() { &mut if foo {} $0 }
+"#,
+        expect![[r#"
+            fn foo()  fn()
+            bt u32     u32
+            kw async
+            kw const
+            kw crate::
+            kw else
+            kw else if
+            kw enum
+            kw extern
+            kw false
+            kw fn
+            kw for
+            kw if
+            kw if let
+            kw impl
+            kw impl for
+            kw let
+            kw letm
+            kw loop
+            kw match
+            kw mod
+            kw return
+            kw self::
+            kw static
+            kw struct
+            kw trait
+            kw true
+            kw type
+            kw union
+            kw unsafe
+            kw use
+            kw while
+            kw while let
+            sn macro_rules
+            sn pd
+            sn ppd
+        "#]],
+    );
+    check(
+        r#"
+fn foo() { return if foo {} $0 }
+"#,
+        expect![[r#"
+            fn foo()  fn()
+            bt u32     u32
+            kw async
+            kw const
+            kw crate::
+            kw else
+            kw else if
+            kw enum
+            kw extern
+            kw false
+            kw fn
+            kw for
+            kw if
+            kw if let
+            kw impl
+            kw impl for
+            kw let
+            kw letm
+            kw loop
+            kw match
+            kw mod
+            kw return
+            kw self::
+            kw static
+            kw struct
+            kw trait
+            kw true
+            kw type
+            kw union
+            kw unsafe
+            kw use
+            kw while
+            kw while let
+            sn macro_rules
+            sn pd
+            sn ppd
+        "#]],
+    );
+    check(
+        r#"
+fn foo() { match () { () => if foo {} $0 } }
+"#,
+        expect![[r#"
+            kw else
+            kw else if
+            kw mut
+            kw ref
+        "#]],
+    );
+    check(
+        r#"
+fn foo() { match () { () => if foo {} $0, } }
+"#,
+        expect![[r#"
+            kw else
+            kw else if
+            kw mut
+            kw ref
+        "#]],
+    );
+    check(
+        r#"
+fn foo() { match () { () => if foo {} $0, _ => (), } }
+"#,
+        expect![[r#"
+            kw else
+            kw else if
+            kw mut
+            kw ref
+        "#]],
+    );
+    // FIXME: support else completion after ast::RecordExprField
 }
 
 #[test]
@@ -2937,8 +3229,51 @@
 }
 
 #[test]
+fn ambiguous_float_literal_in_ambiguous_method_call() {
+    check(
+        r#"
+#![rustc_coherence_is_core]
+
+impl i32 {
+    pub fn int_method(self) {}
+}
+impl f64 {
+    pub fn float_method(self) {}
+}
+
+fn foo() -> (i32, i32) {
+    1.$0
+    (2, 3)
+}
+    "#,
+        expect![[r#"
+            me int_method() fn(self)
+            sn box    Box::new(expr)
+            sn call   function(expr)
+            sn const        const {}
+            sn dbg        dbg!(expr)
+            sn dbgr      dbg!(&expr)
+            sn deref           *expr
+            sn let               let
+            sn letm          let mut
+            sn match   match expr {}
+            sn ref             &expr
+            sn refm        &mut expr
+            sn return    return expr
+            sn unsafe      unsafe {}
+        "#]],
+    );
+}
+
+#[test]
 fn let_in_condition() {
     check_edit("let", r#"fn f() { if $0 {} }"#, r#"fn f() { if let $1 = $0 {} }"#);
+    check_edit("let", r#"fn f() { if $0x {} }"#, r#"fn f() { if let $1 = $0x {} }"#);
+    check_edit(
+        "let",
+        r#"fn f() { if $0foo.bar() {} }"#,
+        r#"fn f() { if let $1 = $0foo.bar() {} }"#,
+    );
 }
 
 #[test]
@@ -2947,6 +3282,293 @@
 }
 
 #[test]
+fn let_in_previous_line_of_ambiguous_expr() {
+    check_edit(
+        "let",
+        r#"
+        fn f() {
+            $0
+            (1, 2).foo();
+        }"#,
+        r#"
+        fn f() {
+            let $1 = $0;
+            (1, 2).foo();
+        }"#,
+    );
+
+    check_edit(
+        "let",
+        r#"
+        fn f() {
+            $0
+            (1, 2)
+        }"#,
+        r#"
+        fn f() {
+            let $1 = $0;
+            (1, 2)
+        }"#,
+    );
+
+    check_edit(
+        "let",
+        r#"
+        fn f() -> i32 {
+            $0
+            -2
+        }"#,
+        r#"
+        fn f() -> i32 {
+            let $1 = $0;
+            -2
+        }"#,
+    );
+
+    check_edit(
+        "let",
+        r#"
+        fn f() -> [i32; 2] {
+            $0
+            [1, 2]
+        }"#,
+        r#"
+        fn f() -> [i32; 2] {
+            let $1 = $0;
+            [1, 2]
+        }"#,
+    );
+
+    check_edit(
+        "let",
+        r#"
+        fn f() -> [u8; 2] {
+            $0
+            *b"01"
+        }"#,
+        r#"
+        fn f() -> [u8; 2] {
+            let $1 = $0;
+            *b"01"
+        }"#,
+    );
+
+    check(
+        r#"
+        fn foo() {
+            $0
+            *b"01"
+        }"#,
+        expect![[r#"
+            fn foo()  fn()
+            bt u32     u32
+            kw async
+            kw const
+            kw crate::
+            kw enum
+            kw extern
+            kw false
+            kw fn
+            kw for
+            kw if
+            kw if let
+            kw impl
+            kw impl for
+            kw let
+            kw letm
+            kw loop
+            kw match
+            kw mod
+            kw return
+            kw self::
+            kw static
+            kw struct
+            kw trait
+            kw true
+            kw type
+            kw union
+            kw unsafe
+            kw use
+            kw while
+            kw while let
+            sn macro_rules
+            sn pd
+            sn ppd
+        "#]],
+    );
+
+    check(
+        r#"
+        fn foo() {
+            match $0 {}
+        }"#,
+        expect![[r#"
+            fn foo() fn()
+            bt u32    u32
+            kw const
+            kw crate::
+            kw false
+            kw for
+            kw if
+            kw if let
+            kw loop
+            kw match
+            kw return
+            kw self::
+            kw true
+            kw unsafe
+            kw while
+            kw while let
+        "#]],
+    );
+
+    check(
+        r#"
+        fn foo() {
+            $0 *b"01"
+        }"#,
+        expect![[r#"
+            fn foo() fn()
+            bt u32    u32
+            kw const
+            kw crate::
+            kw false
+            kw for
+            kw if
+            kw if let
+            kw loop
+            kw match
+            kw return
+            kw self::
+            kw true
+            kw unsafe
+            kw while
+            kw while let
+        "#]],
+    );
+}
+
+#[test]
+fn field_in_previous_line_of_ambiguous_expr() {
+    check(
+        r#"
+        struct Foo { field: i32 }
+        impl Foo {
+            fn method(&self) {}
+        }
+        fn foo() -> (i32, i32) {
+            let foo = Foo { field: 4 };
+            foo.$0
+            (2, 3)
+        }"#,
+        expect![[r#"
+            fd field           i32
+            me method()  fn(&self)
+            sn box  Box::new(expr)
+            sn call function(expr)
+            sn const      const {}
+            sn dbg      dbg!(expr)
+            sn dbgr    dbg!(&expr)
+            sn deref         *expr
+            sn let             let
+            sn letm        let mut
+            sn match match expr {}
+            sn ref           &expr
+            sn refm      &mut expr
+            sn return  return expr
+            sn unsafe    unsafe {}
+        "#]],
+    );
+
+    check(
+        r#"
+        struct Foo { field: i32 }
+        impl Foo {
+            fn method(&self) {}
+        }
+        fn foo() -> (i32, i32) {
+            let foo = Foo { field: 4 };
+            foo.a$0
+            (2, 3)
+        }"#,
+        expect![[r#"
+            fd field           i32
+            me method()  fn(&self)
+            sn box  Box::new(expr)
+            sn call function(expr)
+            sn const      const {}
+            sn dbg      dbg!(expr)
+            sn dbgr    dbg!(&expr)
+            sn deref         *expr
+            sn let             let
+            sn letm        let mut
+            sn match match expr {}
+            sn ref           &expr
+            sn refm      &mut expr
+            sn return  return expr
+            sn unsafe    unsafe {}
+        "#]],
+    );
+}
+
+#[test]
+fn fn_field_in_previous_line_of_ambiguous_expr() {
+    check(
+        r#"
+        struct Foo { field: fn() }
+        impl Foo {
+            fn method(&self) {}
+        }
+        fn foo() -> (i32, i32) {
+            let foo = Foo { field: || () };
+            foo.$0
+            (2, 3)
+        }"#,
+        expect![[r#"
+            fd field          fn()
+            me method()  fn(&self)
+            sn box  Box::new(expr)
+            sn call function(expr)
+            sn const      const {}
+            sn dbg      dbg!(expr)
+            sn dbgr    dbg!(&expr)
+            sn deref         *expr
+            sn let             let
+            sn letm        let mut
+            sn match match expr {}
+            sn ref           &expr
+            sn refm      &mut expr
+            sn return  return expr
+            sn unsafe    unsafe {}
+        "#]],
+    );
+
+    check_edit(
+        "field",
+        r#"
+        struct Foo { field: fn() }
+        impl Foo {
+            fn method(&self) {}
+        }
+        fn foo() -> (i32, i32) {
+            let foo = Foo { field: || () };
+            foo.a$0
+            (2, 3)
+        }"#,
+        r#"
+        struct Foo { field: fn() }
+        impl Foo {
+            fn method(&self) {}
+        }
+        fn foo() -> (i32, i32) {
+            let foo = Foo { field: || () };
+            (foo.field)()
+            (2, 3)
+        }"#,
+    );
+}
+
+#[test]
 fn private_inherent_and_public_trait() {
     check(
         r#"
diff --git a/crates/ide-completion/src/tests/flyimport.rs b/crates/ide-completion/src/tests/flyimport.rs
index 2d3ebad..0cd4208 100644
--- a/crates/ide-completion/src/tests/flyimport.rs
+++ b/crates/ide-completion/src/tests/flyimport.rs
@@ -16,7 +16,8 @@
     expect: Expect,
 ) {
     let (db, position) = crate::tests::position(ra_fixture);
-    let (ctx, analysis) = crate::context::CompletionContext::new(&db, position, &config).unwrap();
+    let (ctx, analysis) =
+        crate::context::CompletionContext::new(&db, position, &config, None).unwrap();
 
     let mut acc = crate::completions::Completions::default();
     hir::attach_db(ctx.db, || {
diff --git a/crates/ide-completion/src/tests/item.rs b/crates/ide-completion/src/tests/item.rs
index ed87b33..61a9da8 100644
--- a/crates/ide-completion/src/tests/item.rs
+++ b/crates/ide-completion/src/tests/item.rs
@@ -23,6 +23,10 @@
             un Union                  Union
             bt u32                      u32
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     )
@@ -45,6 +49,10 @@
             un Union                  Union
             bt u32                      u32
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     )
diff --git a/crates/ide-completion/src/tests/predicate.rs b/crates/ide-completion/src/tests/predicate.rs
index 65036f6..682b890 100644
--- a/crates/ide-completion/src/tests/predicate.rs
+++ b/crates/ide-completion/src/tests/predicate.rs
@@ -22,6 +22,10 @@
             un Union                  Union
             bt u32                      u32
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -95,6 +99,10 @@
             un Union                  Union
             bt u32                      u32
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -120,6 +128,10 @@
             un Union                  Union
             bt u32                      u32
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs
index c438ca7..59a0c14 100644
--- a/crates/ide-completion/src/tests/special.rs
+++ b/crates/ide-completion/src/tests/special.rs
@@ -1492,6 +1492,10 @@
         expect![[r#"
             bt u32 u32
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -1506,6 +1510,10 @@
             tp T
             bt u32 u32
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -1531,6 +1539,10 @@
         expect![[r#"
             bt u32 u32
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
diff --git a/crates/ide-completion/src/tests/type_pos.rs b/crates/ide-completion/src/tests/type_pos.rs
index 125e11e..3bbba18 100644
--- a/crates/ide-completion/src/tests/type_pos.rs
+++ b/crates/ide-completion/src/tests/type_pos.rs
@@ -25,6 +25,10 @@
             un Union                  Union
             bt u32                      u32
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     )
@@ -50,6 +54,10 @@
             un Union                  Union
             bt u32                      u32
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw pub
             kw pub(crate)
             kw pub(super)
@@ -76,6 +84,37 @@
             un Union                  Union
             bt u32                      u32
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
+            kw self::
+        "#]],
+    );
+}
+
+#[test]
+fn fn_return_type_after_reference() {
+    check_with_base_items(
+        r#"
+fn x<'lt, T, const C: usize>(_: &()) -> &$0
+"#,
+        expect![[r#"
+            en Enum                    Enum
+            ma makro!(…) macro_rules! makro
+            md module
+            st Record                Record
+            st Tuple                  Tuple
+            st Unit                    Unit
+            tt Trait
+            tp T
+            un Union                  Union
+            bt u32                      u32
+            kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -106,6 +145,10 @@
             bt u32                      u32
             it ()
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     )
@@ -131,6 +174,10 @@
             bt u32                      u32
             it Foo<i32>
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -157,6 +204,10 @@
             bt u32                      u32
             it i32
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -185,6 +236,10 @@
             bt u32                      u32
             it u64
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -210,6 +265,10 @@
             bt u32                      u32
             it u64
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -236,6 +295,10 @@
             bt u32                      u32
             it i32
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -270,6 +333,10 @@
             bt u32                      u32
             it a::Foo<a::Foo<i32>>
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -299,6 +366,10 @@
             bt u32                      u32
             it Foo<i32>
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -325,6 +396,10 @@
             un Union                  Union
             bt u32                      u32
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -392,6 +467,10 @@
             un Union                  Union
             bt u32                      u32
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -442,6 +521,10 @@
             un Union                      Union
             bt u32                          u32
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -487,6 +570,10 @@
             un Union                  Union
             bt u32                      u32
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -512,6 +599,10 @@
             un Union                  Union
             bt u32                      u32
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -555,6 +646,10 @@
             un Union                  Union
             bt u32                      u32
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -582,6 +677,10 @@
             un Union                      Union
             bt u32                          u32
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -625,6 +724,10 @@
             un Union                  Union
             bt u32                      u32
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -650,6 +753,10 @@
             un Union                  Union
             bt u32                      u32
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -666,6 +773,10 @@
             ct CONST                   Unit
             ma makro!(…) macro_rules! makro
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -690,6 +801,10 @@
             st Foo  Foo
             bt u32  u32
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     )
@@ -716,6 +831,10 @@
             st S      S
             bt u32  u32
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     )
@@ -745,6 +864,10 @@
             un Union                  Union
             bt u32                      u32
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -765,6 +888,10 @@
             ct X                      usize
             ma makro!(…) macro_rules! makro
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -791,6 +918,10 @@
             un Union                  Union
             bt u32                      u32
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -808,6 +939,10 @@
             ct X                      usize
             ma makro!(…) macro_rules! makro
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -835,6 +970,10 @@
             un Union                  Union
             bt u32                      u32
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -852,6 +991,10 @@
             ct X                      usize
             ma makro!(…) macro_rules! makro
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -870,6 +1013,10 @@
             ct X                      usize
             ma makro!(…) macro_rules! makro
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -889,6 +1036,10 @@
             ct X                      usize
             ma makro!(…) macro_rules! makro
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -907,6 +1058,10 @@
             ct X                      usize
             ma makro!(…) macro_rules! makro
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -923,6 +1078,10 @@
             ct X                      usize
             ma makro!(…) macro_rules! makro
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -941,6 +1100,10 @@
             ct X                      usize
             ma makro!(…) macro_rules! makro
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -955,6 +1118,10 @@
             ct CONST                   Unit
             ma makro!(…) macro_rules! makro
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -968,6 +1135,10 @@
             ct CONST                   Unit
             ma makro!(…) macro_rules! makro
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
@@ -980,6 +1151,10 @@
             lt 'a
             ma makro!(…) macro_rules! makro
             kw crate::
+            kw dyn
+            kw fn
+            kw for
+            kw impl
             kw self::
         "#]],
     );
diff --git a/crates/ide-db/Cargo.toml b/crates/ide-db/Cargo.toml
index e065adb..b714816 100644
--- a/crates/ide-db/Cargo.toml
+++ b/crates/ide-db/Cargo.toml
@@ -30,6 +30,7 @@
 triomphe.workspace = true
 nohash-hasher.workspace = true
 bitflags.workspace = true
+smallvec.workspace = true
 
 # local deps
 base-db.workspace = true
@@ -42,15 +43,15 @@
 # ide should depend only on the top-level `hir` package. if you need
 # something from some `hir-xxx` subpackage, reexport the API via `hir`.
 hir.workspace = true
+macros.workspace = true
+
+test-utils.workspace = true
+test-fixture.workspace = true
 
 line-index.workspace = true
 
 [dev-dependencies]
 expect-test = "1.5.1"
 
-# local deps
-test-utils.workspace = true
-test-fixture.workspace = true
-
 [lints]
 workspace = true
diff --git a/crates/ide-db/src/lib.rs b/crates/ide-db/src/lib.rs
index 44bccd8..7efa97b 100644
--- a/crates/ide-db/src/lib.rs
+++ b/crates/ide-db/src/lib.rs
@@ -2,6 +2,8 @@
 //!
 //! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search.
 
+extern crate self as ide_db;
+
 mod apply_change;
 
 pub mod active_parameter;
@@ -14,6 +16,8 @@
 pub mod label;
 pub mod path_transform;
 pub mod prime_caches;
+pub mod ra_fixture;
+pub mod range_mapper;
 pub mod rename;
 pub mod rust_doc;
 pub mod search;
@@ -364,3 +368,25 @@
     WeakWarning,
     Allow,
 }
+
+#[derive(Debug, Clone, Copy)]
+pub struct MiniCore<'a>(&'a str);
+
+impl<'a> MiniCore<'a> {
+    #[inline]
+    pub fn new(minicore: &'a str) -> Self {
+        Self(minicore)
+    }
+
+    #[inline]
+    pub const fn default() -> Self {
+        Self(test_utils::MiniCore::RAW_SOURCE)
+    }
+}
+
+impl<'a> Default for MiniCore<'a> {
+    #[inline]
+    fn default() -> Self {
+        Self::default()
+    }
+}
diff --git a/crates/ide-db/src/ra_fixture.rs b/crates/ide-db/src/ra_fixture.rs
new file mode 100644
index 0000000..1f056a8
--- /dev/null
+++ b/crates/ide-db/src/ra_fixture.rs
@@ -0,0 +1,532 @@
+//! Working with the fixtures in r-a tests, and providing IDE services for them.
+
+use std::hash::{BuildHasher, Hash};
+
+use hir::{CfgExpr, FilePositionWrapper, FileRangeWrapper, Semantics};
+use smallvec::SmallVec;
+use span::{TextRange, TextSize};
+use syntax::{
+    AstToken, SmolStr,
+    ast::{self, IsString},
+};
+
+use crate::{
+    MiniCore, RootDatabase, SymbolKind, active_parameter::ActiveParameter,
+    documentation::Documentation, range_mapper::RangeMapper, search::ReferenceCategory,
+};
+
+pub use span::FileId;
+
+impl RootDatabase {
+    fn from_ra_fixture(
+        text: &str,
+        minicore: MiniCore<'_>,
+    ) -> Result<(RootDatabase, Vec<(FileId, usize)>, Vec<FileId>), ()> {
+        // We don't want a mistake in the fixture to crash r-a, so we wrap this in `catch_unwind()`.
+        std::panic::catch_unwind(|| {
+            let mut db = RootDatabase::default();
+            let fixture = test_fixture::ChangeFixture::parse_with_proc_macros(
+                &db,
+                text,
+                minicore.0,
+                Vec::new(),
+            );
+            db.apply_change(fixture.change);
+            let files = fixture
+                .files
+                .into_iter()
+                .zip(fixture.file_lines)
+                .map(|(file_id, range)| (file_id.file_id(&db), range))
+                .collect();
+            (db, files, fixture.sysroot_files)
+        })
+        .map_err(|error| {
+            tracing::error!(
+                "cannot crate the crate graph: {}\nCrate graph:\n{}\n",
+                if let Some(&s) = error.downcast_ref::<&'static str>() {
+                    s
+                } else if let Some(s) = error.downcast_ref::<String>() {
+                    s.as_str()
+                } else {
+                    "Box<dyn Any>"
+                },
+                text,
+            );
+        })
+    }
+}
+
+pub struct RaFixtureAnalysis {
+    pub db: RootDatabase,
+    tmp_file_ids: Vec<(FileId, usize)>,
+    line_offsets: Vec<TextSize>,
+    virtual_file_id_to_line: Vec<usize>,
+    mapper: RangeMapper,
+    literal: ast::String,
+    // `minicore` etc..
+    sysroot_files: Vec<FileId>,
+    combined_len: TextSize,
+}
+
+impl RaFixtureAnalysis {
+    pub fn analyze_ra_fixture(
+        sema: &Semantics<'_, RootDatabase>,
+        literal: ast::String,
+        expanded: &ast::String,
+        minicore: MiniCore<'_>,
+        on_cursor: &mut dyn FnMut(TextRange),
+    ) -> Option<RaFixtureAnalysis> {
+        if !literal.is_raw() {
+            return None;
+        }
+
+        let active_parameter = ActiveParameter::at_token(sema, expanded.syntax().clone())?;
+        let has_rust_fixture_attr = active_parameter.attrs().is_some_and(|attrs| {
+            attrs.filter_map(|attr| attr.as_simple_path()).any(|path| {
+                path.segments()
+                    .zip(["rust_analyzer", "rust_fixture"])
+                    .all(|(seg, name)| seg.name_ref().map_or(false, |nr| nr.text() == name))
+            })
+        });
+        if !has_rust_fixture_attr {
+            return None;
+        }
+        let value = literal.value().ok()?;
+
+        let mut mapper = RangeMapper::default();
+
+        // This is used for the `Injector`, to resolve precise location in the string literal,
+        // which will then be used to resolve precise location in the enclosing file.
+        let mut offset_with_indent = TextSize::new(0);
+        // This is used to resolve the location relative to the virtual file into a location
+        // relative to the indentation-trimmed file which will then (by the `Injector`) used
+        // to resolve to a location in the actual file.
+        // Besides indentation, we also skip `$0` cursors for this, since they are not included
+        // in the virtual files.
+        let mut offset_without_indent = TextSize::new(0);
+
+        let mut text = &*value;
+        if let Some(t) = text.strip_prefix('\n') {
+            offset_with_indent += TextSize::of("\n");
+            text = t;
+        }
+        // This stores the offsets of each line, **after we remove indentation**.
+        let mut line_offsets = Vec::new();
+        for mut line in text.split_inclusive('\n') {
+            line_offsets.push(offset_without_indent);
+
+            if line.starts_with("@@") {
+                // Introducing `//` into a fixture inside fixture causes all sorts of problems,
+                // so for testing purposes we escape it as `@@` and replace it here.
+                mapper.add("//", TextRange::at(offset_with_indent, TextSize::of("@@")));
+                line = &line["@@".len()..];
+                offset_with_indent += TextSize::of("@@");
+                offset_without_indent += TextSize::of("@@");
+            }
+
+            // Remove indentation to simplify the mapping with fixture (which de-indents).
+            // Removing indentation shouldn't affect highlighting.
+            let mut unindented_line = line.trim_start();
+            if unindented_line.is_empty() {
+                // The whole line was whitespaces, but we need the newline.
+                unindented_line = "\n";
+            }
+            offset_with_indent += TextSize::of(line) - TextSize::of(unindented_line);
+
+            let marker = "$0";
+            match unindented_line.find(marker) {
+                Some(marker_pos) => {
+                    let (before_marker, after_marker) = unindented_line.split_at(marker_pos);
+                    let after_marker = &after_marker[marker.len()..];
+
+                    mapper.add(
+                        before_marker,
+                        TextRange::at(offset_with_indent, TextSize::of(before_marker)),
+                    );
+                    offset_with_indent += TextSize::of(before_marker);
+                    offset_without_indent += TextSize::of(before_marker);
+
+                    if let Some(marker_range) = literal
+                        .map_range_up(TextRange::at(offset_with_indent, TextSize::of(marker)))
+                    {
+                        on_cursor(marker_range);
+                    }
+                    offset_with_indent += TextSize::of(marker);
+
+                    mapper.add(
+                        after_marker,
+                        TextRange::at(offset_with_indent, TextSize::of(after_marker)),
+                    );
+                    offset_with_indent += TextSize::of(after_marker);
+                    offset_without_indent += TextSize::of(after_marker);
+                }
+                None => {
+                    mapper.add(
+                        unindented_line,
+                        TextRange::at(offset_with_indent, TextSize::of(unindented_line)),
+                    );
+                    offset_with_indent += TextSize::of(unindented_line);
+                    offset_without_indent += TextSize::of(unindented_line);
+                }
+            }
+        }
+
+        let combined = mapper.take_text();
+        let combined_len = TextSize::of(&combined);
+        let (analysis, tmp_file_ids, sysroot_files) =
+            RootDatabase::from_ra_fixture(&combined, minicore).ok()?;
+
+        // We use a `Vec` because we know the `FileId`s will always be close.
+        let mut virtual_file_id_to_line = Vec::new();
+        for &(file_id, line) in &tmp_file_ids {
+            virtual_file_id_to_line.resize(file_id.index() as usize + 1, usize::MAX);
+            virtual_file_id_to_line[file_id.index() as usize] = line;
+        }
+
+        Some(RaFixtureAnalysis {
+            db: analysis,
+            tmp_file_ids,
+            line_offsets,
+            virtual_file_id_to_line,
+            mapper,
+            literal,
+            sysroot_files,
+            combined_len,
+        })
+    }
+
+    pub fn files(&self) -> impl Iterator<Item = FileId> {
+        self.tmp_file_ids.iter().map(|(file, _)| *file)
+    }
+
+    /// This returns `None` for minicore or other sysroot files.
+    fn virtual_file_id_to_line(&self, file_id: FileId) -> Option<usize> {
+        if self.is_sysroot_file(file_id) {
+            None
+        } else {
+            Some(self.virtual_file_id_to_line[file_id.index() as usize])
+        }
+    }
+
+    pub fn map_offset_down(&self, offset: TextSize) -> Option<(FileId, TextSize)> {
+        let inside_literal_range = self.literal.map_offset_down(offset)?;
+        let combined_offset = self.mapper.map_offset_down(inside_literal_range)?;
+        // There is usually a small number of files, so a linear search is smaller and faster.
+        let (_, &(file_id, file_line)) =
+            self.tmp_file_ids.iter().enumerate().find(|&(idx, &(_, file_line))| {
+                let file_start = self.line_offsets[file_line];
+                let file_end = self
+                    .tmp_file_ids
+                    .get(idx + 1)
+                    .map(|&(_, next_file_line)| self.line_offsets[next_file_line])
+                    .unwrap_or_else(|| self.combined_len);
+                TextRange::new(file_start, file_end).contains(combined_offset)
+            })?;
+        let file_line_offset = self.line_offsets[file_line];
+        let file_offset = combined_offset - file_line_offset;
+        Some((file_id, file_offset))
+    }
+
+    pub fn map_range_down(&self, range: TextRange) -> Option<(FileId, TextRange)> {
+        let (start_file_id, start_offset) = self.map_offset_down(range.start())?;
+        let (end_file_id, end_offset) = self.map_offset_down(range.end())?;
+        if start_file_id != end_file_id {
+            None
+        } else {
+            Some((start_file_id, TextRange::new(start_offset, end_offset)))
+        }
+    }
+
+    pub fn map_range_up(
+        &self,
+        virtual_file: FileId,
+        range: TextRange,
+    ) -> impl Iterator<Item = TextRange> {
+        // This could be `None` if the file is empty.
+        self.virtual_file_id_to_line(virtual_file)
+            .and_then(|line| self.line_offsets.get(line))
+            .into_iter()
+            .flat_map(move |&tmp_file_offset| {
+                // Resolve the offset relative to the virtual file to an offset relative to the combined indentation-trimmed file
+                let range = range + tmp_file_offset;
+                // Then resolve that to an offset relative to the real file.
+                self.mapper.map_range_up(range)
+            })
+            // And finally resolve the offset relative to the literal to relative to the file.
+            .filter_map(|range| self.literal.map_range_up(range))
+    }
+
+    pub fn map_offset_up(&self, virtual_file: FileId, offset: TextSize) -> Option<TextSize> {
+        self.map_range_up(virtual_file, TextRange::empty(offset)).next().map(|range| range.start())
+    }
+
+    pub fn is_sysroot_file(&self, file_id: FileId) -> bool {
+        self.sysroot_files.contains(&file_id)
+    }
+}
+
+pub trait UpmapFromRaFixture: Sized {
+    fn upmap_from_ra_fixture(
+        self,
+        analysis: &RaFixtureAnalysis,
+        virtual_file_id: FileId,
+        real_file_id: FileId,
+    ) -> Result<Self, ()>;
+}
+
+trait IsEmpty {
+    fn is_empty(&self) -> bool;
+}
+
+impl<T> IsEmpty for Vec<T> {
+    fn is_empty(&self) -> bool {
+        self.is_empty()
+    }
+}
+
+impl<T, const N: usize> IsEmpty for SmallVec<[T; N]> {
+    fn is_empty(&self) -> bool {
+        self.is_empty()
+    }
+}
+
+#[allow(clippy::disallowed_types)]
+impl<K, V, S> IsEmpty for std::collections::HashMap<K, V, S> {
+    fn is_empty(&self) -> bool {
+        self.is_empty()
+    }
+}
+
+fn upmap_collection<T, Collection>(
+    collection: Collection,
+    analysis: &RaFixtureAnalysis,
+    virtual_file_id: FileId,
+    real_file_id: FileId,
+) -> Result<Collection, ()>
+where
+    T: UpmapFromRaFixture,
+    Collection: IntoIterator<Item = T> + FromIterator<T> + IsEmpty,
+{
+    if collection.is_empty() {
+        // The collection was already empty, don't mark it as failing just because of that.
+        return Ok(collection);
+    }
+    let result = collection
+        .into_iter()
+        .filter_map(|item| item.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id).ok())
+        .collect::<Collection>();
+    if result.is_empty() {
+        // The collection was emptied by the upmapping - all items errored, therefore mark it as erroring as well.
+        Err(())
+    } else {
+        Ok(result)
+    }
+}
+
+impl<T: UpmapFromRaFixture> UpmapFromRaFixture for Option<T> {
+    fn upmap_from_ra_fixture(
+        self,
+        analysis: &RaFixtureAnalysis,
+        virtual_file_id: FileId,
+        real_file_id: FileId,
+    ) -> Result<Self, ()> {
+        Ok(match self {
+            Some(it) => Some(it.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?),
+            None => None,
+        })
+    }
+}
+
+impl<T: UpmapFromRaFixture> UpmapFromRaFixture for Vec<T> {
+    fn upmap_from_ra_fixture(
+        self,
+        analysis: &RaFixtureAnalysis,
+        virtual_file_id: FileId,
+        real_file_id: FileId,
+    ) -> Result<Self, ()> {
+        upmap_collection(self, analysis, virtual_file_id, real_file_id)
+    }
+}
+
+impl<T: UpmapFromRaFixture, const N: usize> UpmapFromRaFixture for SmallVec<[T; N]> {
+    fn upmap_from_ra_fixture(
+        self,
+        analysis: &RaFixtureAnalysis,
+        virtual_file_id: FileId,
+        real_file_id: FileId,
+    ) -> Result<Self, ()> {
+        upmap_collection(self, analysis, virtual_file_id, real_file_id)
+    }
+}
+
+#[allow(clippy::disallowed_types)]
+impl<K: UpmapFromRaFixture + Hash + Eq, V: UpmapFromRaFixture, S: BuildHasher + Default>
+    UpmapFromRaFixture for std::collections::HashMap<K, V, S>
+{
+    fn upmap_from_ra_fixture(
+        self,
+        analysis: &RaFixtureAnalysis,
+        virtual_file_id: FileId,
+        real_file_id: FileId,
+    ) -> Result<Self, ()> {
+        upmap_collection(self, analysis, virtual_file_id, real_file_id)
+    }
+}
+
+// A map of `FileId`s is treated as associating the ranges in the values with the keys.
+#[allow(clippy::disallowed_types)]
+impl<V: UpmapFromRaFixture, S: BuildHasher + Default> UpmapFromRaFixture
+    for std::collections::HashMap<FileId, V, S>
+{
+    fn upmap_from_ra_fixture(
+        self,
+        analysis: &RaFixtureAnalysis,
+        _virtual_file_id: FileId,
+        real_file_id: FileId,
+    ) -> Result<Self, ()> {
+        if self.is_empty() {
+            return Ok(self);
+        }
+        let result = self
+            .into_iter()
+            .filter_map(|(virtual_file_id, value)| {
+                Some((
+                    real_file_id,
+                    value.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id).ok()?,
+                ))
+            })
+            .collect::<std::collections::HashMap<_, _, _>>();
+        if result.is_empty() { Err(()) } else { Ok(result) }
+    }
+}
+
+macro_rules! impl_tuple {
+    () => {}; // Base case.
+    ( $first:ident, $( $rest:ident, )* ) => {
+        impl<
+            $first: UpmapFromRaFixture,
+            $( $rest: UpmapFromRaFixture, )*
+        > UpmapFromRaFixture for ( $first, $( $rest, )* ) {
+            fn upmap_from_ra_fixture(
+                self,
+                analysis: &RaFixtureAnalysis,
+                virtual_file_id: FileId,
+                real_file_id: FileId,
+            ) -> Result<Self, ()> {
+                #[allow(non_snake_case)]
+                let ( $first, $($rest,)* ) = self;
+                Ok((
+                    $first.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?,
+                    $( $rest.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?, )*
+                ))
+            }
+        }
+
+        impl_tuple!( $($rest,)* );
+    };
+}
+impl_tuple!(A, B, C, D, E,);
+
+impl UpmapFromRaFixture for TextSize {
+    fn upmap_from_ra_fixture(
+        self,
+        analysis: &RaFixtureAnalysis,
+        virtual_file_id: FileId,
+        _real_file_id: FileId,
+    ) -> Result<Self, ()> {
+        analysis.map_offset_up(virtual_file_id, self).ok_or(())
+    }
+}
+
+impl UpmapFromRaFixture for TextRange {
+    fn upmap_from_ra_fixture(
+        self,
+        analysis: &RaFixtureAnalysis,
+        virtual_file_id: FileId,
+        _real_file_id: FileId,
+    ) -> Result<Self, ()> {
+        analysis.map_range_up(virtual_file_id, self).next().ok_or(())
+    }
+}
+
+// Deliberately do not implement that, as it's easy to get things misbehave and be treated with the wrong FileId:
+//
+// impl UpmapFromRaFixture for FileId {
+//     fn upmap_from_ra_fixture(
+//         self,
+//         _analysis: &RaFixtureAnalysis,
+//         _virtual_file_id: FileId,
+//         real_file_id: FileId,
+//     ) -> Result<Self, ()> {
+//         Ok(real_file_id)
+//     }
+// }
+
+impl UpmapFromRaFixture for FilePositionWrapper<FileId> {
+    fn upmap_from_ra_fixture(
+        self,
+        analysis: &RaFixtureAnalysis,
+        _virtual_file_id: FileId,
+        real_file_id: FileId,
+    ) -> Result<Self, ()> {
+        Ok(FilePositionWrapper {
+            file_id: real_file_id,
+            offset: self.offset.upmap_from_ra_fixture(analysis, self.file_id, real_file_id)?,
+        })
+    }
+}
+
+impl UpmapFromRaFixture for FileRangeWrapper<FileId> {
+    fn upmap_from_ra_fixture(
+        self,
+        analysis: &RaFixtureAnalysis,
+        _virtual_file_id: FileId,
+        real_file_id: FileId,
+    ) -> Result<Self, ()> {
+        Ok(FileRangeWrapper {
+            file_id: real_file_id,
+            range: self.range.upmap_from_ra_fixture(analysis, self.file_id, real_file_id)?,
+        })
+    }
+}
+
+#[macro_export]
+macro_rules! impl_empty_upmap_from_ra_fixture {
+    ( $( $ty:ty ),* $(,)? ) => {
+        $(
+            impl $crate::ra_fixture::UpmapFromRaFixture for $ty {
+                fn upmap_from_ra_fixture(
+                    self,
+                    _analysis: &$crate::ra_fixture::RaFixtureAnalysis,
+                    _virtual_file_id: $crate::ra_fixture::FileId,
+                    _real_file_id: $crate::ra_fixture::FileId,
+                ) -> Result<Self, ()> {
+                    Ok(self)
+                }
+            }
+        )*
+    };
+}
+
+impl_empty_upmap_from_ra_fixture!(
+    bool,
+    i8,
+    i16,
+    i32,
+    i64,
+    i128,
+    u8,
+    u16,
+    u32,
+    u64,
+    u128,
+    f32,
+    f64,
+    &str,
+    String,
+    SmolStr,
+    Documentation,
+    SymbolKind,
+    CfgExpr,
+    ReferenceCategory,
+);
diff --git a/crates/ide-db/src/range_mapper.rs b/crates/ide-db/src/range_mapper.rs
new file mode 100644
index 0000000..ef84888
--- /dev/null
+++ b/crates/ide-db/src/range_mapper.rs
@@ -0,0 +1,65 @@
+//! Maps between ranges in documents.
+
+use std::cmp::Ordering;
+
+use stdx::equal_range_by;
+use syntax::{TextRange, TextSize};
+
+#[derive(Default)]
+pub struct RangeMapper {
+    buf: String,
+    ranges: Vec<(TextRange, Option<TextRange>)>,
+}
+
+impl RangeMapper {
+    pub fn add(&mut self, text: &str, source_range: TextRange) {
+        let len = TextSize::of(text);
+        assert_eq!(len, source_range.len());
+        self.add_impl(text, Some(source_range.start()));
+    }
+
+    pub fn add_unmapped(&mut self, text: &str) {
+        self.add_impl(text, None);
+    }
+
+    fn add_impl(&mut self, text: &str, source: Option<TextSize>) {
+        let len = TextSize::of(text);
+        let target_range = TextRange::at(TextSize::of(&self.buf), len);
+        self.ranges.push((target_range, source.map(|it| TextRange::at(it, len))));
+        self.buf.push_str(text);
+    }
+
+    pub fn take_text(&mut self) -> String {
+        std::mem::take(&mut self.buf)
+    }
+
+    pub fn map_range_up(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ {
+        equal_range_by(&self.ranges, |&(r, _)| {
+            if range.is_empty() && r.contains(range.start()) {
+                Ordering::Equal
+            } else {
+                TextRange::ordering(r, range)
+            }
+        })
+        .filter_map(move |i| {
+            let (target_range, source_range) = self.ranges[i];
+            let intersection = target_range.intersect(range).unwrap();
+            let source_range = source_range?;
+            Some(intersection - target_range.start() + source_range.start())
+        })
+    }
+
+    pub fn map_offset_down(&self, offset: TextSize) -> Option<TextSize> {
+        // Using a binary search here is a bit complicated because of the `None` entries.
+        // But the number of lines in fixtures is usually low.
+        let (target_range, source_range) =
+            self.ranges.iter().find_map(|&(target_range, source_range)| {
+                let source_range = source_range?;
+                if !source_range.contains(offset) {
+                    return None;
+                }
+                Some((target_range, source_range))
+            })?;
+        Some(offset - source_range.start() + target_range.start())
+    }
+}
diff --git a/crates/ide-db/src/source_change.rs b/crates/ide-db/src/source_change.rs
index 16c0d8d..57072bb 100644
--- a/crates/ide-db/src/source_change.rs
+++ b/crates/ide-db/src/source_change.rs
@@ -10,6 +10,7 @@
 use crate::{SnippetCap, assists::Command, syntax_helpers::tree_diff::diff};
 use base_db::AnchoredPathBuf;
 use itertools::Itertools;
+use macros::UpmapFromRaFixture;
 use nohash_hasher::IntMap;
 use rustc_hash::FxHashMap;
 use span::FileId;
@@ -20,7 +21,7 @@
 };
 
 /// An annotation ID associated with an indel, to describe changes.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, UpmapFromRaFixture)]
 pub struct ChangeAnnotationId(u32);
 
 impl fmt::Display for ChangeAnnotationId {
diff --git a/crates/ide-db/src/text_edit.rs b/crates/ide-db/src/text_edit.rs
index 6e9bd7b..d2a7371 100644
--- a/crates/ide-db/src/text_edit.rs
+++ b/crates/ide-db/src/text_edit.rs
@@ -5,6 +5,7 @@
 //! rust-analyzer.
 
 use itertools::Itertools;
+use macros::UpmapFromRaFixture;
 pub use span::{TextRange, TextSize};
 use std::cmp::max;
 
@@ -13,14 +14,14 @@
 /// `InsertDelete` -- a single "atomic" change to text
 ///
 /// Must not overlap with other `InDel`s
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash, UpmapFromRaFixture)]
 pub struct Indel {
     pub insert: String,
     /// Refers to offsets in the original text
     pub delete: TextRange,
 }
 
-#[derive(Default, Debug, Clone)]
+#[derive(Default, Debug, Clone, UpmapFromRaFixture)]
 pub struct TextEdit {
     /// Invariant: disjoint and sorted by `delete`.
     indels: Vec<Indel>,
diff --git a/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs b/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
index 25c1e63..4ed71f0 100644
--- a/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
+++ b/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
@@ -488,4 +488,27 @@
 "#,
         );
     }
+
+    #[test]
+    fn regression_17233() {
+        check_diagnostics(
+            r#"
+pub trait A {
+    type X: B;
+}
+pub trait B: A {
+    fn confused_name(self, _: i32);
+}
+
+pub struct Foo;
+impl Foo {
+    pub fn confused_name(&self) {}
+}
+
+pub fn repro<T: A>() {
+    Foo.confused_name();
+}
+"#,
+        );
+    }
 }
diff --git a/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs b/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs
index e31367f..c86ecd2 100644
--- a/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs
+++ b/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs
@@ -155,4 +155,56 @@
 "#,
         );
     }
+
+    #[test]
+    fn uninhabited_variants() {
+        check_diagnostics(
+            r#"
+//- minicore: result
+enum Infallible {}
+
+trait Foo {
+    type Bar;
+}
+
+struct Wrapper<T> {
+    error: T,
+}
+
+struct FooWrapper<T: Foo> {
+    error: T::Bar,
+}
+
+fn foo<T: Foo<Bar = Infallible>>(result: Result<T, T::Bar>) -> T {
+    let Ok(ok) = result;
+    ok
+}
+
+fn bar<T: Foo<Bar = Infallible>>(result: Result<T, (T::Bar,)>) -> T {
+    let Ok(ok) = result;
+    ok
+}
+
+fn baz<T: Foo<Bar = Infallible>>(result: Result<T, Wrapper<T::Bar>>) -> T {
+    let Ok(ok) = result;
+    ok
+}
+
+fn qux<T: Foo<Bar = Infallible>>(result: Result<T, FooWrapper<T>>) -> T {
+    let Ok(ok) = result;
+    ok
+}
+
+fn quux<T: Foo<Bar = Infallible>>(result: Result<T, [T::Bar; 1]>) -> T {
+    let Ok(ok) = result;
+    ok
+}
+
+fn corge<T: Foo<Bar = Infallible>>(result: Result<T, (i32, T::Bar)>) -> T {
+    let Ok(ok) = result;
+    ok
+}
+"#,
+        );
+    }
 }
diff --git a/crates/ide-diagnostics/src/tests.rs b/crates/ide-diagnostics/src/tests.rs
index 37af05e..3dc155e 100644
--- a/crates/ide-diagnostics/src/tests.rs
+++ b/crates/ide-diagnostics/src/tests.rs
@@ -311,7 +311,7 @@
     }
 
     fn check(minicore: MiniCore) {
-        let source = minicore.source_code();
+        let source = minicore.source_code(MiniCore::RAW_SOURCE);
         let mut config = DiagnosticsConfig::test_sample();
         // This should be ignored since we conditionally remove code which creates single item use with braces
         config.disabled.insert("unused_braces".to_owned());
@@ -321,7 +321,7 @@
     }
 
     // Checks that there is no diagnostic in minicore for each flag.
-    for flag in MiniCore::available_flags() {
+    for flag in MiniCore::available_flags(MiniCore::RAW_SOURCE) {
         if flag == "clone" {
             // Clone without copy has `moved-out-of-ref`, so ignoring.
             // FIXME: Maybe we should merge copy and clone in a single flag?
@@ -332,5 +332,5 @@
     }
     // And one time for all flags, to check codes which are behind multiple flags + prevent name collisions
     eprintln!("Checking all minicore flags");
-    check(MiniCore::from_flags(MiniCore::available_flags()))
+    check(MiniCore::from_flags(MiniCore::available_flags(MiniCore::RAW_SOURCE)))
 }
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml
index 06d2776..08ffd39 100644
--- a/crates/ide/Cargo.toml
+++ b/crates/ide/Cargo.toml
@@ -42,6 +42,7 @@
 # ide should depend only on the top-level `hir` package. if you need
 # something from some `hir-xxx` subpackage, reexport the API via `hir`.
 hir.workspace = true
+macros.workspace = true
 
 [target.'cfg(not(any(target_arch = "wasm32", target_os = "emscripten")))'.dependencies]
 toolchain.workspace = true
diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs
index dec1889..36c4404 100644
--- a/crates/ide/src/annotations.rs
+++ b/crates/ide/src/annotations.rs
@@ -1,6 +1,6 @@
 use hir::{HasSource, InFile, InRealFile, Semantics};
 use ide_db::{
-    FileId, FilePosition, FileRange, FxIndexSet, RootDatabase, defs::Definition,
+    FileId, FilePosition, FileRange, FxIndexSet, MiniCore, RootDatabase, defs::Definition,
     helpers::visit_file_defs,
 };
 use itertools::Itertools;
@@ -11,7 +11,7 @@
     annotations::fn_references::find_all_methods,
     goto_implementation::goto_implementation,
     navigation_target,
-    references::find_all_refs,
+    references::{FindAllRefsConfig, find_all_refs},
     runnables::{Runnable, runnables},
 };
 
@@ -36,7 +36,7 @@
     HasReferences { pos: FilePosition, data: Option<Vec<FileRange>> },
 }
 
-pub struct AnnotationConfig {
+pub struct AnnotationConfig<'a> {
     pub binary_target: bool,
     pub annotate_runnables: bool,
     pub annotate_impls: bool,
@@ -44,6 +44,7 @@
     pub annotate_method_references: bool,
     pub annotate_enum_variant_references: bool,
     pub location: AnnotationLocation,
+    pub minicore: MiniCore<'a>,
 }
 
 pub enum AnnotationLocation {
@@ -53,7 +54,7 @@
 
 pub(crate) fn annotations(
     db: &RootDatabase,
-    config: &AnnotationConfig,
+    config: &AnnotationConfig<'_>,
     file_id: FileId,
 ) -> Vec<Annotation> {
     let mut annotations = FxIndexSet::default();
@@ -196,13 +197,22 @@
         .collect()
 }
 
-pub(crate) fn resolve_annotation(db: &RootDatabase, mut annotation: Annotation) -> Annotation {
+pub(crate) fn resolve_annotation(
+    db: &RootDatabase,
+    config: &AnnotationConfig<'_>,
+    mut annotation: Annotation,
+) -> Annotation {
     match annotation.kind {
         AnnotationKind::HasImpls { pos, ref mut data } => {
             *data = goto_implementation(db, pos).map(|range| range.info);
         }
         AnnotationKind::HasReferences { pos, ref mut data } => {
-            *data = find_all_refs(&Semantics::new(db), pos, None).map(|result| {
+            *data = find_all_refs(
+                &Semantics::new(db),
+                pos,
+                &FindAllRefsConfig { search_scope: None, minicore: config.minicore },
+            )
+            .map(|result| {
                 result
                     .into_iter()
                     .flat_map(|res| res.references)
@@ -228,12 +238,13 @@
 #[cfg(test)]
 mod tests {
     use expect_test::{Expect, expect};
+    use ide_db::MiniCore;
 
     use crate::{Annotation, AnnotationConfig, fixture};
 
     use super::AnnotationLocation;
 
-    const DEFAULT_CONFIG: AnnotationConfig = AnnotationConfig {
+    const DEFAULT_CONFIG: AnnotationConfig<'_> = AnnotationConfig {
         binary_target: true,
         annotate_runnables: true,
         annotate_impls: true,
@@ -241,12 +252,13 @@
         annotate_method_references: true,
         annotate_enum_variant_references: true,
         location: AnnotationLocation::AboveName,
+        minicore: MiniCore::default(),
     };
 
     fn check_with_config(
         #[rust_analyzer::rust_fixture] ra_fixture: &str,
         expect: Expect,
-        config: &AnnotationConfig,
+        config: &AnnotationConfig<'_>,
     ) {
         let (analysis, file_id) = fixture::file(ra_fixture);
 
@@ -254,7 +266,7 @@
             .annotations(config, file_id)
             .unwrap()
             .into_iter()
-            .map(|annotation| analysis.resolve_annotation(annotation).unwrap())
+            .map(|annotation| analysis.resolve_annotation(&DEFAULT_CONFIG, annotation).unwrap())
             .collect();
 
         expect.assert_debug_eq(&annotations);
diff --git a/crates/ide/src/call_hierarchy.rs b/crates/ide/src/call_hierarchy.rs
index f42cead..aded911 100644
--- a/crates/ide/src/call_hierarchy.rs
+++ b/crates/ide/src/call_hierarchy.rs
@@ -4,14 +4,16 @@
 
 use hir::Semantics;
 use ide_db::{
-    FileRange, FxIndexMap, RootDatabase,
+    FileRange, FxIndexMap, MiniCore, RootDatabase,
     defs::{Definition, NameClass, NameRefClass},
     helpers::pick_best_token,
     search::FileReference,
 };
 use syntax::{AstNode, SyntaxKind::IDENT, ast};
 
-use crate::{FilePosition, NavigationTarget, RangeInfo, TryToNav, goto_definition};
+use crate::{
+    FilePosition, GotoDefinitionConfig, NavigationTarget, RangeInfo, TryToNav, goto_definition,
+};
 
 #[derive(Debug, Clone)]
 pub struct CallItem {
@@ -19,22 +21,28 @@
     pub ranges: Vec<FileRange>,
 }
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub struct CallHierarchyConfig {
+#[derive(Debug, Clone, Copy)]
+pub struct CallHierarchyConfig<'a> {
     /// Whether to exclude tests from the call hierarchy
     pub exclude_tests: bool,
+    pub minicore: MiniCore<'a>,
 }
 
 pub(crate) fn call_hierarchy(
     db: &RootDatabase,
     position: FilePosition,
+    config: &CallHierarchyConfig<'_>,
 ) -> Option<RangeInfo<Vec<NavigationTarget>>> {
-    goto_definition::goto_definition(db, position)
+    goto_definition::goto_definition(
+        db,
+        position,
+        &GotoDefinitionConfig { minicore: config.minicore },
+    )
 }
 
 pub(crate) fn incoming_calls(
     db: &RootDatabase,
-    CallHierarchyConfig { exclude_tests }: CallHierarchyConfig,
+    config: &CallHierarchyConfig<'_>,
     FilePosition { file_id, offset }: FilePosition,
 ) -> Option<Vec<CallItem>> {
     let sema = &Semantics::new(db);
@@ -71,7 +79,7 @@
             });
 
             if let Some((def, nav)) = def_nav {
-                if exclude_tests && def.is_test(db) {
+                if config.exclude_tests && def.is_test(db) {
                     continue;
                 }
 
@@ -89,7 +97,7 @@
 
 pub(crate) fn outgoing_calls(
     db: &RootDatabase,
-    CallHierarchyConfig { exclude_tests }: CallHierarchyConfig,
+    config: &CallHierarchyConfig<'_>,
     FilePosition { file_id, offset }: FilePosition,
 ) -> Option<Vec<CallItem>> {
     let sema = Semantics::new(db);
@@ -119,7 +127,7 @@
                     let callable = sema.type_of_expr(&expr)?.original.as_callable(db)?;
                     match callable.kind() {
                         hir::CallableKind::Function(it) => {
-                            if exclude_tests && it.is_test(db) {
+                            if config.exclude_tests && it.is_test(db) {
                                 return None;
                             }
                             it.try_to_nav(&sema)
@@ -132,7 +140,7 @@
                 }
                 ast::CallableExpr::MethodCall(expr) => {
                     let function = sema.resolve_method_call(&expr)?;
-                    if exclude_tests && function.is_test(db) {
+                    if config.exclude_tests && function.is_test(db) {
                         return None;
                     }
                     function
@@ -166,7 +174,7 @@
 #[cfg(test)]
 mod tests {
     use expect_test::{Expect, expect};
-    use ide_db::FilePosition;
+    use ide_db::{FilePosition, MiniCore};
     use itertools::Itertools;
 
     use crate::fixture;
@@ -189,21 +197,20 @@
             )
         }
 
+        let config = crate::CallHierarchyConfig { exclude_tests, minicore: MiniCore::default() };
         let (analysis, pos) = fixture::position(ra_fixture);
 
-        let mut navs = analysis.call_hierarchy(pos).unwrap().unwrap().info;
+        let mut navs = analysis.call_hierarchy(pos, &config).unwrap().unwrap().info;
         assert_eq!(navs.len(), 1);
         let nav = navs.pop().unwrap();
         expected_nav.assert_eq(&nav.debug_render());
 
-        let config = crate::CallHierarchyConfig { exclude_tests };
-
         let item_pos =
             FilePosition { file_id: nav.file_id, offset: nav.focus_or_full_range().start() };
-        let incoming_calls = analysis.incoming_calls(config, item_pos).unwrap().unwrap();
+        let incoming_calls = analysis.incoming_calls(&config, item_pos).unwrap().unwrap();
         expected_incoming.assert_eq(&incoming_calls.into_iter().map(debug_render).join("\n"));
 
-        let outgoing_calls = analysis.outgoing_calls(config, item_pos).unwrap().unwrap();
+        let outgoing_calls = analysis.outgoing_calls(&config, item_pos).unwrap().unwrap();
         expected_outgoing.assert_eq(&outgoing_calls.into_iter().map(debug_render).join("\n"));
     }
 
diff --git a/crates/ide/src/goto_declaration.rs b/crates/ide/src/goto_declaration.rs
index 686dbe2..375ce94 100644
--- a/crates/ide/src/goto_declaration.rs
+++ b/crates/ide/src/goto_declaration.rs
@@ -6,8 +6,8 @@
 use syntax::{AstNode, SyntaxKind::*, T, ast, match_ast};
 
 use crate::{
-    FilePosition, NavigationTarget, RangeInfo, goto_definition::goto_definition,
-    navigation_target::TryToNav,
+    FilePosition, GotoDefinitionConfig, NavigationTarget, RangeInfo,
+    goto_definition::goto_definition, navigation_target::TryToNav,
 };
 
 // Feature: Go to Declaration
@@ -21,6 +21,7 @@
 pub(crate) fn goto_declaration(
     db: &RootDatabase,
     position @ FilePosition { file_id, offset }: FilePosition,
+    config: &GotoDefinitionConfig<'_>,
 ) -> Option<RangeInfo<Vec<NavigationTarget>>> {
     let sema = Semantics::new(db);
     let file = sema.parse_guess_edition(file_id).syntax().clone();
@@ -69,20 +70,27 @@
         .flatten()
         .collect();
 
-    if info.is_empty() { goto_definition(db, position) } else { Some(RangeInfo::new(range, info)) }
+    if info.is_empty() {
+        goto_definition(db, position, config)
+    } else {
+        Some(RangeInfo::new(range, info))
+    }
 }
 
 #[cfg(test)]
 mod tests {
-    use ide_db::FileRange;
+    use ide_db::{FileRange, MiniCore};
     use itertools::Itertools;
 
-    use crate::fixture;
+    use crate::{GotoDefinitionConfig, fixture};
+
+    const TEST_CONFIG: GotoDefinitionConfig<'_> =
+        GotoDefinitionConfig { minicore: MiniCore::default() };
 
     fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         let (analysis, position, expected) = fixture::annotations(ra_fixture);
         let navs = analysis
-            .goto_declaration(position)
+            .goto_declaration(position, &TEST_CONFIG)
             .unwrap()
             .expect("no declaration or definition found")
             .info;
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index 2dcb13d..0ee9795 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -1,5 +1,6 @@
 use std::{iter, mem::discriminant};
 
+use crate::Analysis;
 use crate::{
     FilePosition, NavigationTarget, RangeInfo, TryToNav, UpmappingResult,
     doc_links::token_as_doc_comment,
@@ -8,6 +9,7 @@
 use hir::{
     AsAssocItem, AssocItem, CallableKind, FileRange, HasCrate, InFile, ModuleDef, Semantics, sym,
 };
+use ide_db::{MiniCore, ra_fixture::UpmapFromRaFixture};
 use ide_db::{
     RootDatabase, SymbolKind,
     base_db::{AnchoredPath, SourceDatabase},
@@ -25,6 +27,11 @@
     match_ast,
 };
 
+#[derive(Debug)]
+pub struct GotoDefinitionConfig<'a> {
+    pub minicore: MiniCore<'a>,
+}
+
 // Feature: Go to Definition
 //
 // Navigates to the definition of an identifier.
@@ -39,6 +46,7 @@
 pub(crate) fn goto_definition(
     db: &RootDatabase,
     FilePosition { file_id, offset }: FilePosition,
+    config: &GotoDefinitionConfig<'_>,
 ) -> Option<RangeInfo<Vec<NavigationTarget>>> {
     let sema = &Semantics::new(db);
     let file = sema.parse_guess_edition(file_id).syntax().clone();
@@ -83,52 +91,64 @@
         return Some(RangeInfo::new(original_token.text_range(), navs));
     }
 
-    let navs = sema
-        .descend_into_macros_no_opaque(original_token.clone(), false)
-        .into_iter()
-        .filter_map(|token| {
-            if let Some(navs) = find_definition_for_known_blanket_dual_impls(sema, &token.value) {
-                return Some(navs);
-            }
+    let tokens = sema.descend_into_macros_no_opaque(original_token.clone(), false);
+    let mut navs = Vec::new();
+    for token in tokens {
+        if let Some(n) = find_definition_for_known_blanket_dual_impls(sema, &token.value) {
+            navs.extend(n);
+            continue;
+        }
 
-            let parent = token.value.parent()?;
+        if let Some(token) = ast::String::cast(token.value.clone())
+            && let Some(original_token) = ast::String::cast(original_token.clone())
+            && let Some((analysis, fixture_analysis)) =
+                Analysis::from_ra_fixture(sema, original_token, &token, config.minicore)
+            && let Some((virtual_file_id, file_offset)) = fixture_analysis.map_offset_down(offset)
+        {
+            return hir::attach_db_allow_change(&analysis.db, || {
+                goto_definition(
+                    &analysis.db,
+                    FilePosition { file_id: virtual_file_id, offset: file_offset },
+                    config,
+                )
+            })
+            .and_then(|navs| {
+                navs.upmap_from_ra_fixture(&fixture_analysis, virtual_file_id, file_id).ok()
+            });
+        }
 
-            let token_file_id = token.file_id;
-            if let Some(token) = ast::String::cast(token.value.clone())
-                && let Some(x) =
-                    try_lookup_include_path(sema, InFile::new(token_file_id, token), file_id)
-            {
-                return Some(vec![x]);
-            }
+        let parent = token.value.parent()?;
 
-            if ast::TokenTree::can_cast(parent.kind())
-                && let Some(x) = try_lookup_macro_def_in_macro_use(sema, token.value)
-            {
-                return Some(vec![x]);
-            }
+        let token_file_id = token.file_id;
+        if let Some(token) = ast::String::cast(token.value.clone())
+            && let Some(x) =
+                try_lookup_include_path(sema, InFile::new(token_file_id, token), file_id)
+        {
+            navs.push(x);
+            continue;
+        }
 
-            Some(
-                IdentClass::classify_node(sema, &parent)?
-                    .definitions()
+        if ast::TokenTree::can_cast(parent.kind())
+            && let Some(x) = try_lookup_macro_def_in_macro_use(sema, token.value)
+        {
+            navs.push(x);
+            continue;
+        }
+
+        let Some(ident_class) = IdentClass::classify_node(sema, &parent) else { continue };
+        navs.extend(ident_class.definitions().into_iter().flat_map(|(def, _)| {
+            if let Definition::ExternCrateDecl(crate_def) = def {
+                return crate_def
+                    .resolved_crate(db)
+                    .map(|it| it.root_module().to_nav(sema.db))
                     .into_iter()
-                    .flat_map(|(def, _)| {
-                        if let Definition::ExternCrateDecl(crate_def) = def {
-                            return crate_def
-                                .resolved_crate(db)
-                                .map(|it| it.root_module().to_nav(sema.db))
-                                .into_iter()
-                                .flatten()
-                                .collect();
-                        }
-                        try_filter_trait_item_definition(sema, &def)
-                            .unwrap_or_else(|| def_to_nav(sema, def))
-                    })
-                    .collect(),
-            )
-        })
-        .flatten()
-        .unique()
-        .collect::<Vec<NavigationTarget>>();
+                    .flatten()
+                    .collect();
+            }
+            try_filter_trait_item_definition(sema, &def).unwrap_or_else(|| def_to_nav(sema, def))
+        }));
+    }
+    let navs = navs.into_iter().unique().collect();
 
     Some(RangeInfo::new(original_token.text_range(), navs))
 }
@@ -584,15 +604,22 @@
 
 #[cfg(test)]
 mod tests {
-    use crate::fixture;
-    use ide_db::FileRange;
+    use crate::{GotoDefinitionConfig, fixture};
+    use ide_db::{FileRange, MiniCore};
     use itertools::Itertools;
     use syntax::SmolStr;
 
+    const TEST_CONFIG: GotoDefinitionConfig<'_> =
+        GotoDefinitionConfig { minicore: MiniCore::default() };
+
     #[track_caller]
     fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         let (analysis, position, expected) = fixture::annotations(ra_fixture);
-        let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
+        let navs = analysis
+            .goto_definition(position, &TEST_CONFIG)
+            .unwrap()
+            .expect("no definition found")
+            .info;
 
         let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start());
         let navs = navs
@@ -611,14 +638,22 @@
 
     fn check_unresolved(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         let (analysis, position) = fixture::position(ra_fixture);
-        let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
+        let navs = analysis
+            .goto_definition(position, &TEST_CONFIG)
+            .unwrap()
+            .expect("no definition found")
+            .info;
 
         assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {navs:?}")
     }
 
     fn check_name(expected_name: &str, #[rust_analyzer::rust_fixture] ra_fixture: &str) {
         let (analysis, position, _) = fixture::annotations(ra_fixture);
-        let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
+        let navs = analysis
+            .goto_definition(position, &TEST_CONFIG)
+            .unwrap()
+            .expect("no definition found")
+            .info;
         assert!(navs.len() < 2, "expected single navigation target but encountered {}", navs.len());
         let Some(target) = navs.into_iter().next() else {
             panic!("expected single navigation target but encountered none");
@@ -3961,4 +3996,87 @@
 "#,
         );
     }
+
+    #[test]
+    fn ra_fixture() {
+        check(
+            r##"
+fn fixture(#[rust_analyzer::rust_fixture] ra_fixture: &str) {}
+
+fn foo() {
+    fixture(r#"
+fn foo() {}
+// ^^^
+fn bar() {
+    f$0oo();
+}
+    "#)
+}
+        "##,
+        );
+    }
+
+    #[test]
+    fn regression_20038() {
+        check(
+            r#"
+//- minicore: clone, fn
+struct Map<Fut, F>(Fut, F);
+
+struct InspectFn<F>(F);
+
+trait FnOnce1<A> {
+    type Output;
+}
+
+trait Future1 {
+    type Output;
+}
+
+trait FusedFuture1: Future1 {
+    fn is_terminated(&self) -> bool;
+     //^^^^^^^^^^^^^
+}
+
+impl<T, A, R> FnOnce1<A> for T
+where
+    T: FnOnce(A) -> R,
+{
+    type Output = R;
+}
+
+impl<F, A> FnOnce1<A> for InspectFn<F>
+where
+    F: for<'a> FnOnce1<&'a A, Output = ()>,
+{
+    type Output = A;
+}
+
+impl<Fut, F, T> Future1 for Map<Fut, F>
+where
+    Fut: Future1,
+    F: FnOnce1<Fut::Output, Output = T>,
+{
+    type Output = T;
+}
+
+impl<Fut, F, T> FusedFuture1 for Map<Fut, F>
+where
+    Fut: Future1,
+    F: FnOnce1<Fut::Output, Output = T>,
+{
+    fn is_terminated(&self) -> bool {
+        false
+    }
+}
+
+fn overflows<Fut, F>(inner: &Map<Fut, InspectFn<F>>)
+where
+    Map<Fut, InspectFn<F>>: FusedFuture1
+{
+    let _x = inner.is_terminated$0();
+}
+"#,
+        )
+    }
 }
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index c4fb6d1..e1d18b0 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -11,29 +11,32 @@
     db::DefDatabase,
 };
 use ide_db::{
-    FileRange, FxIndexSet, Ranker, RootDatabase,
+    FileRange, FxIndexSet, MiniCore, Ranker, RootDatabase,
     defs::{Definition, IdentClass, NameRefClass, OperatorClass},
     famous_defs::FamousDefs,
     helpers::pick_best_token,
+    ra_fixture::UpmapFromRaFixture,
 };
 use itertools::{Itertools, multizip};
-use span::Edition;
+use macros::UpmapFromRaFixture;
+use span::{Edition, TextRange};
 use syntax::{
-    AstNode,
+    AstNode, AstToken,
     SyntaxKind::{self, *},
     SyntaxNode, T, ast,
 };
 
 use crate::{
-    FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, TryToNav,
+    Analysis, FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, TryToNav,
     doc_links::token_as_doc_comment,
     markdown_remove::remove_markdown,
     markup::Markup,
     navigation_target::UpmappingResult,
     runnables::{runnable_fn, runnable_mod},
 };
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct HoverConfig {
+
+#[derive(Clone, Debug)]
+pub struct HoverConfig<'a> {
     pub links_in_hover: bool,
     pub memory_layout: Option<MemoryLayoutHoverConfig>,
     pub documentation: bool,
@@ -44,6 +47,7 @@
     pub max_enum_variants_count: Option<usize>,
     pub max_subst_ty_len: SubstTyLen,
     pub show_drop_glue: bool,
+    pub minicore: MiniCore<'a>,
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]
@@ -75,7 +79,7 @@
     PlainText,
 }
 
-#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq, UpmapFromRaFixture)]
 pub enum HoverAction {
     Runnable(Runnable),
     Implementation(FilePosition),
@@ -108,14 +112,14 @@
     }
 }
 
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Clone, Eq, PartialEq, Hash, UpmapFromRaFixture)]
 pub struct HoverGotoTypeData {
     pub mod_path: String,
     pub nav: NavigationTarget,
 }
 
 /// Contains the results when hovering over an item
-#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
+#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, UpmapFromRaFixture)]
 pub struct HoverResult {
     pub markup: Markup,
     pub actions: Vec<HoverAction>,
@@ -130,7 +134,7 @@
 pub(crate) fn hover(
     db: &RootDatabase,
     frange @ FileRange { file_id, range }: FileRange,
-    config: &HoverConfig,
+    config: &HoverConfig<'_>,
 ) -> Option<RangeInfo<HoverResult>> {
     let sema = &hir::Semantics::new(db);
     let file = sema.parse_guess_edition(file_id).syntax().clone();
@@ -161,7 +165,7 @@
     sema: &Semantics<'_, RootDatabase>,
     FilePosition { file_id, offset }: FilePosition,
     file: SyntaxNode,
-    config: &HoverConfig,
+    config: &HoverConfig<'_>,
     edition: Edition,
     display_target: DisplayTarget,
 ) -> Option<RangeInfo<HoverResult>> {
@@ -219,6 +223,21 @@
         return Some(RangeInfo::new(range, res));
     }
 
+    if let Some(literal) = ast::String::cast(original_token.clone())
+        && let Some((analysis, fixture_analysis)) =
+            Analysis::from_ra_fixture(sema, literal.clone(), &literal, config.minicore)
+    {
+        let (virtual_file_id, virtual_offset) = fixture_analysis.map_offset_down(offset)?;
+        return analysis
+            .hover(
+                config,
+                FileRange { file_id: virtual_file_id, range: TextRange::empty(virtual_offset) },
+            )
+            .ok()??
+            .upmap_from_ra_fixture(&fixture_analysis, virtual_file_id, file_id)
+            .ok();
+    }
+
     // prefer descending the same token kind in attribute expansions, in normal macros text
     // equivalency is more important
     let mut descended = sema.descend_into_macros(original_token.clone());
@@ -383,9 +402,9 @@
 
 fn hover_ranged(
     sema: &Semantics<'_, RootDatabase>,
-    FileRange { range, .. }: FileRange,
+    FileRange { file_id, range }: FileRange,
     file: SyntaxNode,
-    config: &HoverConfig,
+    config: &HoverConfig<'_>,
     edition: Edition,
     display_target: DisplayTarget,
 ) -> Option<RangeInfo<HoverResult>> {
@@ -404,6 +423,20 @@
         {
             render::deref_expr(sema, config, prefix_expr, edition, display_target)
         }
+        Either::Left(ast::Expr::Literal(literal)) => {
+            if let Some(literal) = ast::String::cast(literal.token())
+                && let Some((analysis, fixture_analysis)) =
+                    Analysis::from_ra_fixture(sema, literal.clone(), &literal, config.minicore)
+            {
+                let (virtual_file_id, virtual_range) = fixture_analysis.map_range_down(range)?;
+                return analysis
+                    .hover(config, FileRange { file_id: virtual_file_id, range: virtual_range })
+                    .ok()??
+                    .upmap_from_ra_fixture(&fixture_analysis, virtual_file_id, file_id)
+                    .ok();
+            }
+            None
+        }
         _ => None,
     };
     let res =
@@ -426,7 +459,7 @@
     scope_node: &SyntaxNode,
     macro_arm: Option<u32>,
     render_extras: bool,
-    config: &HoverConfig,
+    config: &HoverConfig<'_>,
     edition: Edition,
     display_target: DisplayTarget,
 ) -> HoverResult {
diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs
index f29ccc9..a1eff3a 100644
--- a/crates/ide/src/hover/render.rs
+++ b/crates/ide/src/hover/render.rs
@@ -35,7 +35,7 @@
 
 pub(super) fn type_info_of(
     sema: &Semantics<'_, RootDatabase>,
-    _config: &HoverConfig,
+    _config: &HoverConfig<'_>,
     expr_or_pat: &Either<ast::Expr, ast::Pat>,
     edition: Edition,
     display_target: DisplayTarget,
@@ -49,7 +49,7 @@
 
 pub(super) fn closure_expr(
     sema: &Semantics<'_, RootDatabase>,
-    config: &HoverConfig,
+    config: &HoverConfig<'_>,
     c: ast::ClosureExpr,
     edition: Edition,
     display_target: DisplayTarget,
@@ -60,7 +60,7 @@
 
 pub(super) fn try_expr(
     sema: &Semantics<'_, RootDatabase>,
-    _config: &HoverConfig,
+    _config: &HoverConfig<'_>,
     try_expr: &ast::TryExpr,
     edition: Edition,
     display_target: DisplayTarget,
@@ -155,7 +155,7 @@
 
 pub(super) fn deref_expr(
     sema: &Semantics<'_, RootDatabase>,
-    _config: &HoverConfig,
+    _config: &HoverConfig<'_>,
     deref_expr: &ast::PrefixExpr,
     edition: Edition,
     display_target: DisplayTarget,
@@ -219,7 +219,7 @@
 
 pub(super) fn underscore(
     sema: &Semantics<'_, RootDatabase>,
-    config: &HoverConfig,
+    config: &HoverConfig<'_>,
     token: &SyntaxToken,
     edition: Edition,
     display_target: DisplayTarget,
@@ -263,7 +263,7 @@
 
 pub(super) fn keyword(
     sema: &Semantics<'_, RootDatabase>,
-    config: &HoverConfig,
+    config: &HoverConfig<'_>,
     token: &SyntaxToken,
     edition: Edition,
     display_target: DisplayTarget,
@@ -290,7 +290,7 @@
 /// i.e. `let S {a, ..} = S {a: 1, b: 2}`
 pub(super) fn struct_rest_pat(
     sema: &Semantics<'_, RootDatabase>,
-    _config: &HoverConfig,
+    _config: &HoverConfig<'_>,
     pattern: &ast::RecordPat,
     edition: Edition,
     display_target: DisplayTarget,
@@ -371,7 +371,7 @@
     def: Definition,
     markup: &Markup,
     markup_range_map: Option<DocsRangeMap>,
-    config: &HoverConfig,
+    config: &HoverConfig<'_>,
 ) -> Markup {
     let markup = markup.as_str();
     let markup = if config.links_in_hover {
@@ -481,7 +481,7 @@
     macro_arm: Option<u32>,
     render_extras: bool,
     subst_types: Option<&Vec<(Symbol, Type<'_>)>>,
-    config: &HoverConfig,
+    config: &HoverConfig<'_>,
     edition: Edition,
     display_target: DisplayTarget,
 ) -> (Markup, Option<DocsRangeMap>) {
@@ -979,7 +979,7 @@
 
 fn type_info(
     sema: &Semantics<'_, RootDatabase>,
-    config: &HoverConfig,
+    config: &HoverConfig<'_>,
     ty: TypeInfo<'_>,
     edition: Edition,
     display_target: DisplayTarget,
@@ -1038,7 +1038,7 @@
 
 fn closure_ty(
     sema: &Semantics<'_, RootDatabase>,
-    config: &HoverConfig,
+    config: &HoverConfig<'_>,
     TypeInfo { original, adjusted }: &TypeInfo<'_>,
     edition: Edition,
     display_target: DisplayTarget,
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index df18006..91fb4d0 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -1,5 +1,5 @@
 use expect_test::{Expect, expect};
-use ide_db::{FileRange, base_db::SourceDatabase};
+use ide_db::{FileRange, MiniCore, base_db::SourceDatabase};
 use syntax::TextRange;
 
 use crate::{
@@ -8,7 +8,7 @@
 
 use hir::setup_tracing;
 
-const HOVER_BASE_CONFIG: HoverConfig = HoverConfig {
+const HOVER_BASE_CONFIG: HoverConfig<'_> = HoverConfig {
     links_in_hover: false,
     memory_layout: Some(MemoryLayoutHoverConfig {
         size: Some(MemoryLayoutHoverRenderKind::Both),
@@ -25,6 +25,7 @@
     max_enum_variants_count: Some(5),
     max_subst_ty_len: super::SubstTyLen::Unlimited,
     show_drop_glue: true,
+    minicore: MiniCore::default(),
 };
 
 fn check_hover_no_result(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index f7b09b4..21550d5 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -8,9 +8,12 @@
     ClosureStyle, DisplayTarget, EditionedFileId, HasVisibility, HirDisplay, HirDisplayError,
     HirWrite, InRealFile, ModuleDef, ModuleDefId, Semantics, sym,
 };
-use ide_db::{FileRange, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder};
+use ide_db::{
+    FileRange, MiniCore, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder,
+};
 use ide_db::{FxHashSet, text_edit::TextEdit};
 use itertools::Itertools;
+use macros::UpmapFromRaFixture;
 use smallvec::{SmallVec, smallvec};
 use stdx::never;
 use syntax::{
@@ -37,6 +40,7 @@
 mod implied_dyn_trait;
 mod lifetime;
 mod param_name;
+mod ra_fixture;
 mod range_exclusive;
 
 // Feature: Inlay Hints
@@ -80,7 +84,7 @@
     db: &RootDatabase,
     file_id: FileId,
     range_limit: Option<TextRange>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
 ) -> Vec<InlayHint> {
     let _p = tracing::info_span!("inlay_hints").entered();
     let sema = Semantics::new(db);
@@ -132,7 +136,7 @@
     file_id: FileId,
     resolve_range: TextRange,
     hash: u64,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     hasher: impl Fn(&InlayHint) -> u64,
 ) -> Option<InlayHint> {
     let _p = tracing::info_span!("inlay_hints_resolve").entered();
@@ -208,7 +212,7 @@
     hints: &mut Vec<InlayHint>,
     ctx: &mut InlayHintCtx,
     famous_defs @ FamousDefs(sema, _krate): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     file_id: EditionedFileId,
     display_target: DisplayTarget,
     node: SyntaxNode,
@@ -239,6 +243,7 @@
                         closure_ret::hints(hints, famous_defs, config, display_target, it)
                     },
                     ast::Expr::RangeExpr(it) => range_exclusive::hints(hints, famous_defs, config, it),
+                    ast::Expr::Literal(it) => ra_fixture::hints(hints, famous_defs.0, file_id, config, it),
                     _ => Some(()),
                 }
             },
@@ -294,8 +299,8 @@
     };
 }
 
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct InlayHintsConfig {
+#[derive(Clone, Debug)]
+pub struct InlayHintsConfig<'a> {
     pub render_colons: bool,
     pub type_hints: bool,
     pub sized_bound: bool,
@@ -321,9 +326,10 @@
     pub max_length: Option<usize>,
     pub closing_brace_hints_min_lines: Option<usize>,
     pub fields_to_resolve: InlayFieldsToResolve,
+    pub minicore: MiniCore<'a>,
 }
 
-impl InlayHintsConfig {
+impl InlayHintsConfig<'_> {
     fn lazy_text_edit(&self, finish: impl FnOnce() -> TextEdit) -> LazyProperty<TextEdit> {
         if self.fields_to_resolve.resolve_text_edits {
             LazyProperty::Lazy
@@ -466,7 +472,7 @@
     After,
 }
 
-#[derive(Debug)]
+#[derive(Debug, UpmapFromRaFixture)]
 pub struct InlayHint {
     /// The text range this inlay hint applies to.
     pub range: TextRange,
@@ -485,9 +491,10 @@
 }
 
 /// A type signaling that a value is either computed, or is available for computation.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Default, UpmapFromRaFixture)]
 pub enum LazyProperty<T> {
     Computed(T),
+    #[default]
     Lazy,
 }
 
@@ -537,7 +544,7 @@
     Markdown(String),
 }
 
-#[derive(Default, Hash)]
+#[derive(Default, Hash, UpmapFromRaFixture)]
 pub struct InlayHintLabel {
     pub parts: SmallVec<[InlayHintLabelPart; 1]>,
 }
@@ -623,6 +630,7 @@
     }
 }
 
+#[derive(UpmapFromRaFixture)]
 pub struct InlayHintLabelPart {
     pub text: String,
     /// Source location represented by this label part. The client will use this to fetch the part's
@@ -724,7 +732,7 @@
 
 fn label_of_ty(
     famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     ty: &hir::Type<'_>,
     display_target: DisplayTarget,
 ) -> Option<InlayHintLabel> {
@@ -734,7 +742,7 @@
         mut max_length: Option<usize>,
         ty: &hir::Type<'_>,
         label_builder: &mut InlayHintLabelBuilder<'_>,
-        config: &InlayHintsConfig,
+        config: &InlayHintsConfig<'_>,
         display_target: DisplayTarget,
     ) -> Result<(), HirDisplayError> {
         hir::attach_db(sema.db, || {
@@ -829,7 +837,7 @@
 
 fn ty_to_text_edit(
     sema: &Semantics<'_, RootDatabase>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     node_for_hint: &SyntaxNode,
     ty: &hir::Type<'_>,
     offset_to_insert_ty: TextSize,
@@ -860,6 +868,7 @@
 
     use expect_test::Expect;
     use hir::ClosureStyle;
+    use ide_db::MiniCore;
     use itertools::Itertools;
     use test_utils::extract_annotations;
 
@@ -869,7 +878,7 @@
 
     use super::{ClosureReturnTypeHints, GenericParameterHints, InlayFieldsToResolve};
 
-    pub(super) const DISABLED_CONFIG: InlayHintsConfig = InlayHintsConfig {
+    pub(super) const DISABLED_CONFIG: InlayHintsConfig<'_> = InlayHintsConfig {
         discriminant_hints: DiscriminantHints::Never,
         render_colons: false,
         type_hints: false,
@@ -899,8 +908,9 @@
         fields_to_resolve: InlayFieldsToResolve::empty(),
         implicit_drop_hints: false,
         range_exclusive_hints: false,
+        minicore: MiniCore::default(),
     };
-    pub(super) const TEST_CONFIG: InlayHintsConfig = InlayHintsConfig {
+    pub(super) const TEST_CONFIG: InlayHintsConfig<'_> = InlayHintsConfig {
         type_hints: true,
         parameter_hints: true,
         chaining_hints: true,
@@ -917,7 +927,7 @@
 
     #[track_caller]
     pub(super) fn check_with_config(
-        config: InlayHintsConfig,
+        config: InlayHintsConfig<'_>,
         #[rust_analyzer::rust_fixture] ra_fixture: &str,
     ) {
         let (analysis, file_id) = fixture::file(ra_fixture);
@@ -936,7 +946,7 @@
 
     #[track_caller]
     pub(super) fn check_expect(
-        config: InlayHintsConfig,
+        config: InlayHintsConfig<'_>,
         #[rust_analyzer::rust_fixture] ra_fixture: &str,
         expect: Expect,
     ) {
@@ -951,7 +961,7 @@
     /// expect test.
     #[track_caller]
     pub(super) fn check_edit(
-        config: InlayHintsConfig,
+        config: InlayHintsConfig<'_>,
         #[rust_analyzer::rust_fixture] ra_fixture: &str,
         expect: Expect,
     ) {
@@ -974,7 +984,7 @@
 
     #[track_caller]
     pub(super) fn check_no_edit(
-        config: InlayHintsConfig,
+        config: InlayHintsConfig<'_>,
         #[rust_analyzer::rust_fixture] ra_fixture: &str,
     ) {
         let (analysis, file_id) = fixture::file(ra_fixture);
diff --git a/crates/ide/src/inlay_hints/adjustment.rs b/crates/ide/src/inlay_hints/adjustment.rs
index 7231a31..ebb0d57 100644
--- a/crates/ide/src/inlay_hints/adjustment.rs
+++ b/crates/ide/src/inlay_hints/adjustment.rs
@@ -23,7 +23,7 @@
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     display_target: DisplayTarget,
     expr: &ast::Expr,
 ) -> Option<()> {
diff --git a/crates/ide/src/inlay_hints/bind_pat.rs b/crates/ide/src/inlay_hints/bind_pat.rs
index 121b16b..de207c7 100644
--- a/crates/ide/src/inlay_hints/bind_pat.rs
+++ b/crates/ide/src/inlay_hints/bind_pat.rs
@@ -20,7 +20,7 @@
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     display_target: DisplayTarget,
     pat: &ast::IdentPat,
 ) -> Option<()> {
diff --git a/crates/ide/src/inlay_hints/binding_mode.rs b/crates/ide/src/inlay_hints/binding_mode.rs
index 169ab92..e8d305a 100644
--- a/crates/ide/src/inlay_hints/binding_mode.rs
+++ b/crates/ide/src/inlay_hints/binding_mode.rs
@@ -15,7 +15,7 @@
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     pat: &ast::Pat,
 ) -> Option<()> {
     if !config.binding_mode_hints {
diff --git a/crates/ide/src/inlay_hints/bounds.rs b/crates/ide/src/inlay_hints/bounds.rs
index 4abd67b..c9fbdf3 100644
--- a/crates/ide/src/inlay_hints/bounds.rs
+++ b/crates/ide/src/inlay_hints/bounds.rs
@@ -13,7 +13,7 @@
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     params: ast::GenericParamList,
 ) -> Option<()> {
     if !config.sized_bound {
diff --git a/crates/ide/src/inlay_hints/chaining.rs b/crates/ide/src/inlay_hints/chaining.rs
index a8bb652..cf3149c 100644
--- a/crates/ide/src/inlay_hints/chaining.rs
+++ b/crates/ide/src/inlay_hints/chaining.rs
@@ -13,7 +13,7 @@
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     display_target: DisplayTarget,
     expr: &ast::Expr,
 ) -> Option<()> {
@@ -93,7 +93,7 @@
 
     #[track_caller]
     pub(super) fn check_expect_clear_loc(
-        config: InlayHintsConfig,
+        config: InlayHintsConfig<'_>,
         #[rust_analyzer::rust_fixture] ra_fixture: &str,
         expect: Expect,
     ) {
diff --git a/crates/ide/src/inlay_hints/closing_brace.rs b/crates/ide/src/inlay_hints/closing_brace.rs
index 9d246ed..ab3ce5b 100644
--- a/crates/ide/src/inlay_hints/closing_brace.rs
+++ b/crates/ide/src/inlay_hints/closing_brace.rs
@@ -19,7 +19,7 @@
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     sema: &Semantics<'_, RootDatabase>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     display_target: DisplayTarget,
     InRealFile { file_id, value: node }: InRealFile<SyntaxNode>,
 ) -> Option<()> {
diff --git a/crates/ide/src/inlay_hints/closure_captures.rs b/crates/ide/src/inlay_hints/closure_captures.rs
index 3186a56..f8d4ddc 100644
--- a/crates/ide/src/inlay_hints/closure_captures.rs
+++ b/crates/ide/src/inlay_hints/closure_captures.rs
@@ -13,7 +13,7 @@
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     closure: ast::ClosureExpr,
 ) -> Option<()> {
     if !config.closure_capture_hints {
diff --git a/crates/ide/src/inlay_hints/closure_ret.rs b/crates/ide/src/inlay_hints/closure_ret.rs
index fef1cb8..7765dc4 100644
--- a/crates/ide/src/inlay_hints/closure_ret.rs
+++ b/crates/ide/src/inlay_hints/closure_ret.rs
@@ -13,7 +13,7 @@
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     display_target: DisplayTarget,
     closure: ast::ClosureExpr,
 ) -> Option<()> {
diff --git a/crates/ide/src/inlay_hints/discriminant.rs b/crates/ide/src/inlay_hints/discriminant.rs
index a2a7028..5b92671 100644
--- a/crates/ide/src/inlay_hints/discriminant.rs
+++ b/crates/ide/src/inlay_hints/discriminant.rs
@@ -17,7 +17,7 @@
 pub(super) fn enum_hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     enum_: ast::Enum,
 ) -> Option<()> {
     if let DiscriminantHints::Never = config.discriminant_hints {
@@ -41,7 +41,7 @@
 
 fn variant_hints(
     acc: &mut Vec<InlayHint>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     sema: &Semantics<'_, RootDatabase>,
     enum_: &ast::Enum,
     variant: &ast::Variant,
diff --git a/crates/ide/src/inlay_hints/extern_block.rs b/crates/ide/src/inlay_hints/extern_block.rs
index 491018a..8dd6c4d 100644
--- a/crates/ide/src/inlay_hints/extern_block.rs
+++ b/crates/ide/src/inlay_hints/extern_block.rs
@@ -7,7 +7,7 @@
 pub(super) fn extern_block_hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     extern_block: ast::ExternBlock,
 ) -> Option<()> {
     if extern_block.unsafe_token().is_some() {
@@ -33,7 +33,7 @@
 pub(super) fn fn_hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     fn_: &ast::Fn,
     extern_block: &ast::ExternBlock,
 ) -> Option<()> {
@@ -51,7 +51,7 @@
 pub(super) fn static_hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     static_: &ast::Static,
     extern_block: &ast::ExternBlock,
 ) -> Option<()> {
@@ -67,7 +67,7 @@
 }
 
 fn item_hint(
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     extern_block: &ast::ExternBlock,
     token: SyntaxToken,
 ) -> InlayHint {
diff --git a/crates/ide/src/inlay_hints/generic_param.rs b/crates/ide/src/inlay_hints/generic_param.rs
index 1fddb6f..27d14f7 100644
--- a/crates/ide/src/inlay_hints/generic_param.rs
+++ b/crates/ide/src/inlay_hints/generic_param.rs
@@ -16,7 +16,7 @@
 pub(crate) fn hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, krate): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     node: AnyHasGenericArgs,
 ) -> Option<()> {
     let GenericParameterHints { type_hints, lifetime_hints, const_hints } =
diff --git a/crates/ide/src/inlay_hints/implicit_drop.rs b/crates/ide/src/inlay_hints/implicit_drop.rs
index 1e272fe..951a672 100644
--- a/crates/ide/src/inlay_hints/implicit_drop.rs
+++ b/crates/ide/src/inlay_hints/implicit_drop.rs
@@ -23,7 +23,7 @@
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     display_target: hir::DisplayTarget,
     node: &ast::Fn,
 ) -> Option<()> {
@@ -147,7 +147,7 @@
         inlay_hints::tests::{DISABLED_CONFIG, check_with_config},
     };
 
-    const ONLY_DROP_CONFIG: InlayHintsConfig =
+    const ONLY_DROP_CONFIG: InlayHintsConfig<'_> =
         InlayHintsConfig { implicit_drop_hints: true, ..DISABLED_CONFIG };
 
     #[test]
diff --git a/crates/ide/src/inlay_hints/implicit_static.rs b/crates/ide/src/inlay_hints/implicit_static.rs
index bddce90..0492991 100644
--- a/crates/ide/src/inlay_hints/implicit_static.rs
+++ b/crates/ide/src/inlay_hints/implicit_static.rs
@@ -15,7 +15,7 @@
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(_sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     statik_or_const: Either<ast::Static, ast::Const>,
 ) -> Option<()> {
     if config.lifetime_elision_hints != LifetimeElisionHints::Always {
diff --git a/crates/ide/src/inlay_hints/implied_dyn_trait.rs b/crates/ide/src/inlay_hints/implied_dyn_trait.rs
index 0da1785..562eb1e 100644
--- a/crates/ide/src/inlay_hints/implied_dyn_trait.rs
+++ b/crates/ide/src/inlay_hints/implied_dyn_trait.rs
@@ -11,7 +11,7 @@
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     path: Either<ast::PathType, ast::DynTraitType>,
 ) -> Option<()> {
     let parent = path.syntax().parent()?;
diff --git a/crates/ide/src/inlay_hints/lifetime.rs b/crates/ide/src/inlay_hints/lifetime.rs
index a89c53e..4982b60 100644
--- a/crates/ide/src/inlay_hints/lifetime.rs
+++ b/crates/ide/src/inlay_hints/lifetime.rs
@@ -21,7 +21,7 @@
     acc: &mut Vec<InlayHint>,
     ctx: &mut InlayHintCtx,
     fd: &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     func: ast::Fn,
 ) -> Option<()> {
     if config.lifetime_elision_hints == LifetimeElisionHints::Never {
@@ -70,7 +70,7 @@
     acc: &mut Vec<InlayHint>,
     ctx: &mut InlayHintCtx,
     fd: &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     func: ast::FnPtrType,
 ) -> Option<()> {
     if config.lifetime_elision_hints == LifetimeElisionHints::Never {
@@ -135,7 +135,7 @@
     acc: &mut Vec<InlayHint>,
     ctx: &mut InlayHintCtx,
     fd: &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     func: &ast::PathType,
 ) -> Option<()> {
     if config.lifetime_elision_hints == LifetimeElisionHints::Never {
@@ -196,7 +196,7 @@
     acc: &mut Vec<InlayHint>,
     ctx: &mut InlayHintCtx,
     FamousDefs(_, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     params: impl Iterator<Item = (Option<ast::Name>, ast::Type)>,
     generic_param_list: Option<ast::GenericParamList>,
     ret_type: Option<ast::RetType>,
diff --git a/crates/ide/src/inlay_hints/param_name.rs b/crates/ide/src/inlay_hints/param_name.rs
index 7547077..4122c16 100644
--- a/crates/ide/src/inlay_hints/param_name.rs
+++ b/crates/ide/src/inlay_hints/param_name.rs
@@ -18,7 +18,7 @@
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, krate): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     file_id: EditionedFileId,
     expr: ast::Expr,
 ) -> Option<()> {
@@ -124,12 +124,12 @@
     // hide when:
     // - the parameter name is a suffix of the function's name
     // - the argument is a qualified constructing or call expression where the qualifier is an ADT
-    // - exact argument<->parameter match(ignoring leading underscore) or parameter is a prefix/suffix
-    //   of argument with _ splitting it off
+    // - exact argument<->parameter match(ignoring leading and trailing underscore) or
+    //   parameter is a prefix/suffix of argument with _ splitting it off
     // - param starts with `ra_fixture`
     // - param is a well known name in a unary function
 
-    let param_name = param_name.trim_start_matches('_');
+    let param_name = param_name.trim_matches('_');
     if param_name.is_empty() {
         return true;
     }
@@ -540,6 +540,8 @@
 fn foo(param: u32) {}
 fn bar(param_eter: u32) {}
 fn baz(a_d_e: u32) {}
+fn far(loop_: u32) {}
+fn faz(r#loop: u32) {}
 
 enum CompletionKind {
     Keyword,
@@ -590,6 +592,9 @@
     let param_eter2 = 0;
     bar(param_eter2);
       //^^^^^^^^^^^ param_eter
+    let loop_level = 0;
+    far(loop_level);
+    faz(loop_level);
 
     non_ident_pat((0, 0));
 
diff --git a/crates/ide/src/inlay_hints/ra_fixture.rs b/crates/ide/src/inlay_hints/ra_fixture.rs
new file mode 100644
index 0000000..bee1841
--- /dev/null
+++ b/crates/ide/src/inlay_hints/ra_fixture.rs
@@ -0,0 +1,32 @@
+//! Injected inlay hints for `#[rust_analyzer::rust_fixture]`.
+
+use hir::{EditionedFileId, Semantics};
+use ide_db::{RootDatabase, impl_empty_upmap_from_ra_fixture, ra_fixture::UpmapFromRaFixture};
+use syntax::{AstToken, ast};
+
+use crate::{Analysis, InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind, InlayTooltip};
+
+pub(super) fn hints(
+    acc: &mut Vec<InlayHint>,
+    sema: &Semantics<'_, RootDatabase>,
+    file_id: EditionedFileId,
+    config: &InlayHintsConfig<'_>,
+    literal: ast::Literal,
+) -> Option<()> {
+    let file_id = file_id.file_id(sema.db);
+    let literal = ast::String::cast(literal.token())?;
+    let (analysis, fixture_analysis) =
+        Analysis::from_ra_fixture(sema, literal.clone(), &literal, config.minicore)?;
+    for virtual_file_id in fixture_analysis.files() {
+        acc.extend(
+            analysis
+                .inlay_hints(config, virtual_file_id, None)
+                .ok()?
+                .upmap_from_ra_fixture(&fixture_analysis, virtual_file_id, file_id)
+                .ok()?,
+        );
+    }
+    Some(())
+}
+
+impl_empty_upmap_from_ra_fixture!(InlayHintPosition, InlayKind, InlayTooltip);
diff --git a/crates/ide/src/inlay_hints/range_exclusive.rs b/crates/ide/src/inlay_hints/range_exclusive.rs
index 47bd6d7..a446908 100644
--- a/crates/ide/src/inlay_hints/range_exclusive.rs
+++ b/crates/ide/src/inlay_hints/range_exclusive.rs
@@ -11,7 +11,7 @@
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(_sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     range: impl ast::RangeItem,
 ) -> Option<()> {
     (config.range_exclusive_hints && range.end().is_some())
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index f7d21c9..8572528 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -62,7 +62,7 @@
 
 use cfg::CfgOptions;
 use fetch_crates::CrateInfo;
-use hir::{ChangeWithProcMacros, EditionedFileId, crate_def_map, db::HirDatabase, sym};
+use hir::{ChangeWithProcMacros, EditionedFileId, crate_def_map, sym};
 use ide_db::{
     FxHashMap, FxIndexSet, LineIndexDatabase,
     base_db::{
@@ -71,7 +71,9 @@
     },
     prime_caches, symbol_index,
 };
-use syntax::SourceFile;
+use ide_db::{MiniCore, ra_fixture::RaFixtureAnalysis};
+use macros::UpmapFromRaFixture;
+use syntax::{SourceFile, ast};
 use triomphe::Arc;
 use view_memory_layout::{RecursiveMemoryLayout, view_memory_layout};
 
@@ -83,6 +85,7 @@
     expand_macro::ExpandedMacro,
     file_structure::{FileStructureConfig, StructureNode, StructureNodeKind},
     folding_ranges::{Fold, FoldKind},
+    goto_definition::GotoDefinitionConfig,
     highlight_related::{HighlightRelatedConfig, HighlightedRange},
     hover::{
         HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult,
@@ -102,7 +105,7 @@
     },
     move_item::Direction,
     navigation_target::{NavigationTarget, TryToNav, UpmappingResult},
-    references::ReferenceSearchResult,
+    references::{FindAllRefsConfig, ReferenceSearchResult},
     rename::RenameError,
     runnables::{Runnable, RunnableKind, TestId, UpdateTest},
     signature_help::SignatureHelp,
@@ -144,7 +147,7 @@
 pub type Cancellable<T> = Result<T, Cancelled>;
 
 /// Info associated with a text range.
-#[derive(Debug)]
+#[derive(Debug, UpmapFromRaFixture)]
 pub struct RangeInfo<T> {
     pub range: TextRange,
     pub info: T,
@@ -274,6 +277,28 @@
         (host.analysis(), file_id)
     }
 
+    pub(crate) fn from_ra_fixture(
+        sema: &Semantics<'_, RootDatabase>,
+        literal: ast::String,
+        expanded: &ast::String,
+        minicore: MiniCore<'_>,
+    ) -> Option<(Analysis, RaFixtureAnalysis)> {
+        Self::from_ra_fixture_with_on_cursor(sema, literal, expanded, minicore, &mut |_| {})
+    }
+
+    /// Like [`Analysis::from_ra_fixture()`], but also calls `on_cursor` with the cursor position.
+    pub(crate) fn from_ra_fixture_with_on_cursor(
+        sema: &Semantics<'_, RootDatabase>,
+        literal: ast::String,
+        expanded: &ast::String,
+        minicore: MiniCore<'_>,
+        on_cursor: &mut dyn FnMut(TextRange),
+    ) -> Option<(Analysis, RaFixtureAnalysis)> {
+        let analysis =
+            RaFixtureAnalysis::analyze_ra_fixture(sema, literal, expanded, minicore, on_cursor)?;
+        Some((Analysis { db: analysis.db.clone() }, analysis))
+    }
+
     /// Debug info about the current state of the analysis.
     pub fn status(&self, file_id: Option<FileId>) -> Cancellable<String> {
         self.with_db(|db| status::status(db, file_id))
@@ -446,7 +471,7 @@
     /// Returns a list of the places in the file where type hints can be displayed.
     pub fn inlay_hints(
         &self,
-        config: &InlayHintsConfig,
+        config: &InlayHintsConfig<'_>,
         file_id: FileId,
         range: Option<TextRange>,
     ) -> Cancellable<Vec<InlayHint>> {
@@ -454,7 +479,7 @@
     }
     pub fn inlay_hints_resolve(
         &self,
-        config: &InlayHintsConfig,
+        config: &InlayHintsConfig<'_>,
         file_id: FileId,
         resolve_range: TextRange,
         hash: u64,
@@ -495,16 +520,18 @@
     pub fn goto_definition(
         &self,
         position: FilePosition,
+        config: &GotoDefinitionConfig<'_>,
     ) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
-        self.with_db(|db| goto_definition::goto_definition(db, position))
+        self.with_db(|db| goto_definition::goto_definition(db, position, config))
     }
 
     /// Returns the declaration from the symbol at `position`.
     pub fn goto_declaration(
         &self,
         position: FilePosition,
+        config: &GotoDefinitionConfig<'_>,
     ) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
-        self.with_db(|db| goto_declaration::goto_declaration(db, position))
+        self.with_db(|db| goto_declaration::goto_declaration(db, position, config))
     }
 
     /// Returns the impls from the symbol at `position`.
@@ -526,19 +553,16 @@
     pub fn find_all_refs(
         &self,
         position: FilePosition,
-        search_scope: Option<SearchScope>,
+        config: &FindAllRefsConfig<'_>,
     ) -> Cancellable<Option<Vec<ReferenceSearchResult>>> {
-        let search_scope = AssertUnwindSafe(search_scope);
-        self.with_db(|db| {
-            let _ = &search_scope;
-            references::find_all_refs(&Semantics::new(db), position, search_scope.0)
-        })
+        let config = AssertUnwindSafe(config);
+        self.with_db(|db| references::find_all_refs(&Semantics::new(db), position, &config))
     }
 
     /// Returns a short text describing element at position.
     pub fn hover(
         &self,
-        config: &HoverConfig,
+        config: &HoverConfig<'_>,
         range: FileRange,
     ) -> Cancellable<Option<RangeInfo<HoverResult>>> {
         self.with_db(|db| hover::hover(db, range, config))
@@ -576,14 +600,15 @@
     pub fn call_hierarchy(
         &self,
         position: FilePosition,
+        config: &CallHierarchyConfig<'_>,
     ) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
-        self.with_db(|db| call_hierarchy::call_hierarchy(db, position))
+        self.with_db(|db| call_hierarchy::call_hierarchy(db, position, config))
     }
 
     /// Computes incoming calls for the given file position.
     pub fn incoming_calls(
         &self,
-        config: CallHierarchyConfig,
+        config: &CallHierarchyConfig<'_>,
         position: FilePosition,
     ) -> Cancellable<Option<Vec<CallItem>>> {
         self.with_db(|db| call_hierarchy::incoming_calls(db, config, position))
@@ -592,7 +617,7 @@
     /// Computes outgoing calls for the given file position.
     pub fn outgoing_calls(
         &self,
-        config: CallHierarchyConfig,
+        config: &CallHierarchyConfig<'_>,
         position: FilePosition,
     ) -> Cancellable<Option<Vec<CallItem>>> {
         self.with_db(|db| call_hierarchy::outgoing_calls(db, config, position))
@@ -675,28 +700,22 @@
     /// Computes syntax highlighting for the given file
     pub fn highlight(
         &self,
-        highlight_config: HighlightConfig,
+        highlight_config: HighlightConfig<'_>,
         file_id: FileId,
     ) -> Cancellable<Vec<HlRange>> {
-        // highlighting may construct a new database for "speculative" execution, so we can't currently attach the database
-        // highlighting instead sets up the attach hook where neceesary for the trait solver
-        Cancelled::catch(|| {
-            syntax_highlighting::highlight(&self.db, highlight_config, file_id, None)
-        })
+        self.with_db(|db| syntax_highlighting::highlight(db, &highlight_config, file_id, None))
     }
 
     /// Computes syntax highlighting for the given file range.
     pub fn highlight_range(
         &self,
-        highlight_config: HighlightConfig,
+        highlight_config: HighlightConfig<'_>,
         frange: FileRange,
     ) -> Cancellable<Vec<HlRange>> {
-        // highlighting may construct a new database for "speculative" execution, so we can't currently attach the database
-        // highlighting instead sets up the attach hook where neceesary for the trait solver
-        Cancelled::catch(|| {
+        self.with_db(|db| {
             syntax_highlighting::highlight(
-                &self.db,
-                highlight_config,
+                db,
+                &highlight_config,
                 frange.file_id,
                 Some(frange.range),
             )
@@ -706,22 +725,18 @@
     /// Computes syntax highlighting for the given file.
     pub fn highlight_as_html_with_config(
         &self,
-        config: HighlightConfig,
+        config: HighlightConfig<'_>,
         file_id: FileId,
         rainbow: bool,
     ) -> Cancellable<String> {
-        // highlighting may construct a new database for "speculative" execution, so we can't currently attach the database
-        // highlighting instead sets up the attach hook where neceesary for the trait solver
-        Cancelled::catch(|| {
-            syntax_highlighting::highlight_as_html_with_config(&self.db, config, file_id, rainbow)
+        self.with_db(|db| {
+            syntax_highlighting::highlight_as_html_with_config(db, &config, file_id, rainbow)
         })
     }
 
     /// Computes syntax highlighting for the given file.
     pub fn highlight_as_html(&self, file_id: FileId, rainbow: bool) -> Cancellable<String> {
-        // highlighting may construct a new database for "speculative" execution, so we can't currently attach the database
-        // highlighting instead sets up the attach hook where neceesary for the trait solver
-        Cancelled::catch(|| syntax_highlighting::highlight_as_html(&self.db, file_id, rainbow))
+        self.with_db(|db| syntax_highlighting::highlight_as_html(db, file_id, rainbow))
     }
 
     /// Computes completions at the given position.
@@ -853,14 +868,18 @@
 
     pub fn annotations(
         &self,
-        config: &AnnotationConfig,
+        config: &AnnotationConfig<'_>,
         file_id: FileId,
     ) -> Cancellable<Vec<Annotation>> {
         self.with_db(|db| annotations::annotations(db, config, file_id))
     }
 
-    pub fn resolve_annotation(&self, annotation: Annotation) -> Cancellable<Annotation> {
-        self.with_db(|db| annotations::resolve_annotation(db, annotation))
+    pub fn resolve_annotation(
+        &self,
+        config: &AnnotationConfig<'_>,
+        annotation: Annotation,
+    ) -> Cancellable<Annotation> {
+        self.with_db(|db| annotations::resolve_annotation(db, config, annotation))
     }
 
     pub fn move_item(
@@ -899,12 +918,8 @@
     where
         F: FnOnce(&RootDatabase) -> T + std::panic::UnwindSafe,
     {
-        hir::attach_db(&self.db, || {
-            // the trait solver code may invoke `as_view<HirDatabase>` outside of queries,
-            // so technically we might run into a panic in salsa if the downcaster has not yet been registered.
-            HirDatabase::zalsa_register_downcaster(&self.db);
-            Cancelled::catch(|| f(&self.db))
-        })
+        // We use `attach_db_allow_change()` and not `attach_db()` because fixture injection can change the database.
+        hir::attach_db_allow_change(&self.db, || Cancelled::catch(|| f(&self.db)))
     }
 }
 
diff --git a/crates/ide/src/markup.rs b/crates/ide/src/markup.rs
index 750d125..3eb9986 100644
--- a/crates/ide/src/markup.rs
+++ b/crates/ide/src/markup.rs
@@ -5,6 +5,8 @@
 //! what is used by LSP, so let's keep it simple.
 use std::fmt;
 
+use ide_db::impl_empty_upmap_from_ra_fixture;
+
 #[derive(Clone, Default, Debug, Hash, PartialEq, Eq)]
 pub struct Markup {
     text: String,
@@ -39,3 +41,5 @@
         format!("```text\n{contents}\n```").into()
     }
 }
+
+impl_empty_upmap_from_ra_fixture!(Markup);
diff --git a/crates/ide/src/moniker.rs b/crates/ide/src/moniker.rs
index f1aa03c..4aa9eb9 100644
--- a/crates/ide/src/moniker.rs
+++ b/crates/ide/src/moniker.rs
@@ -384,7 +384,7 @@
     })
 }
 
-fn display<T: HirDisplay>(db: &RootDatabase, module: hir::Module, it: T) -> String {
+fn display<'db, T: HirDisplay<'db>>(db: &'db RootDatabase, module: hir::Module, it: T) -> String {
     match it.display_source_code(db, module.into(), true) {
         Ok(result) => result,
         // Fallback on display variant that always succeeds
diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs
index db12983..b222ff3 100644
--- a/crates/ide/src/navigation_target.rs
+++ b/crates/ide/src/navigation_target.rs
@@ -14,6 +14,7 @@
     defs::{Definition, find_std_module},
     documentation::{Documentation, HasDocs},
     famous_defs::FamousDefs,
+    ra_fixture::UpmapFromRaFixture,
 };
 use span::Edition;
 use stdx::never;
@@ -78,6 +79,44 @@
     }
 }
 
+impl UpmapFromRaFixture for NavigationTarget {
+    fn upmap_from_ra_fixture(
+        self,
+        analysis: &ide_db::ra_fixture::RaFixtureAnalysis,
+        _virtual_file_id: FileId,
+        real_file_id: FileId,
+    ) -> Result<Self, ()> {
+        let virtual_file_id = self.file_id;
+        Ok(NavigationTarget {
+            file_id: real_file_id,
+            full_range: self.full_range.upmap_from_ra_fixture(
+                analysis,
+                virtual_file_id,
+                real_file_id,
+            )?,
+            focus_range: self.focus_range.upmap_from_ra_fixture(
+                analysis,
+                virtual_file_id,
+                real_file_id,
+            )?,
+            name: self.name.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?,
+            kind: self.kind.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?,
+            container_name: self.container_name.upmap_from_ra_fixture(
+                analysis,
+                virtual_file_id,
+                real_file_id,
+            )?,
+            description: self.description.upmap_from_ra_fixture(
+                analysis,
+                virtual_file_id,
+                real_file_id,
+            )?,
+            docs: self.docs.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?,
+            alias: self.alias.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?,
+        })
+    }
+}
+
 pub(crate) trait ToNav {
     fn to_nav(&self, db: &RootDatabase) -> UpmappingResult<NavigationTarget>;
 }
@@ -382,7 +421,7 @@
 
 impl<D> TryToNav for D
 where
-    D: HasSource + ToNavFromAst + Copy + HasDocs + HirDisplay + HasCrate,
+    D: HasSource + ToNavFromAst + Copy + HasDocs + for<'db> HirDisplay<'db> + HasCrate,
     D::Ast: ast::HasName,
 {
     fn try_to_nav(
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 0189939..a53a192 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -19,14 +19,17 @@
 
 use hir::{PathResolution, Semantics};
 use ide_db::{
-    FileId, RootDatabase,
+    FileId, MiniCore, RootDatabase,
     defs::{Definition, NameClass, NameRefClass},
     helpers::pick_best_token,
+    ra_fixture::UpmapFromRaFixture,
     search::{ReferenceCategory, SearchScope, UsageSearchResult},
 };
 use itertools::Itertools;
+use macros::UpmapFromRaFixture;
 use nohash_hasher::IntMap;
 use span::Edition;
+use syntax::AstToken;
 use syntax::{
     AstNode,
     SyntaxKind::*,
@@ -35,10 +38,12 @@
     match_ast,
 };
 
-use crate::{FilePosition, HighlightedRange, NavigationTarget, TryToNav, highlight_related};
+use crate::{
+    Analysis, FilePosition, HighlightedRange, NavigationTarget, TryToNav, highlight_related,
+};
 
 /// Result of a reference search operation.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, UpmapFromRaFixture)]
 pub struct ReferenceSearchResult {
     /// Information about the declaration site of the searched item.
     /// For ADTs (structs/enums), this points to the type definition.
@@ -54,7 +59,7 @@
 }
 
 /// Information about the declaration site of a searched item.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, UpmapFromRaFixture)]
 pub struct Declaration {
     /// Navigation information to jump to the declaration
     pub nav: NavigationTarget,
@@ -82,6 +87,12 @@
 //
 // ![Find All References](https://user-images.githubusercontent.com/48062697/113020670-b7c34f00-917a-11eb-8003-370ac5f2b3cb.gif)
 
+#[derive(Debug)]
+pub struct FindAllRefsConfig<'a> {
+    pub search_scope: Option<SearchScope>,
+    pub minicore: MiniCore<'a>,
+}
+
 /// Find all references to the item at the given position.
 ///
 /// # Arguments
@@ -110,14 +121,14 @@
 pub(crate) fn find_all_refs(
     sema: &Semantics<'_, RootDatabase>,
     position: FilePosition,
-    search_scope: Option<SearchScope>,
+    config: &FindAllRefsConfig<'_>,
 ) -> Option<Vec<ReferenceSearchResult>> {
     let _p = tracing::info_span!("find_all_refs").entered();
     let syntax = sema.parse_guess_edition(position.file_id).syntax().clone();
     let make_searcher = |literal_search: bool| {
         move |def: Definition| {
             let mut usages =
-                def.usages(sema).set_scope(search_scope.as_ref()).include_self_refs().all();
+                def.usages(sema).set_scope(config.search_scope.as_ref()).include_self_refs().all();
             if literal_search {
                 retain_adt_literal_usages(&mut usages, def, sema);
             }
@@ -165,6 +176,20 @@
         return Some(vec![res]);
     }
 
+    if let Some(token) = syntax.token_at_offset(position.offset).left_biased()
+        && let Some(token) = ast::String::cast(token.clone())
+        && let Some((analysis, fixture_analysis)) =
+            Analysis::from_ra_fixture(sema, token.clone(), &token, config.minicore)
+        && let Some((virtual_file_id, file_offset)) =
+            fixture_analysis.map_offset_down(position.offset)
+    {
+        return analysis
+            .find_all_refs(FilePosition { file_id: virtual_file_id, offset: file_offset }, config)
+            .ok()??
+            .upmap_from_ra_fixture(&fixture_analysis, virtual_file_id, position.file_id)
+            .ok();
+    }
+
     match name_for_constructor_search(&syntax, position) {
         Some(name) => {
             let def = match NameClass::classify(sema, &name)? {
@@ -433,10 +458,10 @@
 mod tests {
     use expect_test::{Expect, expect};
     use hir::EditionedFileId;
-    use ide_db::{FileId, RootDatabase};
+    use ide_db::{FileId, MiniCore, RootDatabase};
     use stdx::format_to;
 
-    use crate::{SearchScope, fixture};
+    use crate::{SearchScope, fixture, references::FindAllRefsConfig};
 
     #[test]
     fn exclude_tests() {
@@ -1513,8 +1538,11 @@
         expect: Expect,
     ) {
         let (analysis, pos) = fixture::position(ra_fixture);
-        let refs =
-            analysis.find_all_refs(pos, search_scope.map(|it| it(&analysis.db))).unwrap().unwrap();
+        let config = FindAllRefsConfig {
+            search_scope: search_scope.map(|it| it(&analysis.db)),
+            minicore: MiniCore::default(),
+        };
+        let refs = analysis.find_all_refs(pos, &config).unwrap().unwrap();
 
         let mut actual = String::new();
         for mut refs in refs {
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index cc1bbfb..494701d 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -8,6 +8,7 @@
     sym,
 };
 use ide_assists::utils::{has_test_related_attribute, test_related_attribute_syn};
+use ide_db::impl_empty_upmap_from_ra_fixture;
 use ide_db::{
     FilePosition, FxHashMap, FxIndexMap, FxIndexSet, RootDatabase, SymbolKind,
     base_db::RootQueryDb,
@@ -17,6 +18,7 @@
     search::{FileReferenceNode, SearchScope},
 };
 use itertools::Itertools;
+use macros::UpmapFromRaFixture;
 use smallvec::SmallVec;
 use span::{Edition, TextSize};
 use stdx::format_to;
@@ -28,7 +30,7 @@
 
 use crate::{FileId, NavigationTarget, ToNav, TryToNav, references};
 
-#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq, UpmapFromRaFixture)]
 pub struct Runnable {
     pub use_name_in_title: bool,
     pub nav: NavigationTarget,
@@ -37,6 +39,8 @@
     pub update_test: UpdateTest,
 }
 
+impl_empty_upmap_from_ra_fixture!(RunnableKind, UpdateTest);
+
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub enum TestId {
     Name(SmolStr),
diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs
index 453d6f5..e261928 100644
--- a/crates/ide/src/static_index.rs
+++ b/crates/ide/src/static_index.rs
@@ -4,7 +4,7 @@
 use arrayvec::ArrayVec;
 use hir::{Crate, Module, Semantics, db::HirDatabase};
 use ide_db::{
-    FileId, FileRange, FxHashMap, FxHashSet, RootDatabase,
+    FileId, FileRange, FxHashMap, FxHashSet, MiniCore, RootDatabase,
     base_db::{RootQueryDb, SourceDatabase, VfsPath},
     defs::{Definition, IdentClass},
     documentation::Documentation,
@@ -184,6 +184,7 @@
                     closing_brace_hints_min_lines: Some(25),
                     fields_to_resolve: InlayFieldsToResolve::empty(),
                     range_exclusive_hints: false,
+                    minicore: MiniCore::default(),
                 },
                 file_id,
                 None,
@@ -215,6 +216,7 @@
             max_enum_variants_count: Some(5),
             max_subst_ty_len: SubstTyLen::Unlimited,
             show_drop_glue: true,
+            minicore: MiniCore::default(),
         };
         let tokens = tokens.filter(|token| {
             matches!(
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index 0da9ee0..66895cb 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -1,7 +1,6 @@
 pub(crate) mod tags;
 
 mod highlights;
-mod injector;
 
 mod escape;
 mod format;
@@ -16,7 +15,7 @@
 
 use either::Either;
 use hir::{DefWithBody, EditionedFileId, InFile, InRealFile, MacroKind, Name, Semantics};
-use ide_db::{FxHashMap, FxHashSet, Ranker, RootDatabase, SymbolKind};
+use ide_db::{FxHashMap, FxHashSet, MiniCore, Ranker, RootDatabase, SymbolKind};
 use syntax::{
     AstNode, AstToken, NodeOrToken,
     SyntaxKind::*,
@@ -44,8 +43,8 @@
     pub binding_hash: Option<u64>,
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub struct HighlightConfig {
+#[derive(Copy, Clone, Debug)]
+pub struct HighlightConfig<'a> {
     /// Whether to highlight strings
     pub strings: bool,
     /// Whether to highlight comments
@@ -64,6 +63,7 @@
     pub macro_bang: bool,
     /// Whether to highlight unresolved things be their syntax
     pub syntactic_name_ref_highlighting: bool,
+    pub minicore: MiniCore<'a>,
 }
 
 // Feature: Semantic Syntax Highlighting
@@ -191,7 +191,7 @@
 // ![Semantic Syntax Highlighting](https://user-images.githubusercontent.com/48062697/113187625-f7f50100-9250-11eb-825e-91c58f236071.png)
 pub(crate) fn highlight(
     db: &RootDatabase,
-    config: HighlightConfig,
+    config: &HighlightConfig<'_>,
     file_id: FileId,
     range_to_highlight: Option<TextRange>,
 ) -> Vec<HlRange> {
@@ -226,7 +226,7 @@
 fn traverse(
     hl: &mut Highlights,
     sema: &Semantics<'_, RootDatabase>,
-    config: HighlightConfig,
+    config: &HighlightConfig<'_>,
     InRealFile { file_id, value: root }: InRealFile<&SyntaxNode>,
     krate: Option<hir::Crate>,
     range_to_highlight: TextRange,
@@ -426,12 +426,9 @@
         let edition = descended_element.file_id.edition(sema.db);
         let (unsafe_ops, bindings_shadow_count) = match current_body {
             Some(current_body) => {
-                let (ops, bindings) = per_body_cache.entry(current_body).or_insert_with(|| {
-                    (
-                        hir::attach_db(sema.db, || sema.get_unsafe_ops(current_body)),
-                        Default::default(),
-                    )
-                });
+                let (ops, bindings) = per_body_cache
+                    .entry(current_body)
+                    .or_insert_with(|| (sema.get_unsafe_ops(current_body), Default::default()));
                 (&*ops, Some(bindings))
             }
             None => (&empty, None),
@@ -494,7 +491,7 @@
 fn string_injections(
     hl: &mut Highlights,
     sema: &Semantics<'_, RootDatabase>,
-    config: HighlightConfig,
+    config: &HighlightConfig<'_>,
     file_id: EditionedFileId,
     krate: Option<hir::Crate>,
     token: SyntaxToken,
@@ -591,7 +588,7 @@
     })
 }
 
-fn filter_by_config(highlight: &mut Highlight, config: HighlightConfig) -> bool {
+fn filter_by_config(highlight: &mut Highlight, config: &HighlightConfig<'_>) -> bool {
     match &mut highlight.tag {
         HlTag::StringLiteral if !config.strings => return false,
         HlTag::Comment if !config.comments => return false,
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index d73575f..829d127 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -137,7 +137,7 @@
         }
         (T![!], MACRO_RULES) => HlPunct::MacroBang.into(),
         (T![!], NEVER_TYPE) => HlTag::BuiltinType.into(),
-        (T![!], PREFIX_EXPR) => HlOperator::Logical.into(),
+        (T![!], PREFIX_EXPR) => HlOperator::Negation.into(),
         (T![*], PTR_TYPE) => HlTag::Keyword.into(),
         (T![*], PREFIX_EXPR) => {
             let h = HlTag::Operator(HlOperator::Other).into();
diff --git a/crates/ide/src/syntax_highlighting/html.rs b/crates/ide/src/syntax_highlighting/html.rs
index 358ac9b..75e46b8 100644
--- a/crates/ide/src/syntax_highlighting/html.rs
+++ b/crates/ide/src/syntax_highlighting/html.rs
@@ -1,6 +1,7 @@
 //! Renders a bit of code as HTML.
 
 use hir::{EditionedFileId, Semantics};
+use ide_db::MiniCore;
 use oorandom::Rand32;
 use stdx::format_to;
 use syntax::AstNode;
@@ -12,7 +13,7 @@
 
 pub(crate) fn highlight_as_html_with_config(
     db: &RootDatabase,
-    config: HighlightConfig,
+    config: &HighlightConfig<'_>,
     file_id: FileId,
     rainbow: bool,
 ) -> String {
@@ -60,7 +61,7 @@
 pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: bool) -> String {
     highlight_as_html_with_config(
         db,
-        HighlightConfig {
+        &HighlightConfig {
             strings: true,
             comments: true,
             punctuation: true,
@@ -70,6 +71,7 @@
             inject_doc_comment: true,
             macro_bang: true,
             syntactic_name_ref_highlighting: false,
+            minicore: MiniCore::default(),
         },
         file_id,
         rainbow,
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs
index efc7782..7955f5a 100644
--- a/crates/ide/src/syntax_highlighting/inject.rs
+++ b/crates/ide/src/syntax_highlighting/inject.rs
@@ -4,9 +4,9 @@
 
 use either::Either;
 use hir::{EditionedFileId, HirFileId, InFile, Semantics, sym};
+use ide_db::range_mapper::RangeMapper;
 use ide_db::{
-    SymbolKind, active_parameter::ActiveParameter, defs::Definition,
-    documentation::docs_with_rangemap, rust_doc::is_rust_fence,
+    SymbolKind, defs::Definition, documentation::docs_with_rangemap, rust_doc::is_rust_fence,
 };
 use syntax::{
     AstToken, NodeOrToken, SyntaxNode, TextRange, TextSize,
@@ -16,85 +16,56 @@
 use crate::{
     Analysis, HlMod, HlRange, HlTag, RootDatabase,
     doc_links::{doc_attributes, extract_definitions_from_docs, resolve_doc_path_for_def},
-    syntax_highlighting::{HighlightConfig, highlights::Highlights, injector::Injector},
+    syntax_highlighting::{HighlightConfig, highlights::Highlights},
 };
 
 pub(super) fn ra_fixture(
     hl: &mut Highlights,
     sema: &Semantics<'_, RootDatabase>,
-    config: HighlightConfig,
+    config: &HighlightConfig<'_>,
     literal: &ast::String,
     expanded: &ast::String,
 ) -> Option<()> {
-    let active_parameter =
-        hir::attach_db(sema.db, || ActiveParameter::at_token(sema, expanded.syntax().clone()))?;
-    let has_rust_fixture_attr = active_parameter.attrs().is_some_and(|attrs| {
-        attrs.filter_map(|attr| attr.as_simple_path()).any(|path| {
-            path.segments()
-                .zip(["rust_analyzer", "rust_fixture"])
-                .all(|(seg, name)| seg.name_ref().map_or(false, |nr| nr.text() == name))
-        })
-    });
-    if !has_rust_fixture_attr {
-        return None;
-    }
-    let value = literal.value().ok()?;
+    let (analysis, fixture_analysis) = Analysis::from_ra_fixture_with_on_cursor(
+        sema,
+        literal.clone(),
+        expanded,
+        config.minicore,
+        &mut |range| {
+            hl.add(HlRange {
+                range,
+                highlight: HlTag::Keyword | HlMod::Injected,
+                binding_hash: None,
+            });
+        },
+    )?;
 
     if let Some(range) = literal.open_quote_text_range() {
         hl.add(HlRange { range, highlight: HlTag::StringLiteral.into(), binding_hash: None })
     }
 
-    let mut inj = Injector::default();
-
-    let mut text = &*value;
-    let mut offset: TextSize = 0.into();
-
-    while !text.is_empty() {
-        let marker = "$0";
-        let idx = text.find(marker).unwrap_or(text.len());
-        let (chunk, next) = text.split_at(idx);
-        inj.add(chunk, TextRange::at(offset, TextSize::of(chunk)));
-
-        text = next;
-        offset += TextSize::of(chunk);
-
-        if let Some(next) = text.strip_prefix(marker) {
-            if let Some(range) = literal.map_range_up(TextRange::at(offset, TextSize::of(marker))) {
-                hl.add(HlRange {
-                    range,
-                    highlight: HlTag::Keyword | HlMod::Injected,
-                    binding_hash: None,
-                });
-            }
-
-            text = next;
-
-            let marker_len = TextSize::of(marker);
-            offset += marker_len;
-        }
-    }
-
-    let (analysis, tmp_file_id) = Analysis::from_single_file(inj.take_text());
-
-    for mut hl_range in analysis
-        .highlight(
-            HighlightConfig {
-                syntactic_name_ref_highlighting: false,
-                comments: true,
-                punctuation: true,
-                operator: true,
-                strings: true,
-                specialize_punctuation: config.specialize_punctuation,
-                specialize_operator: config.operator,
-                inject_doc_comment: config.inject_doc_comment,
-                macro_bang: config.macro_bang,
-            },
-            tmp_file_id,
-        )
-        .unwrap()
-    {
-        for range in inj.map_range_up(hl_range.range) {
-            if let Some(range) = literal.map_range_up(range) {
+    for tmp_file_id in fixture_analysis.files() {
+        for mut hl_range in analysis
+            .highlight(
+                HighlightConfig {
+                    syntactic_name_ref_highlighting: false,
+                    comments: true,
+                    punctuation: true,
+                    operator: true,
+                    strings: true,
+                    specialize_punctuation: config.specialize_punctuation,
+                    specialize_operator: config.operator,
+                    inject_doc_comment: config.inject_doc_comment,
+                    macro_bang: config.macro_bang,
+                    // What if there is a fixture inside a fixture? It's fixtures all the way down.
+                    // (In fact, we have a fixture inside a fixture in our test suite!)
+                    minicore: config.minicore,
+                },
+                tmp_file_id,
+            )
+            .unwrap()
+        {
+            for range in fixture_analysis.map_range_up(tmp_file_id, hl_range.range) {
                 hl_range.range = range;
                 hl_range.highlight |= HlMod::Injected;
                 hl.add(hl_range);
@@ -116,7 +87,7 @@
 pub(super) fn doc_comment(
     hl: &mut Highlights,
     sema: &Semantics<'_, RootDatabase>,
-    config: HighlightConfig,
+    config: &HighlightConfig<'_>,
     src_file_id: EditionedFileId,
     node: &SyntaxNode,
 ) {
@@ -128,39 +99,37 @@
 
     // Extract intra-doc links and emit highlights for them.
     if let Some((docs, doc_mapping)) = docs_with_rangemap(sema.db, &attributes) {
-        hir::attach_db(sema.db, || {
-            extract_definitions_from_docs(&docs)
-                .into_iter()
-                .filter_map(|(range, link, ns)| {
-                    doc_mapping
-                        .map(range)
-                        .filter(|(mapping, _)| mapping.file_id == src_file_id)
-                        .and_then(|(InFile { value: mapped_range, .. }, attr_id)| {
-                            Some(mapped_range).zip(resolve_doc_path_for_def(
-                                sema.db,
-                                def,
-                                &link,
-                                ns,
-                                attr_id.is_inner_attr(),
-                            ))
-                        })
-                })
-                .for_each(|(range, def)| {
-                    hl.add(HlRange {
-                        range,
-                        highlight: module_def_to_hl_tag(def)
-                            | HlMod::Documentation
-                            | HlMod::Injected
-                            | HlMod::IntraDocLink,
-                        binding_hash: None,
+        extract_definitions_from_docs(&docs)
+            .into_iter()
+            .filter_map(|(range, link, ns)| {
+                doc_mapping
+                    .map(range)
+                    .filter(|(mapping, _)| mapping.file_id == src_file_id)
+                    .and_then(|(InFile { value: mapped_range, .. }, attr_id)| {
+                        Some(mapped_range).zip(resolve_doc_path_for_def(
+                            sema.db,
+                            def,
+                            &link,
+                            ns,
+                            attr_id.is_inner_attr(),
+                        ))
                     })
+            })
+            .for_each(|(range, def)| {
+                hl.add(HlRange {
+                    range,
+                    highlight: module_def_to_hl_tag(def)
+                        | HlMod::Documentation
+                        | HlMod::Injected
+                        | HlMod::IntraDocLink,
+                    binding_hash: None,
                 })
-        });
+            })
     }
 
     // Extract doc-test sources from the docs and calculate highlighting for them.
 
-    let mut inj = Injector::default();
+    let mut inj = RangeMapper::default();
     inj.add_unmapped("fn doctest() {\n");
 
     let attrs_source_map = attributes.source_map(sema.db);
@@ -249,7 +218,7 @@
     if let Ok(ranges) = analysis.with_db(|db| {
         super::highlight(
             db,
-            HighlightConfig {
+            &HighlightConfig {
                 syntactic_name_ref_highlighting: true,
                 comments: true,
                 punctuation: true,
@@ -259,6 +228,7 @@
                 specialize_operator: config.operator,
                 inject_doc_comment: config.inject_doc_comment,
                 macro_bang: config.macro_bang,
+                minicore: config.minicore,
             },
             tmp_file_id,
             None,
diff --git a/crates/ide/src/syntax_highlighting/injector.rs b/crates/ide/src/syntax_highlighting/injector.rs
deleted file mode 100644
index c30f797..0000000
--- a/crates/ide/src/syntax_highlighting/injector.rs
+++ /dev/null
@@ -1,77 +0,0 @@
-//! Extracts a subsequence of a text document, remembering the mapping of ranges
-//! between original and extracted texts.
-use std::ops::{self, Sub};
-
-use stdx::equal_range_by;
-use syntax::{TextRange, TextSize};
-
-#[derive(Default)]
-pub(super) struct Injector {
-    buf: String,
-    ranges: Vec<(TextRange, Option<Delta<TextSize>>)>,
-}
-
-impl Injector {
-    pub(super) fn add(&mut self, text: &str, source_range: TextRange) {
-        let len = TextSize::of(text);
-        assert_eq!(len, source_range.len());
-        self.add_impl(text, Some(source_range.start()));
-    }
-
-    pub(super) fn add_unmapped(&mut self, text: &str) {
-        self.add_impl(text, None);
-    }
-
-    fn add_impl(&mut self, text: &str, source: Option<TextSize>) {
-        let len = TextSize::of(text);
-        let target_range = TextRange::at(TextSize::of(&self.buf), len);
-        self.ranges.push((target_range, source.map(|it| Delta::new(target_range.start(), it))));
-        self.buf.push_str(text);
-    }
-
-    pub(super) fn take_text(&mut self) -> String {
-        std::mem::take(&mut self.buf)
-    }
-
-    pub(super) fn map_range_up(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ {
-        equal_range_by(&self.ranges, |&(r, _)| TextRange::ordering(r, range)).filter_map(move |i| {
-            let (target_range, delta) = self.ranges[i];
-            let intersection = target_range.intersect(range).unwrap();
-            Some(intersection + delta?)
-        })
-    }
-}
-
-#[derive(Clone, Copy)]
-enum Delta<T> {
-    Add(T),
-    Sub(T),
-}
-
-impl<T> Delta<T> {
-    fn new(from: T, to: T) -> Delta<T>
-    where
-        T: Ord + Sub<Output = T>,
-    {
-        if to >= from { Delta::Add(to - from) } else { Delta::Sub(from - to) }
-    }
-}
-
-impl ops::Add<Delta<TextSize>> for TextSize {
-    type Output = TextSize;
-
-    fn add(self, rhs: Delta<TextSize>) -> TextSize {
-        match rhs {
-            Delta::Add(it) => self + it,
-            Delta::Sub(it) => self - it,
-        }
-    }
-}
-
-impl ops::Add<Delta<TextSize>> for TextRange {
-    type Output = TextRange;
-
-    fn add(self, rhs: Delta<TextSize>) -> TextRange {
-        TextRange::at(self.start() + rhs, self.len())
-    }
-}
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs
index 4b87626..456a612 100644
--- a/crates/ide/src/syntax_highlighting/tags.rs
+++ b/crates/ide/src/syntax_highlighting/tags.rs
@@ -124,8 +124,10 @@
     Bitwise,
     /// +, -, *, /, +=, -=, *=, /=
     Arithmetic,
-    /// &&, ||, !
+    /// &&, ||
     Logical,
+    /// !
+    Negation,
     /// >, <, ==, >=, <=, !=
     Comparison,
     /// Other operators
@@ -194,6 +196,7 @@
                 HlOperator::Arithmetic => "arithmetic",
                 HlOperator::Logical => "logical",
                 HlOperator::Comparison => "comparison",
+                HlOperator::Negation => "negation",
                 HlOperator::Other => "operator",
             },
             HlTag::StringLiteral => "string_literal",
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_general.html b/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
index d99b29c..d058191 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
@@ -148,7 +148,7 @@
     <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="parenthesis">(</span><span class="numeric_literal">-</span><span class="numeric_literal">42</span><span class="comma">,</span><span class="parenthesis">)</span><span class="semicolon">;</span>
     <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="operator">-</span><span class="variable">baz</span><span class="operator">.</span><span class="field library">0</span><span class="semicolon">;</span>
 
-    <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="logical">!</span><span class="bool_literal">true</span><span class="semicolon">;</span>
+    <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="negation">!</span><span class="bool_literal">true</span><span class="semicolon">;</span>
 
     <span class="label declaration">'foo</span><span class="colon">:</span> <span class="keyword control">loop</span> <span class="brace">{</span>
         <span class="keyword control">break</span> <span class="label">'foo</span><span class="semicolon">;</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
index 3b468ab..579c6ce 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
@@ -43,18 +43,19 @@
 <pre><code><span class="keyword">fn</span> <span class="function declaration">fixture</span><span class="parenthesis">(</span><span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="tool_module attribute">rust_analyzer</span><span class="operator attribute">::</span><span class="tool_module attribute">rust_fixture</span><span class="attribute_bracket attribute">]</span> <span class="value_param declaration reference">ra_fixture</span><span class="colon">:</span> <span class="punctuation">&</span><span class="builtin_type">str</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
 
 <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
-    <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r#"</span><span class="none injected">
-</span><span class="keyword injected">trait</span><span class="none injected"> </span><span class="trait declaration injected">Foo</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected">
-    </span><span class="keyword injected">fn</span><span class="none injected"> </span><span class="function associated declaration injected static trait">foo</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected">
-        </span><span class="unresolved_reference injected">println</span><span class="macro_bang injected">!</span><span class="parenthesis injected">(</span><span class="string_literal injected">"2 + 2 = {}"</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">4</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span><span class="none injected">
-    </span><span class="brace injected">}</span><span class="none injected">
+    <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r#"</span>
+@@- minicore: sized
+<span class="keyword injected">trait</span><span class="none injected"> </span><span class="trait declaration injected">Foo</span><span class="colon injected">:</span><span class="none injected"> </span><span class="trait default_library injected library">Sized</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected">
+</span>    <span class="keyword injected">fn</span><span class="none injected"> </span><span class="function associated declaration injected static trait">foo</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected">
+</span>        <span class="unresolved_reference injected">println</span><span class="macro_bang injected">!</span><span class="parenthesis injected">(</span><span class="string_literal injected">"2 + 2 = {}"</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">4</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span><span class="none injected">
+</span>    <span class="brace injected">}</span><span class="none injected">
 </span><span class="brace injected">}</span><span class="string_literal">"#</span>
     <span class="parenthesis">)</span><span class="semicolon">;</span>
-    <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r"</span><span class="none injected">
-</span><span class="keyword injected">fn</span><span class="none injected"> </span><span class="function declaration injected">foo</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected">
-    </span><span class="function injected">foo</span><span class="parenthesis injected">(</span><span class="keyword injected">$0</span><span class="brace injected">{</span><span class="none injected">
-        </span><span class="numeric_literal injected">92</span><span class="none injected">
-    </span><span class="brace injected">}</span><span class="keyword injected">$0</span><span class="parenthesis injected">)</span><span class="none injected">
+    <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r"</span>
+<span class="keyword injected">fn</span><span class="none injected"> </span><span class="function declaration injected">foo</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected">
+</span>    <span class="function injected">foo</span><span class="parenthesis injected">(</span><span class="keyword injected">$0</span><span class="brace injected">{</span><span class="none injected">
+</span>        <span class="numeric_literal injected">92</span><span class="none injected">
+</span>    <span class="brace injected">}</span><span class="keyword injected">$0</span><span class="parenthesis injected">)</span><span class="none injected">
 </span><span class="brace injected">}</span><span class="string_literal">"</span>
     <span class="parenthesis">)</span><span class="semicolon">;</span>
 <span class="brace">}</span></code></pre>
\ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection_2.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection_2.html
new file mode 100644
index 0000000..fc2d9a3
--- /dev/null
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection_2.html
@@ -0,0 +1,61 @@
+
+<style>
+body                { margin: 0; }
+pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
+
+.lifetime           { color: #DFAF8F; font-style: italic; }
+.label              { color: #DFAF8F; font-style: italic; }
+.comment            { color: #7F9F7F; }
+.documentation      { color: #629755; }
+.intra_doc_link     { font-style: italic; }
+.injected           { opacity: 0.65 ; }
+.struct, .enum      { color: #7CB8BB; }
+.enum_variant       { color: #BDE0F3; }
+.string_literal     { color: #CC9393; }
+.field              { color: #94BFF3; }
+.function           { color: #93E0E3; }
+.parameter          { color: #94BFF3; }
+.text               { color: #DCDCCC; }
+.type               { color: #7CB8BB; }
+.builtin_type       { color: #8CD0D3; }
+.type_param         { color: #DFAF8F; }
+.attribute          { color: #94BFF3; }
+.numeric_literal    { color: #BFEBBF; }
+.bool_literal       { color: #BFE6EB; }
+.macro              { color: #94BFF3; }
+.proc_macro         { color: #94BFF3; text-decoration: underline; }
+.derive             { color: #94BFF3; font-style: italic; }
+.module             { color: #AFD8AF; }
+.value_param        { color: #DCDCCC; }
+.variable           { color: #DCDCCC; }
+.format_specifier   { color: #CC696B; }
+.mutable            { text-decoration: underline; }
+.escape_sequence    { color: #94BFF3; }
+.keyword            { color: #F0DFAF; font-weight: bold; }
+.control            { font-style: italic; }
+.reference          { font-style: italic; font-weight: bold; }
+.const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
+
+.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
+.unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
+</style>
+<pre><code><span class="keyword">fn</span> <span class="function declaration">fixture</span><span class="parenthesis">(</span><span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="tool_module attribute">rust_analyzer</span><span class="operator attribute">::</span><span class="tool_module attribute">rust_fixture</span><span class="attribute_bracket attribute">]</span> <span class="value_param declaration reference">ra_fixture</span><span class="colon">:</span> <span class="punctuation">&</span><span class="builtin_type">str</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
+
+<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
+    <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r#"</span>
+@@- /main.rs crate:main deps:other_crate
+<span class="keyword injected">fn</span><span class="none injected"> </span><span class="function declaration injected">test</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected">
+</span>    <span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">x</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="module crate_root injected library">other_crate</span><span class="operator injected">::</span><span class="module injected library">foo</span><span class="operator injected">::</span><span class="struct injected library">S</span><span class="operator injected">::</span><span class="function associated injected library static">thing</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span><span class="none injected">
+</span>    <span class="variable injected">x</span><span class="semicolon injected">;</span><span class="none injected">
+</span><span class="brace injected">}</span><span class="none injected"> </span><span class="comment injected">//^ i128</span><span class="none injected">
+</span><span class="none injected">
+</span>@@- /lib.rs crate:other_crate
+<span class="keyword injected">pub</span><span class="none injected"> </span><span class="keyword injected">mod</span><span class="none injected"> </span><span class="module declaration injected public">foo</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected">
+</span>    <span class="keyword injected">pub</span><span class="none injected"> </span><span class="keyword injected">struct</span><span class="none injected"> </span><span class="struct declaration injected public">S</span><span class="semicolon injected">;</span><span class="none injected">
+</span>    <span class="keyword injected">impl</span><span class="none injected"> </span><span class="struct injected public">S</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected">
+</span>        <span class="keyword injected">pub</span><span class="none injected"> </span><span class="keyword injected">fn</span><span class="none injected"> </span><span class="function associated declaration injected public static">thing</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="operator injected">-&gt;</span><span class="none injected"> </span><span class="builtin_type injected">i128</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected"> </span><span class="numeric_literal injected">0</span><span class="none injected"> </span><span class="brace injected">}</span><span class="none injected">
+</span>    <span class="brace injected">}</span><span class="none injected">
+</span><span class="brace injected">}</span><span class="none injected">
+</span>   <span class="none injected"> </span><span class="string_literal">"#</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+<span class="brace">}</span></code></pre>
\ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html b/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html
index 9c42401..cceb159 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html
@@ -41,7 +41,7 @@
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 </style>
 <pre><code><span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
-    <span class="numeric_literal">1</span> <span class="arithmetic">+</span> <span class="numeric_literal">1</span> <span class="arithmetic">-</span> <span class="numeric_literal">1</span> <span class="arithmetic">*</span> <span class="numeric_literal">1</span> <span class="arithmetic">/</span> <span class="numeric_literal">1</span> <span class="arithmetic">%</span> <span class="numeric_literal">1</span> <span class="bitwise">|</span> <span class="numeric_literal">1</span> <span class="bitwise">&</span> <span class="numeric_literal">1</span> <span class="logical">!</span> <span class="numeric_literal">1</span> <span class="bitwise">^</span> <span class="numeric_literal">1</span> <span class="bitwise">&gt;&gt;</span> <span class="numeric_literal">1</span> <span class="bitwise">&lt;&lt;</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
+    <span class="numeric_literal">1</span> <span class="arithmetic">+</span> <span class="numeric_literal">1</span> <span class="arithmetic">-</span> <span class="numeric_literal">1</span> <span class="arithmetic">*</span> <span class="numeric_literal">1</span> <span class="arithmetic">/</span> <span class="numeric_literal">1</span> <span class="arithmetic">%</span> <span class="numeric_literal">1</span> <span class="bitwise">|</span> <span class="numeric_literal">1</span> <span class="bitwise">&</span> <span class="numeric_literal">1</span> <span class="negation">!</span> <span class="numeric_literal">1</span> <span class="bitwise">^</span> <span class="numeric_literal">1</span> <span class="bitwise">&gt;&gt;</span> <span class="numeric_literal">1</span> <span class="bitwise">&lt;&lt;</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
     <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">a</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="semicolon">;</span>
     <span class="variable mutable">a</span> <span class="arithmetic mutable">+=</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
     <span class="variable mutable">a</span> <span class="arithmetic mutable">-=</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 8198701..4e84127 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -1,13 +1,13 @@
 use std::time::Instant;
 
 use expect_test::{ExpectFile, expect_file};
-use ide_db::SymbolKind;
+use ide_db::{MiniCore, SymbolKind};
 use span::Edition;
 use test_utils::{AssertLinear, bench, bench_fixture, skip_slow_tests};
 
 use crate::{FileRange, HighlightConfig, HlTag, TextRange, fixture};
 
-const HL_CONFIG: HighlightConfig = HighlightConfig {
+const HL_CONFIG: HighlightConfig<'_> = HighlightConfig {
     strings: true,
     comments: true,
     punctuation: true,
@@ -17,6 +17,7 @@
     inject_doc_comment: true,
     macro_bang: true,
     syntactic_name_ref_highlighting: false,
+    minicore: MiniCore::default(),
 };
 
 #[test]
@@ -1017,6 +1018,35 @@
 }
 
 #[test]
+fn test_injection_2() {
+    check_highlighting(
+        r##"
+fn fixture(#[rust_analyzer::rust_fixture] ra_fixture: &str) {}
+
+fn main() {
+    fixture(r#"
+@@- /main.rs crate:main deps:other_crate
+fn test() {
+    let x = other_crate::foo::S::thing();
+    x;
+} //^ i128
+
+@@- /lib.rs crate:other_crate
+pub mod foo {
+    pub struct S;
+    impl S {
+        pub fn thing() -> i128 { 0 }
+    }
+}
+    "#);
+}
+"##,
+        expect_file!["./test_data/highlight_injection_2.html"],
+        false,
+    );
+}
+
+#[test]
 fn test_injection() {
     check_highlighting(
         r##"
@@ -1024,7 +1054,8 @@
 
 fn main() {
     fixture(r#"
-trait Foo {
+@@- minicore: sized
+trait Foo: Sized {
     fn foo() {
         println!("2 + 2 = {}", 4);
     }
@@ -1223,7 +1254,7 @@
 /// Note that the `snapshot` file is overwritten by the rendered HTML.
 fn check_highlighting_with_config(
     #[rust_analyzer::rust_fixture] ra_fixture: &str,
-    config: HighlightConfig,
+    config: HighlightConfig<'_>,
     expect: ExpectFile,
     rainbow: bool,
 ) {
diff --git a/crates/intern/src/symbol/symbols.rs b/crates/intern/src/symbol/symbols.rs
index 920bdd9..756377f 100644
--- a/crates/intern/src/symbol/symbols.rs
+++ b/crates/intern/src/symbol/symbols.rs
@@ -517,4 +517,6 @@
     precision,
     width,
     never_type_fallback,
+    specialization,
+    min_specialization,
 }
diff --git a/crates/macros/src/lib.rs b/crates/macros/src/lib.rs
index 8bafcf4..3f90ecc 100644
--- a/crates/macros/src/lib.rs
+++ b/crates/macros/src/lib.rs
@@ -162,3 +162,42 @@
 
     ignored
 }
+
+decl_derive!(
+    [UpmapFromRaFixture] => upmap_from_ra_fixture
+);
+
+fn upmap_from_ra_fixture(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
+    if let syn::Data::Union(_) = s.ast().data {
+        panic!("cannot derive on union")
+    }
+
+    s.add_bounds(synstructure::AddBounds::Generics);
+    s.bind_with(|_| synstructure::BindStyle::Move);
+    let body = s.each_variant(|vi| {
+        let bindings = vi.bindings();
+        vi.construct(|_, index| {
+            let bind = &bindings[index];
+
+            quote! {
+                ::ide_db::ra_fixture::UpmapFromRaFixture::upmap_from_ra_fixture(
+                    #bind, __analysis, __virtual_file_id, __real_file_id,
+                )?
+            }
+        })
+    });
+
+    s.bound_impl(
+        quote!(::ide_db::ra_fixture::UpmapFromRaFixture),
+        quote! {
+            fn upmap_from_ra_fixture(
+                self,
+                __analysis: &::ide_db::ra_fixture::RaFixtureAnalysis,
+                __virtual_file_id: ::ide_db::ra_fixture::FileId,
+                __real_file_id: ::ide_db::ra_fixture::FileId,
+            ) -> Result<Self, ()> {
+                Ok(match self { #body })
+            }
+        },
+    )
+}
diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml
index c7da654..8384d5b 100644
--- a/crates/parser/Cargo.toml
+++ b/crates/parser/Cargo.toml
@@ -19,6 +19,7 @@
 tracing = { workspace = true, optional = true }
 
 edition.workspace = true
+winnow = { version = "0.7.13", default-features = false }
 
 [dev-dependencies]
 expect-test = "1.5.1"
diff --git a/crates/parser/src/frontmatter.rs b/crates/parser/src/frontmatter.rs
new file mode 100644
index 0000000..2747db4
--- /dev/null
+++ b/crates/parser/src/frontmatter.rs
@@ -0,0 +1,348 @@
+// Copied from https://github.com/rust-lang/cargo/blob/367fd9f213750cd40317803dd0a5a3ce3f0c676d/src/cargo/util/frontmatter.rs
+#![expect(dead_code)] // avoid editing
+#![expect(unreachable_pub)] // avoid editing
+#![expect(clippy::useless_format)] // avoid editing
+
+type Span = std::ops::Range<usize>;
+
+#[derive(Debug)]
+pub struct ScriptSource<'s> {
+    /// The full file
+    raw: &'s str,
+    /// The `#!/usr/bin/env cargo` line, if present
+    shebang: Option<Span>,
+    /// The code fence opener (`---`)
+    open: Option<Span>,
+    /// Trailing text after `ScriptSource::open` that identifies the meaning of
+    /// `ScriptSource::frontmatter`
+    info: Option<Span>,
+    /// The lines between `ScriptSource::open` and `ScriptSource::close`
+    frontmatter: Option<Span>,
+    /// The code fence closer (`---`)
+    close: Option<Span>,
+    /// All content after the frontmatter and shebang
+    content: Span,
+}
+
+impl<'s> ScriptSource<'s> {
+    pub fn parse(raw: &'s str) -> Result<Self, FrontmatterError> {
+        use winnow::stream::FindSlice as _;
+        use winnow::stream::Location as _;
+        use winnow::stream::Offset as _;
+        use winnow::stream::Stream as _;
+
+        let content_end = raw.len();
+        let mut source = Self {
+            raw,
+            shebang: None,
+            open: None,
+            info: None,
+            frontmatter: None,
+            close: None,
+            content: 0..content_end,
+        };
+
+        let mut input = winnow::stream::LocatingSlice::new(raw);
+
+        if let Some(shebang_end) = strip_shebang(input.as_ref()) {
+            let shebang_start = input.current_token_start();
+            let _ = input.next_slice(shebang_end);
+            let shebang_end = input.current_token_start();
+            source.shebang = Some(shebang_start..shebang_end);
+            source.content = shebang_end..content_end;
+        }
+
+        // Whitespace may precede a frontmatter but must end with a newline
+        if let Some(nl_end) = strip_ws_lines(input.as_ref()) {
+            let _ = input.next_slice(nl_end);
+        }
+
+        // Opens with a line that starts with 3 or more `-` followed by an optional identifier
+        const FENCE_CHAR: char = '-';
+        let fence_length = input
+            .as_ref()
+            .char_indices()
+            .find_map(|(i, c)| (c != FENCE_CHAR).then_some(i))
+            .unwrap_or_else(|| input.eof_offset());
+        let open_start = input.current_token_start();
+        let fence_pattern = input.next_slice(fence_length);
+        let open_end = input.current_token_start();
+        match fence_length {
+            0 => {
+                return Ok(source);
+            }
+            1 | 2 => {
+                // either not a frontmatter or invalid frontmatter opening
+                return Err(FrontmatterError::new(
+                    format!(
+                        "found {fence_length} `{FENCE_CHAR}` in rust frontmatter, expected at least 3"
+                    ),
+                    raw.len()..raw.len(),
+                ).push_visible_span(open_start..open_end));
+            }
+            _ => {}
+        }
+        source.open = Some(open_start..open_end);
+        let Some(info_nl) = input.find_slice("\n") else {
+            return Err(FrontmatterError::new(
+                format!("unclosed frontmatter; expected `{fence_pattern}`"),
+                raw.len()..raw.len(),
+            )
+            .push_visible_span(open_start..open_end));
+        };
+        let info = input.next_slice(info_nl.start);
+        let info = info.strip_suffix('\r').unwrap_or(info); // already excludes `\n`
+        let info = info.trim_matches(is_horizontal_whitespace);
+        if !info.is_empty() {
+            let info_start = info.offset_from(&raw);
+            let info_end = info_start + info.len();
+            source.info = Some(info_start..info_end);
+        }
+
+        // Ends with a line that starts with a matching number of `-` only followed by whitespace
+        let nl_fence_pattern = format!("\n{fence_pattern}");
+        let Some(frontmatter_nl) = input.find_slice(nl_fence_pattern.as_str()) else {
+            for len in (2..(nl_fence_pattern.len() - 1)).rev() {
+                let Some(frontmatter_nl) = input.find_slice(&nl_fence_pattern[0..len]) else {
+                    continue;
+                };
+                let _ = input.next_slice(frontmatter_nl.start + 1);
+                let close_start = input.current_token_start();
+                let _ = input.next_slice(len);
+                let close_end = input.current_token_start();
+                let fewer_dashes = fence_length - len;
+                return Err(FrontmatterError::new(
+                    format!(
+                        "closing code fence has {fewer_dashes} less `-` than the opening fence"
+                    ),
+                    close_start..close_end,
+                )
+                .push_visible_span(open_start..open_end));
+            }
+            return Err(FrontmatterError::new(
+                format!("unclosed frontmatter; expected `{fence_pattern}`"),
+                raw.len()..raw.len(),
+            )
+            .push_visible_span(open_start..open_end));
+        };
+        let frontmatter_start = input.current_token_start() + 1; // skip nl from infostring
+        let _ = input.next_slice(frontmatter_nl.start + 1);
+        let frontmatter_end = input.current_token_start();
+        source.frontmatter = Some(frontmatter_start..frontmatter_end);
+        let close_start = input.current_token_start();
+        let _ = input.next_slice(fence_length);
+        let close_end = input.current_token_start();
+        source.close = Some(close_start..close_end);
+
+        let nl = input.find_slice("\n");
+        let after_closing_fence =
+            input.next_slice(nl.map(|span| span.end).unwrap_or_else(|| input.eof_offset()));
+        let content_start = input.current_token_start();
+        let extra_dashes = after_closing_fence.chars().take_while(|b| *b == FENCE_CHAR).count();
+        if 0 < extra_dashes {
+            let extra_start = close_end;
+            let extra_end = extra_start + extra_dashes;
+            return Err(FrontmatterError::new(
+                format!("closing code fence has {extra_dashes} more `-` than the opening fence"),
+                extra_start..extra_end,
+            )
+            .push_visible_span(open_start..open_end));
+        } else {
+            let after_closing_fence = strip_newline(after_closing_fence);
+            let after_closing_fence = after_closing_fence.trim_matches(is_horizontal_whitespace);
+            if !after_closing_fence.is_empty() {
+                // extra characters beyond the original fence pattern
+                let after_start = after_closing_fence.offset_from(&raw);
+                let after_end = after_start + after_closing_fence.len();
+                return Err(FrontmatterError::new(
+                    format!("unexpected characters after frontmatter close"),
+                    after_start..after_end,
+                )
+                .push_visible_span(open_start..open_end));
+            }
+        }
+
+        source.content = content_start..content_end;
+
+        if let Some(nl_end) = strip_ws_lines(input.as_ref()) {
+            let _ = input.next_slice(nl_end);
+        }
+        let fence_length = input
+            .as_ref()
+            .char_indices()
+            .find_map(|(i, c)| (c != FENCE_CHAR).then_some(i))
+            .unwrap_or_else(|| input.eof_offset());
+        if 0 < fence_length {
+            let fence_start = input.current_token_start();
+            let fence_end = fence_start + fence_length;
+            return Err(FrontmatterError::new(
+                format!("only one frontmatter is supported"),
+                fence_start..fence_end,
+            )
+            .push_visible_span(open_start..open_end)
+            .push_visible_span(close_start..close_end));
+        }
+
+        Ok(source)
+    }
+
+    pub fn shebang(&self) -> Option<&'s str> {
+        self.shebang.clone().map(|span| &self.raw[span])
+    }
+
+    pub fn shebang_span(&self) -> Option<Span> {
+        self.shebang.clone()
+    }
+
+    pub fn open_span(&self) -> Option<Span> {
+        self.open.clone()
+    }
+
+    pub fn info(&self) -> Option<&'s str> {
+        self.info.clone().map(|span| &self.raw[span])
+    }
+
+    pub fn info_span(&self) -> Option<Span> {
+        self.info.clone()
+    }
+
+    pub fn frontmatter(&self) -> Option<&'s str> {
+        self.frontmatter.clone().map(|span| &self.raw[span])
+    }
+
+    pub fn frontmatter_span(&self) -> Option<Span> {
+        self.frontmatter.clone()
+    }
+
+    pub fn close_span(&self) -> Option<Span> {
+        self.close.clone()
+    }
+
+    pub fn content(&self) -> &'s str {
+        &self.raw[self.content.clone()]
+    }
+
+    pub fn content_span(&self) -> Span {
+        self.content.clone()
+    }
+}
+
+/// Returns the index after the shebang line, if present
+pub fn strip_shebang(input: &str) -> Option<usize> {
+    // See rust-lang/rust's compiler/rustc_lexer/src/lib.rs's `strip_shebang`
+    // Shebang must start with `#!` literally, without any preceding whitespace.
+    // For simplicity we consider any line starting with `#!` a shebang,
+    // regardless of restrictions put on shebangs by specific platforms.
+    if let Some(rest) = input.strip_prefix("#!") {
+        // Ok, this is a shebang but if the next non-whitespace token is `[`,
+        // then it may be valid Rust code, so consider it Rust code.
+        //
+        // NOTE: rustc considers line and block comments to be whitespace but to avoid
+        // any more awareness of Rust grammar, we are excluding it.
+        if !rest.trim_start().starts_with('[') {
+            // No other choice than to consider this a shebang.
+            let newline_end = input.find('\n').map(|pos| pos + 1).unwrap_or(input.len());
+            return Some(newline_end);
+        }
+    }
+    None
+}
+
+/// Returns the index after any lines with only whitespace, if present
+pub fn strip_ws_lines(input: &str) -> Option<usize> {
+    let ws_end = input.find(|c| !is_whitespace(c)).unwrap_or(input.len());
+    if ws_end == 0 {
+        return None;
+    }
+
+    let nl_start = input[0..ws_end].rfind('\n')?;
+    let nl_end = nl_start + 1;
+    Some(nl_end)
+}
+
+/// True if `c` is considered a whitespace according to Rust language definition.
+/// See [Rust language reference](https://doc.rust-lang.org/reference/whitespace.html)
+/// for definitions of these classes.
+fn is_whitespace(c: char) -> bool {
+    // This is Pattern_White_Space.
+    //
+    // Note that this set is stable (ie, it doesn't change with different
+    // Unicode versions), so it's ok to just hard-code the values.
+
+    matches!(
+        c,
+        // End-of-line characters
+        | '\u{000A}' // line feed (\n)
+        | '\u{000B}' // vertical tab
+        | '\u{000C}' // form feed
+        | '\u{000D}' // carriage return (\r)
+        | '\u{0085}' // next line (from latin1)
+        | '\u{2028}' // LINE SEPARATOR
+        | '\u{2029}' // PARAGRAPH SEPARATOR
+
+        // `Default_Ignorable_Code_Point` characters
+        | '\u{200E}' // LEFT-TO-RIGHT MARK
+        | '\u{200F}' // RIGHT-TO-LEFT MARK
+
+        // Horizontal space characters
+        | '\u{0009}'   // tab (\t)
+        | '\u{0020}' // space
+    )
+}
+
+/// True if `c` is considered horizontal whitespace according to Rust language definition.
+fn is_horizontal_whitespace(c: char) -> bool {
+    // This is Pattern_White_Space.
+    //
+    // Note that this set is stable (ie, it doesn't change with different
+    // Unicode versions), so it's ok to just hard-code the values.
+
+    matches!(
+        c,
+        // Horizontal space characters
+        '\u{0009}'   // tab (\t)
+        | '\u{0020}' // space
+    )
+}
+
+fn strip_newline(text: &str) -> &str {
+    text.strip_suffix("\r\n").or_else(|| text.strip_suffix('\n')).unwrap_or(text)
+}
+
+#[derive(Debug)]
+pub struct FrontmatterError {
+    message: String,
+    primary_span: Span,
+    visible_spans: Vec<Span>,
+}
+
+impl FrontmatterError {
+    pub fn new(message: impl Into<String>, span: Span) -> Self {
+        Self { message: message.into(), primary_span: span, visible_spans: Vec::new() }
+    }
+
+    pub fn push_visible_span(mut self, span: Span) -> Self {
+        self.visible_spans.push(span);
+        self
+    }
+
+    pub fn message(&self) -> &str {
+        self.message.as_str()
+    }
+
+    pub fn primary_span(&self) -> Span {
+        self.primary_span.clone()
+    }
+
+    pub fn visible_spans(&self) -> &[Span] {
+        &self.visible_spans
+    }
+}
+
+impl std::fmt::Display for FrontmatterError {
+    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        self.message.fmt(fmt)
+    }
+}
+
+impl std::error::Error for FrontmatterError {}
diff --git a/crates/parser/src/grammar/expressions.rs b/crates/parser/src/grammar/expressions.rs
index 41fd72d..76d26c1 100644
--- a/crates/parser/src/grammar/expressions.rs
+++ b/crates/parser/src/grammar/expressions.rs
@@ -430,6 +430,11 @@
             // }
             T!['('] if allow_calls => call_expr(p, lhs),
             T!['['] if allow_calls => index_expr(p, lhs),
+            // test_err postfix_dot_expr_ambiguity
+            // fn foo() {
+            //     x.
+            //     ()
+            // }
             T![.] => match postfix_dot_expr::<false>(p, lhs) {
                 Ok(it) => it,
                 Err(it) => {
@@ -458,6 +463,7 @@
 
     if PATH_NAME_REF_KINDS.contains(p.nth(nth1))
         && (p.nth(nth2) == T!['('] || p.nth_at(nth2, T![::]))
+        || p.nth(nth1) == T!['(']
     {
         return Ok(method_call_expr::<FLOAT_RECOVERY>(p, lhs));
     }
@@ -526,19 +532,26 @@
     lhs: CompletedMarker,
 ) -> CompletedMarker {
     if FLOAT_RECOVERY {
-        assert!(p.at_ts(PATH_NAME_REF_KINDS) && (p.nth(1) == T!['('] || p.nth_at(1, T![::])));
-    } else {
         assert!(
-            p.at(T![.])
-                && PATH_NAME_REF_KINDS.contains(p.nth(1))
-                && (p.nth(2) == T!['('] || p.nth_at(2, T![::]))
+            p.at_ts(PATH_NAME_REF_KINDS) && (p.nth(1) == T!['('] || p.nth_at(1, T![::]))
+                || p.current() == T!['(']
+        );
+    } else {
+        assert!(p.at(T![.]));
+        assert!(
+            PATH_NAME_REF_KINDS.contains(p.nth(1)) && (p.nth(2) == T!['('] || p.nth_at(2, T![::]))
+                || p.nth(1) == T!['(']
         );
     }
     let m = lhs.precede(p);
     if !FLOAT_RECOVERY {
         p.bump(T![.]);
     }
-    name_ref_mod_path(p);
+    if p.at_ts(PATH_NAME_REF_KINDS) {
+        name_ref_mod_path(p);
+    } else {
+        p.error("expected method name, field name or number");
+    }
     generic_args::opt_generic_arg_list_expr(p);
     if p.at(T!['(']) {
         arg_list(p);
diff --git a/crates/parser/src/lexed_str.rs b/crates/parser/src/lexed_str.rs
index edc3f40..7c78ba8 100644
--- a/crates/parser/src/lexed_str.rs
+++ b/crates/parser/src/lexed_str.rs
@@ -37,10 +37,17 @@
     pub fn new(edition: Edition, text: &'a str) -> LexedStr<'a> {
         let _p = tracing::info_span!("LexedStr::new").entered();
         let mut conv = Converter::new(edition, text);
-        if let Some(shebang_len) = rustc_lexer::strip_shebang(text) {
-            conv.res.push(SHEBANG, conv.offset);
-            conv.offset = shebang_len;
-        };
+        if let Ok(script) = crate::frontmatter::ScriptSource::parse(text) {
+            if let Some(shebang) = script.shebang_span() {
+                conv.push(SHEBANG, shebang.end - shebang.start, Vec::new());
+            }
+            if script.frontmatter().is_some() {
+                conv.push(FRONTMATTER, script.content_span().start - conv.offset, Vec::new());
+            }
+        } else if let Some(shebang_len) = rustc_lexer::strip_shebang(text) {
+            // Leave error reporting to `rustc_lexer`
+            conv.push(SHEBANG, shebang_len, Vec::new());
+        }
 
         // Re-create the tokenizer from scratch every token because `GuardedStrPrefix` is one token in the lexer
         // but we want to split it to two in edition <2024.
diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs
index 7963f00..53444ef 100644
--- a/crates/parser/src/lib.rs
+++ b/crates/parser/src/lib.rs
@@ -26,6 +26,7 @@
 extern crate rustc_lexer;
 
 mod event;
+mod frontmatter;
 mod grammar;
 mod input;
 mod lexed_str;
diff --git a/crates/parser/test_data/generated/runner.rs b/crates/parser/test_data/generated/runner.rs
index cd6d433..9bdbe56 100644
--- a/crates/parser/test_data/generated/runner.rs
+++ b/crates/parser/test_data/generated/runner.rs
@@ -844,6 +844,10 @@
         run_and_expect_errors("test_data/parser/inline/err/pointer_type_no_mutability.rs");
     }
     #[test]
+    fn postfix_dot_expr_ambiguity() {
+        run_and_expect_errors("test_data/parser/inline/err/postfix_dot_expr_ambiguity.rs");
+    }
+    #[test]
     fn precise_capturing_invalid() {
         run_and_expect_errors("test_data/parser/inline/err/precise_capturing_invalid.rs");
     }
diff --git a/crates/parser/test_data/lexer/ok/frontmatter.rast b/crates/parser/test_data/lexer/ok/frontmatter.rast
new file mode 100644
index 0000000..2c7d3cd
--- /dev/null
+++ b/crates/parser/test_data/lexer/ok/frontmatter.rast
@@ -0,0 +1,12 @@
+FRONTMATTER "\n---\n[dependencies]\nclap = \"4\"\n---\n"
+WHITESPACE "\n"
+FN_KW "fn"
+WHITESPACE " "
+IDENT "main"
+L_PAREN "("
+R_PAREN ")"
+WHITESPACE " "
+L_CURLY "{"
+WHITESPACE "\n"
+R_CURLY "}"
+WHITESPACE "\n"
diff --git a/crates/parser/test_data/lexer/ok/frontmatter.rs b/crates/parser/test_data/lexer/ok/frontmatter.rs
new file mode 100644
index 0000000..be7bf74
--- /dev/null
+++ b/crates/parser/test_data/lexer/ok/frontmatter.rs
@@ -0,0 +1,8 @@
+
+---
+[dependencies]
+clap = "4"
+---
+
+fn main() {
+}
diff --git a/crates/parser/test_data/lexer/ok/shebang_frontmatter.rast b/crates/parser/test_data/lexer/ok/shebang_frontmatter.rast
new file mode 100644
index 0000000..fb4787f
--- /dev/null
+++ b/crates/parser/test_data/lexer/ok/shebang_frontmatter.rast
@@ -0,0 +1,13 @@
+SHEBANG "#!/usr/bin/env cargo\n"
+FRONTMATTER "\n---\n[dependencies]\nclap = \"4\"\n---\n"
+WHITESPACE "\n"
+FN_KW "fn"
+WHITESPACE " "
+IDENT "main"
+L_PAREN "("
+R_PAREN ")"
+WHITESPACE " "
+L_CURLY "{"
+WHITESPACE "\n"
+R_CURLY "}"
+WHITESPACE "\n"
diff --git a/crates/parser/test_data/lexer/ok/shebang_frontmatter.rs b/crates/parser/test_data/lexer/ok/shebang_frontmatter.rs
new file mode 100644
index 0000000..090b771
--- /dev/null
+++ b/crates/parser/test_data/lexer/ok/shebang_frontmatter.rs
@@ -0,0 +1,9 @@
+#!/usr/bin/env cargo
+
+---
+[dependencies]
+clap = "4"
+---
+
+fn main() {
+}
diff --git a/crates/parser/test_data/lexer/ok/single_line_comments.rast b/crates/parser/test_data/lexer/ok/single_line_comments.rast
index a7681e9..c4e531b 100644
--- a/crates/parser/test_data/lexer/ok/single_line_comments.rast
+++ b/crates/parser/test_data/lexer/ok/single_line_comments.rast
@@ -1,5 +1,4 @@
-SHEBANG "#!/usr/bin/env bash"
-WHITESPACE "\n"
+SHEBANG "#!/usr/bin/env bash\n"
 COMMENT "// hello"
 WHITESPACE "\n"
 COMMENT "//! World"
diff --git a/crates/parser/test_data/parser/err/0002_duplicate_shebang.rast b/crates/parser/test_data/parser/err/0002_duplicate_shebang.rast
index 3159a15..7ee1ecf 100644
--- a/crates/parser/test_data/parser/err/0002_duplicate_shebang.rast
+++ b/crates/parser/test_data/parser/err/0002_duplicate_shebang.rast
@@ -1,6 +1,5 @@
 SOURCE_FILE
-  SHEBANG "#!/use/bin/env rusti"
-  WHITESPACE "\n"
+  SHEBANG "#!/use/bin/env rusti\n"
   ATTR
     POUND "#"
     BANG "!"
diff --git a/crates/parser/test_data/parser/inline/err/postfix_dot_expr_ambiguity.rast b/crates/parser/test_data/parser/inline/err/postfix_dot_expr_ambiguity.rast
new file mode 100644
index 0000000..4ee318d
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/err/postfix_dot_expr_ambiguity.rast
@@ -0,0 +1,29 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "foo"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        WHITESPACE "\n    "
+        METHOD_CALL_EXPR
+          PATH_EXPR
+            PATH
+              PATH_SEGMENT
+                NAME_REF
+                  IDENT "x"
+          DOT "."
+          WHITESPACE "\n    "
+          ARG_LIST
+            L_PAREN "("
+            R_PAREN ")"
+        WHITESPACE "\n"
+        R_CURLY "}"
+  WHITESPACE "\n"
+error 17: expected method name, field name or number
diff --git a/crates/parser/test_data/parser/inline/err/postfix_dot_expr_ambiguity.rs b/crates/parser/test_data/parser/inline/err/postfix_dot_expr_ambiguity.rs
new file mode 100644
index 0000000..c1aed30
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/err/postfix_dot_expr_ambiguity.rs
@@ -0,0 +1,4 @@
+fn foo() {
+    x.
+    ()
+}
diff --git a/crates/project-model/src/build_dependencies.rs b/crates/project-model/src/build_dependencies.rs
index 5eda5af..3a682d5 100644
--- a/crates/project-model/src/build_dependencies.rs
+++ b/crates/project-model/src/build_dependencies.rs
@@ -142,7 +142,7 @@
                 if let Some(&(package, workspace)) = by_id.get(package) {
                     cb(&workspaces[workspace][package].name, &mut res[workspace].outputs[package]);
                 } else {
-                    never!("Received compiler message for unknown package: {}", package);
+                    tracing::error!("Received compiler message for unknown package: {}", package);
                 }
             },
             progress,
diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs
index 04fb227..76ba01f 100644
--- a/crates/project-model/src/cargo_workspace.rs
+++ b/crates/project-model/src/cargo_workspace.rs
@@ -49,8 +49,9 @@
     is_virtual_workspace: bool,
     /// Whether this workspace represents the sysroot workspace.
     is_sysroot: bool,
-    /// Environment variables set in the `.cargo/config` file.
-    config_env: Env,
+    /// Environment variables set in the `.cargo/config` file and the extraEnv
+    /// configuration option.
+    env: Env,
     requires_rustc_private: bool,
 }
 
@@ -325,7 +326,7 @@
     pub fn new(
         mut meta: cargo_metadata::Metadata,
         ws_manifest_path: ManifestPath,
-        cargo_config_env: Env,
+        cargo_env: Env,
         is_sysroot: bool,
     ) -> CargoWorkspace {
         let mut pkg_by_id = FxHashMap::default();
@@ -498,7 +499,7 @@
             is_virtual_workspace,
             requires_rustc_private,
             is_sysroot,
-            config_env: cargo_config_env,
+            env: cargo_env,
         }
     }
 
@@ -589,7 +590,7 @@
     }
 
     pub fn env(&self) -> &Env {
-        &self.config_env
+        &self.env
     }
 
     pub fn is_sysroot(&self) -> bool {
diff --git a/crates/project-model/src/env.rs b/crates/project-model/src/env.rs
index d281492..ae0458a 100644
--- a/crates/project-model/src/env.rs
+++ b/crates/project-model/src/env.rs
@@ -1,6 +1,7 @@
 //! Cargo-like environment variables injection.
 use base_db::Env;
 use paths::Utf8Path;
+use rustc_hash::FxHashMap;
 use toolchain::Tool;
 
 use crate::{ManifestPath, PackageData, TargetKind, cargo_config_file::CargoConfigFile};
@@ -60,8 +61,14 @@
     env.set("CARGO_CRATE_NAME", cargo_name.replace('-', "_"));
 }
 
-pub(crate) fn cargo_config_env(manifest: &ManifestPath, config: &Option<CargoConfigFile>) -> Env {
+pub(crate) fn cargo_config_env(
+    manifest: &ManifestPath,
+    config: &Option<CargoConfigFile>,
+    extra_env: &FxHashMap<String, Option<String>>,
+) -> Env {
     let mut env = Env::default();
+    env.extend(extra_env.iter().filter_map(|(k, v)| v.as_ref().map(|v| (k.clone(), v.clone()))));
+
     let Some(serde_json::Value::Object(env_json)) = config.as_ref().and_then(|c| c.get("env"))
     else {
         return env;
@@ -72,22 +79,34 @@
     let base = <_ as AsRef<Utf8Path>>::as_ref(manifest.parent());
 
     for (key, entry) in env_json {
-        let serde_json::Value::Object(entry) = entry else {
-            continue;
-        };
-        let Some(value) = entry.get("value").and_then(|v| v.as_str()) else {
-            continue;
+        let value = match entry {
+            serde_json::Value::String(s) => s.clone(),
+            serde_json::Value::Object(entry) => {
+                // Each entry MUST have a `value` key.
+                let Some(value) = entry.get("value").and_then(|v| v.as_str()) else {
+                    continue;
+                };
+                // If the entry already exists in the environment AND the `force` key is not set to
+                // true, then don't overwrite the value.
+                if extra_env.get(key).is_some_and(Option::is_some)
+                    && !entry.get("force").and_then(|v| v.as_bool()).unwrap_or(false)
+                {
+                    continue;
+                }
+
+                if entry
+                    .get("relative")
+                    .and_then(|v| v.as_bool())
+                    .is_some_and(std::convert::identity)
+                {
+                    base.join(value).to_string()
+                } else {
+                    value.to_owned()
+                }
+            }
+            _ => continue,
         };
 
-        let value = if entry
-            .get("relative")
-            .and_then(|v| v.as_bool())
-            .is_some_and(std::convert::identity)
-        {
-            base.join(value).to_string()
-        } else {
-            value.to_owned()
-        };
         env.insert(key, value);
     }
 
@@ -113,7 +132,19 @@
     },
     "TEST": {
       "value": "test"
-    }
+    },
+    "FORCED": {
+      "value": "test",
+      "force": true
+    },
+    "UNFORCED": {
+      "value": "test",
+      "force": false
+    },
+    "OVERWRITTEN": {
+      "value": "test"
+    },
+    "NOT_AN_OBJECT": "value"
   }
 }
 "#;
@@ -121,9 +152,22 @@
     let cwd = paths::Utf8PathBuf::try_from(std::env::current_dir().unwrap()).unwrap();
     let manifest = paths::AbsPathBuf::assert(cwd.join("Cargo.toml"));
     let manifest = ManifestPath::try_from(manifest).unwrap();
-    let env = cargo_config_env(&manifest, &Some(config));
+    let extra_env = [
+        ("FORCED", Some("ignored")),
+        ("UNFORCED", Some("newvalue")),
+        ("OVERWRITTEN", Some("newvalue")),
+        ("TEST", None),
+    ]
+    .iter()
+    .map(|(k, v)| (k.to_string(), v.map(ToString::to_string)))
+    .collect();
+    let env = cargo_config_env(&manifest, &Some(config), &extra_env);
     assert_eq!(env.get("CARGO_WORKSPACE_DIR").as_deref(), Some(cwd.join("").as_str()));
     assert_eq!(env.get("RELATIVE").as_deref(), Some(cwd.join("../relative").as_str()));
     assert_eq!(env.get("INVALID").as_deref(), Some("../relative"));
     assert_eq!(env.get("TEST").as_deref(), Some("test"));
+    assert_eq!(env.get("FORCED").as_deref(), Some("test"));
+    assert_eq!(env.get("UNFORCED").as_deref(), Some("newvalue"));
+    assert_eq!(env.get("OVERWRITTEN").as_deref(), Some("newvalue"));
+    assert_eq!(env.get("NOT_AN_OBJECT").as_deref(), Some("value"));
 }
diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs
index c0a5009..5cc399b 100644
--- a/crates/project-model/src/sysroot.rs
+++ b/crates/project-model/src/sysroot.rs
@@ -30,7 +30,7 @@
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub enum RustLibSrcWorkspace {
-    Workspace(CargoWorkspace),
+    Workspace { ws: CargoWorkspace, metadata_err: Option<String> },
     Json(ProjectJson),
     Stitched(stitched::Stitched),
     Empty,
@@ -39,7 +39,9 @@
 impl fmt::Display for RustLibSrcWorkspace {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
-            RustLibSrcWorkspace::Workspace(ws) => write!(f, "workspace {}", ws.workspace_root()),
+            RustLibSrcWorkspace::Workspace { ws, .. } => {
+                write!(f, "workspace {}", ws.workspace_root())
+            }
             RustLibSrcWorkspace::Json(json) => write!(f, "json {}", json.manifest_or_root()),
             RustLibSrcWorkspace::Stitched(stitched) => {
                 write!(f, "stitched with {} crates", stitched.crates.len())
@@ -74,7 +76,7 @@
 
     pub fn is_rust_lib_src_empty(&self) -> bool {
         match &self.workspace {
-            RustLibSrcWorkspace::Workspace(ws) => ws.packages().next().is_none(),
+            RustLibSrcWorkspace::Workspace { ws, .. } => ws.packages().next().is_none(),
             RustLibSrcWorkspace::Json(project_json) => project_json.n_crates() == 0,
             RustLibSrcWorkspace::Stitched(stitched) => stitched.crates.is_empty(),
             RustLibSrcWorkspace::Empty => true,
@@ -85,9 +87,16 @@
         self.error.as_deref()
     }
 
+    pub fn metadata_error(&self) -> Option<&str> {
+        match &self.workspace {
+            RustLibSrcWorkspace::Workspace { metadata_err, .. } => metadata_err.as_deref(),
+            _ => None,
+        }
+    }
+
     pub fn num_packages(&self) -> usize {
         match &self.workspace {
-            RustLibSrcWorkspace::Workspace(ws) => ws.packages().count(),
+            RustLibSrcWorkspace::Workspace { ws, .. } => ws.packages().count(),
             RustLibSrcWorkspace::Json(project_json) => project_json.n_crates(),
             RustLibSrcWorkspace::Stitched(stitched) => stitched.crates.len(),
             RustLibSrcWorkspace::Empty => 0,
@@ -210,7 +219,6 @@
         &self,
         sysroot_source_config: &RustSourceWorkspaceConfig,
         no_deps: bool,
-        current_dir: &AbsPath,
         target_dir: &Utf8Path,
         progress: &dyn Fn(String),
     ) -> Option<RustLibSrcWorkspace> {
@@ -224,7 +232,7 @@
             if fs::metadata(&library_manifest).is_ok() {
                 match self.load_library_via_cargo(
                     &library_manifest,
-                    current_dir,
+                    src_root,
                     target_dir,
                     cargo_config,
                     no_deps,
@@ -294,7 +302,9 @@
             && let Some(src_root) = &self.rust_lib_src_root
         {
             let has_core = match &self.workspace {
-                RustLibSrcWorkspace::Workspace(ws) => ws.packages().any(|p| ws[p].name == "core"),
+                RustLibSrcWorkspace::Workspace { ws: workspace, .. } => {
+                    workspace.packages().any(|p| workspace[p].name == "core")
+                }
                 RustLibSrcWorkspace::Json(project_json) => project_json
                     .crates()
                     .filter_map(|(_, krate)| krate.display_name.clone())
@@ -333,7 +343,7 @@
 
         // Make sure we never attempt to write to the sysroot
         let locked = true;
-        let (mut res, _) =
+        let (mut res, err) =
             FetchMetadata::new(library_manifest, current_dir, &cargo_config, self, no_deps)
                 .exec(target_dir, locked, progress)?;
 
@@ -388,7 +398,10 @@
 
         let cargo_workspace =
             CargoWorkspace::new(res, library_manifest.clone(), Default::default(), true);
-        Ok(RustLibSrcWorkspace::Workspace(cargo_workspace))
+        Ok(RustLibSrcWorkspace::Workspace {
+            ws: cargo_workspace,
+            metadata_err: err.map(|e| format!("{e:#}")),
+        })
     }
 }
 
diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs
index 987d381..711cdd1 100644
--- a/crates/project-model/src/tests.rs
+++ b/crates/project-model/src/tests.rs
@@ -241,7 +241,6 @@
     let loaded_sysroot = sysroot.load_workspace(
         &RustSourceWorkspaceConfig::default_cargo(),
         false,
-        &cwd,
         &Utf8PathBuf::default(),
         &|_| (),
     );
@@ -249,7 +248,7 @@
         sysroot.set_workspace(loaded_sysroot);
     }
     assert!(
-        matches!(sysroot.workspace(), RustLibSrcWorkspace::Workspace(_)),
+        matches!(sysroot.workspace(), RustLibSrcWorkspace::Workspace { .. }),
         "got {}",
         sysroot.workspace()
     );
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index 0649ce9..b88db41 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -383,41 +383,40 @@
                         toolchain.clone(),
                     )),
                     config.no_deps,
-                    workspace_dir,
                     &target_dir,
                     progress,
                 )
             });
-            let cargo_config_extra_env =
-                s.spawn(move || cargo_config_env(cargo_toml, &config_file));
+            let cargo_env =
+                s.spawn(move || cargo_config_env(cargo_toml, &config_file, &config.extra_env));
             thread::Result::Ok((
                 rustc_cfg.join()?,
                 target_data.join()?,
                 rustc_dir.join()?,
                 loaded_sysroot.join()?,
                 cargo_metadata.join()?,
-                cargo_config_extra_env.join()?,
+                cargo_env.join()?,
             ))
         });
 
-        let (
-            rustc_cfg,
-            data_layout,
-            mut rustc,
-            loaded_sysroot,
-            cargo_metadata,
-            cargo_config_extra_env,
-        ) = match join {
-            Ok(it) => it,
-            Err(e) => std::panic::resume_unwind(e),
-        };
+        let (rustc_cfg, data_layout, mut rustc, loaded_sysroot, cargo_metadata, mut cargo_env) =
+            match join {
+                Ok(it) => it,
+                Err(e) => std::panic::resume_unwind(e),
+            };
+
+        for (key, value) in config.extra_env.iter() {
+            if let Some(value) = value {
+                cargo_env.insert(key.clone(), value.clone());
+            }
+        }
 
         let (meta, error) = cargo_metadata.with_context(|| {
             format!(
                 "Failed to read Cargo metadata from Cargo.toml file {cargo_toml}, {toolchain:?}",
             )
         })?;
-        let cargo = CargoWorkspace::new(meta, cargo_toml.clone(), cargo_config_extra_env, false);
+        let cargo = CargoWorkspace::new(meta, cargo_toml.clone(), cargo_env, false);
         if let Some(loaded_sysroot) = loaded_sysroot {
             tracing::info!(src_root = ?sysroot.rust_lib_src_root(), root = %loaded_sysroot, "Loaded sysroot");
             sysroot.set_workspace(loaded_sysroot);
@@ -487,7 +486,6 @@
                     sysroot.load_workspace(
                         &RustSourceWorkspaceConfig::Json(*sysroot_project),
                         config.no_deps,
-                        project_root,
                         &target_dir,
                         progress,
                     )
@@ -499,7 +497,6 @@
                             toolchain.clone(),
                         )),
                         config.no_deps,
-                        project_root,
                         &target_dir,
                         progress,
                     )
@@ -561,7 +558,6 @@
                 toolchain.clone(),
             )),
             config.no_deps,
-            dir,
             &target_dir,
             &|_| (),
         );
@@ -590,7 +586,8 @@
             .unwrap_or_else(|| dir.join("target").into());
         let cargo_script =
             fetch_metadata.exec(&target_dir, false, &|_| ()).ok().map(|(ws, error)| {
-                let cargo_config_extra_env = cargo_config_env(detached_file, &config_file);
+                let cargo_config_extra_env =
+                    cargo_config_env(detached_file, &config_file, &config.extra_env);
                 (
                     CargoWorkspace::new(ws, detached_file.clone(), cargo_config_extra_env, false),
                     WorkspaceBuildScripts::default(),
@@ -747,7 +744,7 @@
     pub fn to_roots(&self) -> Vec<PackageRoot> {
         let mk_sysroot = || {
             let mut r = match self.sysroot.workspace() {
-                RustLibSrcWorkspace::Workspace(ws) => ws
+                RustLibSrcWorkspace::Workspace { ws, .. } => ws
                     .packages()
                     .filter_map(|pkg| {
                         if ws[pkg].is_local {
@@ -1093,7 +1090,13 @@
                 },
                 file_id,
             )| {
-                let env = env.clone().into_iter().collect();
+                let mut env = env.clone().into_iter().collect::<Env>();
+                // Override existing env vars with those from `extra_env`
+                env.extend(
+                    extra_env
+                        .iter()
+                        .filter_map(|(k, v)| v.as_ref().map(|v| (k.clone(), v.clone()))),
+                );
 
                 let target_cfgs = match target.as_deref() {
                     Some(target) => cfg_cache.entry(target).or_insert_with(|| {
@@ -1735,7 +1738,7 @@
 ) -> (SysrootPublicDeps, Option<CrateBuilderId>) {
     let _p = tracing::info_span!("sysroot_to_crate_graph").entered();
     match sysroot.workspace() {
-        RustLibSrcWorkspace::Workspace(cargo) => {
+        RustLibSrcWorkspace::Workspace { ws: cargo, .. } => {
             let (sysroot_cg, sysroot_pm) = cargo_to_crate_graph(
                 load,
                 None,
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index 2a9ef98..de24bc0 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -25,7 +25,7 @@
     InlayHintsConfig, LineCol, RootDatabase,
 };
 use ide_db::{
-    EditionedFileId, LineIndexDatabase, SnippetCap,
+    EditionedFileId, LineIndexDatabase, MiniCore, SnippetCap,
     base_db::{SourceDatabase, salsa::Database},
 };
 use itertools::Itertools;
@@ -345,6 +345,8 @@
             self.run_term_search(&workspace, db, &vfs, &file_ids, verbosity);
         }
 
+        hir::clear_tls_solver_cache();
+
         let db = host.raw_database_mut();
         db.trigger_lru_eviction();
 
@@ -1194,6 +1196,7 @@
                     closing_brace_hints_min_lines: Some(20),
                     fields_to_resolve: InlayFieldsToResolve::empty(),
                     range_exclusive_hints: true,
+                    minicore: MiniCore::default(),
                 },
                 analysis.editioned_file_id_to_vfs(file_id),
                 None,
@@ -1203,26 +1206,25 @@
         bar.finish_and_clear();
 
         let mut bar = create_bar();
+        let annotation_config = AnnotationConfig {
+            binary_target: true,
+            annotate_runnables: true,
+            annotate_impls: true,
+            annotate_references: false,
+            annotate_method_references: false,
+            annotate_enum_variant_references: false,
+            location: ide::AnnotationLocation::AboveName,
+            minicore: MiniCore::default(),
+        };
         for &file_id in file_ids {
             let msg = format!("annotations: {}", vfs.file_path(file_id.file_id(db)));
             bar.set_message(move || msg.clone());
             analysis
-                .annotations(
-                    &AnnotationConfig {
-                        binary_target: true,
-                        annotate_runnables: true,
-                        annotate_impls: true,
-                        annotate_references: false,
-                        annotate_method_references: false,
-                        annotate_enum_variant_references: false,
-                        location: ide::AnnotationLocation::AboveName,
-                    },
-                    analysis.editioned_file_id_to_vfs(file_id),
-                )
+                .annotations(&annotation_config, analysis.editioned_file_id_to_vfs(file_id))
                 .unwrap()
                 .into_iter()
                 .for_each(|annotation| {
-                    _ = analysis.resolve_annotation(annotation);
+                    _ = analysis.resolve_annotation(&annotation_config, annotation);
                 });
             bar.inc(1);
         }
diff --git a/crates/rust-analyzer/src/cli/rustc_tests.rs b/crates/rust-analyzer/src/cli/rustc_tests.rs
index 609ebf2..2056714 100644
--- a/crates/rust-analyzer/src/cli/rustc_tests.rs
+++ b/crates/rust-analyzer/src/cli/rustc_tests.rs
@@ -78,7 +78,6 @@
         let loaded_sysroot = sysroot.load_workspace(
             &RustSourceWorkspaceConfig::default_cargo(),
             false,
-            &path,
             &Utf8PathBuf::default(),
             &|_| (),
         );
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 96b6583..652c2e3 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -8,14 +8,14 @@
 use cfg::{CfgAtom, CfgDiff};
 use hir::Symbol;
 use ide::{
-    AssistConfig, CallHierarchyConfig, CallableSnippets, CompletionConfig,
-    CompletionFieldsToResolve, DiagnosticsConfig, GenericParameterHints, HighlightConfig,
-    HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve, InlayHintsConfig,
-    JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, Snippet, SnippetScope,
-    SourceRootId,
+    AnnotationConfig, AssistConfig, CallHierarchyConfig, CallableSnippets, CompletionConfig,
+    CompletionFieldsToResolve, DiagnosticsConfig, GenericParameterHints, GotoDefinitionConfig,
+    HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve,
+    InlayHintsConfig, JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind,
+    Snippet, SnippetScope, SourceRootId,
 };
 use ide_db::{
-    SnippetCap,
+    MiniCore, SnippetCap,
     assists::ExprFillDefaultMode,
     imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
 };
@@ -1454,6 +1454,23 @@
     pub fn references(&self) -> bool {
         self.method_refs || self.refs_adt || self.refs_trait || self.enum_variant_refs
     }
+
+    pub fn into_annotation_config<'a>(
+        self,
+        binary_target: bool,
+        minicore: MiniCore<'a>,
+    ) -> AnnotationConfig<'a> {
+        AnnotationConfig {
+            binary_target,
+            annotate_runnables: self.runnable(),
+            annotate_impls: self.implementations,
+            annotate_references: self.refs_adt,
+            annotate_method_references: self.method_refs,
+            annotate_enum_variant_references: self.enum_variant_refs,
+            location: self.location.into(),
+            minicore,
+        }
+    }
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]
@@ -1688,11 +1705,15 @@
         }
     }
 
-    pub fn call_hierarchy(&self) -> CallHierarchyConfig {
-        CallHierarchyConfig { exclude_tests: self.references_excludeTests().to_owned() }
+    pub fn call_hierarchy<'a>(&self, minicore: MiniCore<'a>) -> CallHierarchyConfig<'a> {
+        CallHierarchyConfig { exclude_tests: self.references_excludeTests().to_owned(), minicore }
     }
 
-    pub fn completion(&self, source_root: Option<SourceRootId>) -> CompletionConfig<'_> {
+    pub fn completion<'a>(
+        &'a self,
+        source_root: Option<SourceRootId>,
+        minicore: MiniCore<'a>,
+    ) -> CompletionConfig<'a> {
         let client_capability_fields = self.completion_resolve_support_properties();
         CompletionConfig {
             enable_postfix_completions: self.completion_postfix_enable(source_root).to_owned(),
@@ -1746,6 +1767,7 @@
                 })
                 .collect(),
             exclude_traits: self.completion_excludeTraits(source_root),
+            minicore,
         }
     }
 
@@ -1820,7 +1842,7 @@
         }
     }
 
-    pub fn hover(&self) -> HoverConfig {
+    pub fn hover<'a>(&self, minicore: MiniCore<'a>) -> HoverConfig<'a> {
         let mem_kind = |kind| match kind {
             MemoryLayoutHoverRenderKindDef::Both => MemoryLayoutHoverRenderKind::Both,
             MemoryLayoutHoverRenderKindDef::Decimal => MemoryLayoutHoverRenderKind::Decimal,
@@ -1853,10 +1875,15 @@
                 None => ide::SubstTyLen::Unlimited,
             },
             show_drop_glue: *self.hover_dropGlue_enable(),
+            minicore,
         }
     }
 
-    pub fn inlay_hints(&self) -> InlayHintsConfig {
+    pub fn goto_definition<'a>(&self, minicore: MiniCore<'a>) -> GotoDefinitionConfig<'a> {
+        GotoDefinitionConfig { minicore }
+    }
+
+    pub fn inlay_hints<'a>(&self, minicore: MiniCore<'a>) -> InlayHintsConfig<'a> {
         let client_capability_fields = self.inlay_hint_resolve_support_properties();
 
         InlayHintsConfig {
@@ -1938,6 +1965,7 @@
             ),
             implicit_drop_hints: self.inlayHints_implicitDrops_enable().to_owned(),
             range_exclusive_hints: self.inlayHints_rangeExclusiveHints_enable().to_owned(),
+            minicore,
         }
     }
 
@@ -1975,7 +2003,7 @@
         self.semanticHighlighting_nonStandardTokens().to_owned()
     }
 
-    pub fn highlighting_config(&self) -> HighlightConfig {
+    pub fn highlighting_config<'a>(&self, minicore: MiniCore<'a>) -> HighlightConfig<'a> {
         HighlightConfig {
             strings: self.semanticHighlighting_strings_enable().to_owned(),
             comments: self.semanticHighlighting_comments_enable().to_owned(),
@@ -1990,6 +2018,7 @@
                 .to_owned(),
             inject_doc_comment: self.semanticHighlighting_doc_comment_inject_enable().to_owned(),
             syntactic_name_ref_highlighting: false,
+            minicore,
         }
     }
 
diff --git a/crates/rust-analyzer/src/flycheck.rs b/crates/rust-analyzer/src/flycheck.rs
index b545106..73a51bb 100644
--- a/crates/rust-analyzer/src/flycheck.rs
+++ b/crates/rust-analyzer/src/flycheck.rs
@@ -12,7 +12,7 @@
 use crossbeam_channel::{Receiver, Sender, select_biased, unbounded};
 use ide_db::FxHashSet;
 use itertools::Itertools;
-use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
+use paths::{AbsPath, AbsPathBuf, Utf8Path, Utf8PathBuf};
 use rustc_hash::FxHashMap;
 use serde::Deserialize as _;
 use serde_derive::Deserialize;
@@ -432,8 +432,10 @@
                                 options
                                     .target_dir
                                     .as_deref()
-                                    .unwrap_or("target".as_ref())
-                                    .join(format!("rust-analyzer/flycheck{}", self.id)),
+                                    .unwrap_or(
+                                        Utf8Path::new("target").join("rust-analyzer").as_path(),
+                                    )
+                                    .join(format!("flycheck{}", self.id)),
                             ),
                             _ => None,
                         },
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index ce6644f..f557dd5 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -13,7 +13,10 @@
 use crossbeam_channel::{Receiver, Sender, unbounded};
 use hir::ChangeWithProcMacros;
 use ide::{Analysis, AnalysisHost, Cancellable, FileId, SourceRootId};
-use ide_db::base_db::{Crate, ProcMacroPaths, SourceDatabase};
+use ide_db::{
+    MiniCore,
+    base_db::{Crate, ProcMacroPaths, SourceDatabase},
+};
 use itertools::Itertools;
 use load_cargo::SourceRootConfig;
 use lsp_types::{SemanticTokens, Url};
@@ -188,6 +191,14 @@
     /// This is marked true if we failed to load a crate root file at crate graph creation,
     /// which will usually end up causing a bunch of incorrect diagnostics on startup.
     pub(crate) incomplete_crate_graph: bool,
+
+    pub(crate) minicore: MiniCoreRustAnalyzerInternalOnly,
+}
+
+// FIXME: This should move to the VFS once the rewrite is done.
+#[derive(Debug, Clone, Default)]
+pub(crate) struct MiniCoreRustAnalyzerInternalOnly {
+    pub(crate) minicore_text: Option<String>,
 }
 
 /// An immutable snapshot of the world's state at a point in time.
@@ -204,6 +215,7 @@
     // FIXME: Can we derive this from somewhere else?
     pub(crate) proc_macros_loaded: bool,
     pub(crate) flycheck: Arc<[FlycheckHandle]>,
+    minicore: MiniCoreRustAnalyzerInternalOnly,
 }
 
 impl std::panic::UnwindSafe for GlobalStateSnapshot {}
@@ -304,6 +316,8 @@
 
             deferred_task_queue: task_queue,
             incomplete_crate_graph: false,
+
+            minicore: MiniCoreRustAnalyzerInternalOnly::default(),
         };
         // Apply any required database inputs from the config.
         this.update_configuration(config);
@@ -550,6 +564,7 @@
             workspaces: Arc::clone(&self.workspaces),
             analysis: self.analysis_host.analysis(),
             vfs: Arc::clone(&self.vfs),
+            minicore: self.minicore.clone(),
             check_fixes: Arc::clone(&self.diagnostics.check_fixes),
             mem_docs: self.mem_docs.clone(),
             semantic_tokens_cache: Arc::clone(&self.semantic_tokens_cache),
@@ -838,6 +853,14 @@
     pub(crate) fn file_exists(&self, file_id: FileId) -> bool {
         self.vfs.read().0.exists(file_id)
     }
+
+    #[inline]
+    pub(crate) fn minicore(&self) -> MiniCore<'_> {
+        match &self.minicore.minicore_text {
+            Some(minicore) => MiniCore::new(minicore),
+            None => MiniCore::default(),
+        }
+    }
 }
 
 pub(crate) fn file_id_to_url(vfs: &vfs::Vfs, id: FileId) -> Url {
diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs
index 6cb28ae..55d092f 100644
--- a/crates/rust-analyzer/src/handlers/request.rs
+++ b/crates/rust-analyzer/src/handlers/request.rs
@@ -7,8 +7,8 @@
 
 use base64::{Engine, prelude::BASE64_STANDARD};
 use ide::{
-    AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, CompletionFieldsToResolve,
-    FilePosition, FileRange, FileStructureConfig, HoverAction, HoverGotoTypeData,
+    AssistKind, AssistResolveStrategy, Cancellable, CompletionFieldsToResolve, FilePosition,
+    FileRange, FileStructureConfig, FindAllRefsConfig, HoverAction, HoverGotoTypeData,
     InlayFieldsToResolve, Query, RangeInfo, ReferenceCategory, Runnable, RunnableKind,
     SingleResolve, SourceChange, TextEdit,
 };
@@ -811,7 +811,8 @@
     let _p = tracing::info_span!("handle_goto_definition").entered();
     let position =
         try_default!(from_proto::file_position(&snap, params.text_document_position_params)?);
-    let nav_info = match snap.analysis.goto_definition(position)? {
+    let config = snap.config.goto_definition(snap.minicore());
+    let nav_info = match snap.analysis.goto_definition(position, &config)? {
         None => return Ok(None),
         Some(it) => it,
     };
@@ -829,7 +830,8 @@
         &snap,
         params.text_document_position_params.clone()
     )?);
-    let nav_info = match snap.analysis.goto_declaration(position)? {
+    let config = snap.config.goto_definition(snap.minicore());
+    let nav_info = match snap.analysis.goto_declaration(position, &config)? {
         None => return handle_goto_definition(snap, params),
         Some(it) => it,
     };
@@ -1106,7 +1108,7 @@
         context.and_then(|ctx| ctx.trigger_character).and_then(|s| s.chars().next());
 
     let source_root = snap.analysis.source_root_id(position.file_id)?;
-    let completion_config = &snap.config.completion(Some(source_root));
+    let completion_config = &snap.config.completion(Some(source_root), snap.minicore());
     // FIXME: We should fix up the position when retrying the cancelled request instead
     position.offset = position.offset.min(line_index.index.len());
     let items = match snap.analysis.completions(
@@ -1160,7 +1162,8 @@
     };
     let source_root = snap.analysis.source_root_id(file_id)?;
 
-    let mut forced_resolve_completions_config = snap.config.completion(Some(source_root));
+    let mut forced_resolve_completions_config =
+        snap.config.completion(Some(source_root), snap.minicore());
     forced_resolve_completions_config.fields_to_resolve = CompletionFieldsToResolve::empty();
 
     let position = FilePosition { file_id, offset };
@@ -1274,7 +1277,7 @@
     };
     let file_range = try_default!(from_proto::file_range(&snap, &params.text_document, range)?);
 
-    let hover = snap.config.hover();
+    let hover = snap.config.hover(snap.minicore());
     let info = match snap.analysis.hover(&hover, file_range)? {
         None => return Ok(None),
         Some(info) => info,
@@ -1360,7 +1363,11 @@
     let exclude_imports = snap.config.find_all_refs_exclude_imports();
     let exclude_tests = snap.config.find_all_refs_exclude_tests();
 
-    let Some(refs) = snap.analysis.find_all_refs(position, None)? else {
+    let Some(refs) = snap.analysis.find_all_refs(
+        position,
+        &FindAllRefsConfig { search_scope: None, minicore: snap.minicore() },
+    )?
+    else {
         return Ok(None);
     };
 
@@ -1615,8 +1622,8 @@
     let target_spec = TargetSpec::for_file(&snap, file_id)?;
 
     let annotations = snap.analysis.annotations(
-        &AnnotationConfig {
-            binary_target: target_spec
+        &lens_config.into_annotation_config(
+            target_spec
                 .map(|spec| {
                     matches!(
                         spec.target_kind(),
@@ -1624,13 +1631,8 @@
                     )
                 })
                 .unwrap_or(false),
-            annotate_runnables: lens_config.runnable(),
-            annotate_impls: lens_config.implementations,
-            annotate_references: lens_config.refs_adt,
-            annotate_method_references: lens_config.method_refs,
-            annotate_enum_variant_references: lens_config.enum_variant_refs,
-            location: lens_config.location.into(),
-        },
+            snap.minicore(),
+        ),
         file_id,
     )?;
 
@@ -1653,7 +1655,8 @@
     let Some(annotation) = from_proto::annotation(&snap, code_lens.range, resolve)? else {
         return Ok(code_lens);
     };
-    let annotation = snap.analysis.resolve_annotation(annotation)?;
+    let config = snap.config.lens().into_annotation_config(false, snap.minicore());
+    let annotation = snap.analysis.resolve_annotation(&config, annotation)?;
 
     let mut acc = Vec::new();
     to_proto::code_lens(&mut acc, &snap, annotation)?;
@@ -1736,7 +1739,7 @@
         range.end().min(line_index.index.len()),
     );
 
-    let inlay_hints_config = snap.config.inlay_hints();
+    let inlay_hints_config = snap.config.inlay_hints(snap.minicore());
     Ok(Some(
         snap.analysis
             .inlay_hints(&inlay_hints_config, file_id, Some(range))?
@@ -1777,7 +1780,7 @@
     let line_index = snap.file_line_index(file_id)?;
     let range = from_proto::text_range(&line_index, resolve_data.resolve_range)?;
 
-    let mut forced_resolve_inlay_hints_config = snap.config.inlay_hints();
+    let mut forced_resolve_inlay_hints_config = snap.config.inlay_hints(snap.minicore());
     forced_resolve_inlay_hints_config.fields_to_resolve = InlayFieldsToResolve::empty();
     let resolve_hints = snap.analysis.inlay_hints_resolve(
         &forced_resolve_inlay_hints_config,
@@ -1816,7 +1819,8 @@
     let position =
         try_default!(from_proto::file_position(&snap, params.text_document_position_params)?);
 
-    let nav_info = match snap.analysis.call_hierarchy(position)? {
+    let config = snap.config.call_hierarchy(snap.minicore());
+    let nav_info = match snap.analysis.call_hierarchy(position, &config)? {
         None => return Ok(None),
         Some(it) => it,
     };
@@ -1842,8 +1846,8 @@
     let frange = try_default!(from_proto::file_range(&snap, &doc, item.selection_range)?);
     let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
 
-    let config = snap.config.call_hierarchy();
-    let call_items = match snap.analysis.incoming_calls(config, fpos)? {
+    let config = snap.config.call_hierarchy(snap.minicore());
+    let call_items = match snap.analysis.incoming_calls(&config, fpos)? {
         None => return Ok(None),
         Some(it) => it,
     };
@@ -1881,8 +1885,8 @@
     let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
     let line_index = snap.file_line_index(fpos.file_id)?;
 
-    let config = snap.config.call_hierarchy();
-    let call_items = match snap.analysis.outgoing_calls(config, fpos)? {
+    let config = snap.config.call_hierarchy(snap.minicore());
+    let call_items = match snap.analysis.outgoing_calls(&config, fpos)? {
         None => return Ok(None),
         Some(it) => it,
     };
@@ -1916,7 +1920,7 @@
     let text = snap.analysis.file_text(file_id)?;
     let line_index = snap.file_line_index(file_id)?;
 
-    let mut highlight_config = snap.config.highlighting_config();
+    let mut highlight_config = snap.config.highlighting_config(snap.minicore());
     // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
     highlight_config.syntactic_name_ref_highlighting =
         snap.workspaces.is_empty() || !snap.proc_macros_loaded;
@@ -1946,7 +1950,7 @@
     let text = snap.analysis.file_text(file_id)?;
     let line_index = snap.file_line_index(file_id)?;
 
-    let mut highlight_config = snap.config.highlighting_config();
+    let mut highlight_config = snap.config.highlighting_config(snap.minicore());
     // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
     highlight_config.syntactic_name_ref_highlighting =
         snap.workspaces.is_empty() || !snap.proc_macros_loaded;
@@ -1988,7 +1992,7 @@
     let text = snap.analysis.file_text(frange.file_id)?;
     let line_index = snap.file_line_index(frange.file_id)?;
 
-    let mut highlight_config = snap.config.highlighting_config();
+    let mut highlight_config = snap.config.highlighting_config(snap.minicore());
     // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
     highlight_config.syntactic_name_ref_highlighting =
         snap.workspaces.is_empty() || !snap.proc_macros_loaded;
@@ -2156,7 +2160,13 @@
 ) -> Option<lsp_ext::CommandLinkGroup> {
     if snap.config.hover_actions().references
         && snap.config.client_commands().show_reference
-        && let Some(ref_search_res) = snap.analysis.find_all_refs(*position, None).unwrap_or(None)
+        && let Some(ref_search_res) = snap
+            .analysis
+            .find_all_refs(
+                *position,
+                &FindAllRefsConfig { search_scope: None, minicore: snap.minicore() },
+            )
+            .unwrap_or(None)
     {
         let uri = to_proto::url(snap, position.file_id);
         let line_index = snap.file_line_index(position.file_id).ok()?;
diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs
index 84b7888..38ee9cb 100644
--- a/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -16,7 +16,7 @@
     FilePosition, TextSize,
 };
 use ide_db::{
-    SnippetCap,
+    MiniCore, SnippetCap,
     imports::insert_use::{ImportGranularity, InsertUseConfig},
 };
 use project_model::CargoConfig;
@@ -186,6 +186,7 @@
             exclude_traits: &[],
             enable_auto_await: true,
             enable_auto_iter: true,
+            minicore: MiniCore::default(),
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -240,6 +241,7 @@
             exclude_traits: &[],
             enable_auto_await: true,
             enable_auto_iter: true,
+            minicore: MiniCore::default(),
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -292,6 +294,7 @@
             exclude_traits: &[],
             enable_auto_await: true,
             enable_auto_iter: true,
+            minicore: MiniCore::default(),
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
diff --git a/crates/rust-analyzer/src/lsp/semantic_tokens.rs b/crates/rust-analyzer/src/lsp/semantic_tokens.rs
index 3c21e19..828118a 100644
--- a/crates/rust-analyzer/src/lsp/semantic_tokens.rs
+++ b/crates/rust-analyzer/src/lsp/semantic_tokens.rs
@@ -91,6 +91,7 @@
         (LIFETIME, "lifetime"),
         (LOGICAL, "logical") => OPERATOR,
         (MACRO_BANG, "macroBang") => MACRO,
+        (NEGATION, "negation") => OPERATOR,
         (PARENTHESIS, "parenthesis"),
         (PROC_MACRO, "procMacro") => MACRO,
         (PUNCTUATION, "punctuation"),
diff --git a/crates/rust-analyzer/src/lsp/to_proto.rs b/crates/rust-analyzer/src/lsp/to_proto.rs
index d51ddb8..024c13e 100644
--- a/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -16,7 +16,9 @@
     SnippetEdit, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize,
     UpdateTest,
 };
-use ide_db::{FxHasher, assists, rust_doc::format_docs, source_change::ChangeAnnotationId};
+use ide_db::{
+    FxHasher, MiniCore, assists, rust_doc::format_docs, source_change::ChangeAnnotationId,
+};
 use itertools::Itertools;
 use paths::{Utf8Component, Utf8Prefix};
 use semver::VersionReq;
@@ -270,7 +272,7 @@
         );
     }
 
-    if let Some(limit) = config.completion(None).limit {
+    if let Some(limit) = config.completion(None, MiniCore::default()).limit {
         res.sort_by(|item1, item2| item1.sort_text.cmp(&item2.sort_text));
         res.truncate(limit);
     }
@@ -400,16 +402,17 @@
 
     set_score(&mut lsp_item, max_relevance, item.relevance);
 
-    let imports =
-        if config.completion(None).enable_imports_on_the_fly && !item.import_to_add.is_empty() {
-            item.import_to_add
-                .clone()
-                .into_iter()
-                .map(|import_path| lsp_ext::CompletionImport { full_import_path: import_path })
-                .collect()
-        } else {
-            Vec::new()
-        };
+    let imports = if config.completion(None, MiniCore::default()).enable_imports_on_the_fly
+        && !item.import_to_add.is_empty()
+    {
+        item.import_to_add
+            .clone()
+            .into_iter()
+            .map(|import_path| lsp_ext::CompletionImport { full_import_path: import_path })
+            .collect()
+    } else {
+        Vec::new()
+    };
     let (ref_resolve_data, resolve_data) = if something_to_resolve || !imports.is_empty() {
         let ref_resolve_data = if ref_match.is_some() {
             let ref_resolve_data = lsp_ext::CompletionResolveData {
@@ -493,8 +496,15 @@
                 .parameter_ranges()
                 .iter()
                 .map(|it| {
-                    let start = call_info.signature[..it.start().into()].chars().count() as u32;
-                    let end = call_info.signature[..it.end().into()].chars().count() as u32;
+                    let start = call_info.signature[..it.start().into()]
+                        .chars()
+                        .map(|c| c.len_utf16())
+                        .sum::<usize>() as u32;
+                    let end = start
+                        + call_info.signature[it.start().into()..it.end().into()]
+                            .chars()
+                            .map(|c| c.len_utf16())
+                            .sum::<usize>() as u32;
                     [start, end]
                 })
                 .map(|label_offsets| lsp_types::ParameterInformation {
@@ -513,9 +523,9 @@
                     label.push_str(", ");
                 }
                 first = false;
-                let start = label.chars().count() as u32;
+                let start = label.len() as u32;
                 label.push_str(param);
-                let end = label.chars().count() as u32;
+                let end = label.len() as u32;
                 params.push(lsp_types::ParameterInformation {
                     label: lsp_types::ParameterLabel::LabelOffsets([start, end]),
                     documentation: None,
@@ -837,6 +847,7 @@
             HlOperator::Bitwise => types::BITWISE,
             HlOperator::Arithmetic => types::ARITHMETIC,
             HlOperator::Logical => types::LOGICAL,
+            HlOperator::Negation => types::NEGATION,
             HlOperator::Comparison => types::COMPARISON,
             HlOperator::Other => types::OPERATOR,
         },
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 3e80e8b..c0947b2 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -847,6 +847,13 @@
                 self.debounce_workspace_fetch();
                 let vfs = &mut self.vfs.write().0;
                 for (path, contents) in files {
+                    if matches!(path.name_and_extension(), Some(("minicore", Some("rs")))) {
+                        // Not a lot of bad can happen from mistakenly identifying `minicore`, so proceed with that.
+                        self.minicore.minicore_text = contents
+                            .as_ref()
+                            .and_then(|contents| String::from_utf8(contents.clone()).ok());
+                    }
+
                     let path = VfsPath::from(path);
                     // if the file is in mem docs, it's managed by the client via notifications
                     // so only set it if its not in there
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index ca15e6a..1475f02 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -222,6 +222,16 @@
                     message.push_str(err);
                     message.push_str("\n\n");
                 }
+                if let Some(err) = ws.sysroot.metadata_error() {
+                    status.health |= lsp_ext::Health::Warning;
+                    format_to!(
+                        message,
+                        "Failed to read Cargo metadata with dependencies for sysroot of `{}`: ",
+                        ws.manifest_or_root()
+                    );
+                    message.push_str(err);
+                    message.push_str("\n\n");
+                }
                 if let ProjectWorkspaceKind::Cargo { rustc: Err(Some(err)), .. } = &ws.kind {
                     status.health |= lsp_ext::Health::Warning;
                     format_to!(
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index d60196d..6c1dcf3 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -2,9 +2,9 @@
 
 #![allow(non_snake_case)]
 use crate::{
-    ast::{self, support, AstChildren, AstNode},
     SyntaxKind::{self, *},
     SyntaxNode, SyntaxToken, T,
+    ast::{self, AstChildren, AstNode, support},
 };
 use std::{fmt, hash};
 pub struct Abi {
@@ -2262,11 +2262,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == ABI }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2298,11 +2294,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == ARG_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2334,11 +2326,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == ARRAY_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2370,11 +2358,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == ARRAY_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2406,11 +2390,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_CLOBBER_ABI }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2442,11 +2422,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_CONST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2478,11 +2454,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_DIR_SPEC }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2514,11 +2486,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2550,11 +2518,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_LABEL }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2586,11 +2550,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_OPERAND_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2622,11 +2582,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_OPERAND_NAMED }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2658,11 +2614,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_OPTION }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2694,11 +2646,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_OPTIONS }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2730,11 +2678,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_REG_OPERAND }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2766,11 +2710,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_REG_SPEC }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2802,11 +2742,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_SYM }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2838,11 +2774,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASSOC_ITEM_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2874,11 +2806,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASSOC_TYPE_ARG }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2910,11 +2838,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == ATTR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2946,11 +2870,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == AWAIT_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2982,11 +2902,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == BECOME_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3018,11 +2934,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == BIN_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3054,11 +2966,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == BLOCK_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3090,11 +2998,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == BOX_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3126,11 +3030,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == BREAK_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3162,11 +3062,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == CALL_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3198,11 +3094,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == CAST_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3234,11 +3126,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == CLOSURE_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3270,11 +3158,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == CONST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3306,11 +3190,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_ARG }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3342,11 +3222,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_BLOCK_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3378,11 +3254,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_PARAM }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3414,11 +3286,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == CONTINUE_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3450,11 +3318,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == DYN_TRAIT_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3486,11 +3350,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == ENUM }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3522,11 +3382,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_STMT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3558,11 +3414,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_BLOCK }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3594,11 +3446,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_CRATE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3630,11 +3478,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_ITEM_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3666,11 +3510,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == FIELD_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3702,11 +3542,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == FN }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3738,11 +3574,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == FN_PTR_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3774,11 +3606,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_BINDER }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3810,11 +3638,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3846,11 +3670,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3882,11 +3702,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == FORMAT_ARGS_ARG }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3918,11 +3734,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == FORMAT_ARGS_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3954,11 +3766,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == GENERIC_ARG_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3990,11 +3798,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == GENERIC_PARAM_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4026,11 +3830,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == IDENT_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4062,11 +3862,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == IF_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4098,11 +3894,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == IMPL }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4134,11 +3926,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == IMPL_TRAIT_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4170,11 +3958,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == INDEX_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4206,11 +3990,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == INFER_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4242,11 +4022,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == ITEM_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4278,11 +4054,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == LABEL }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4314,11 +4086,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == LET_ELSE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4350,11 +4118,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == LET_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4386,11 +4150,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == LET_STMT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4422,11 +4182,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4458,11 +4214,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME_ARG }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4494,11 +4246,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME_PARAM }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4530,11 +4278,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == LITERAL }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4566,11 +4310,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == LITERAL_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4602,11 +4342,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == LOOP_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4638,11 +4374,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_CALL }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4674,11 +4406,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_DEF }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4710,11 +4438,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4746,11 +4470,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_ITEMS }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4782,11 +4502,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4818,11 +4534,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_RULES }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4854,11 +4566,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_STMTS }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4890,11 +4598,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4926,11 +4630,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_ARM }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4962,11 +4662,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_ARM_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4998,11 +4694,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5034,11 +4726,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_GUARD }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5070,11 +4758,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == META }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5106,11 +4790,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == METHOD_CALL_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5142,11 +4822,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == MODULE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5178,11 +4854,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == NAME }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5214,11 +4886,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == NAME_REF }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5250,11 +4918,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == NEVER_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5286,11 +4950,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == OFFSET_OF_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5322,11 +4982,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == OR_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5358,11 +5014,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == PARAM }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5394,11 +5046,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == PARAM_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5430,11 +5078,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5466,11 +5110,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5502,11 +5142,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5538,11 +5174,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == PARENTHESIZED_ARG_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5574,11 +5206,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == PATH }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5610,11 +5238,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5646,11 +5270,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5682,11 +5302,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_SEGMENT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5718,11 +5334,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5754,11 +5366,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == PREFIX_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5790,11 +5398,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == PTR_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5826,11 +5430,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == RANGE_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5862,11 +5462,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == RANGE_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5898,11 +5494,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5934,11 +5526,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_EXPR_FIELD }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5970,11 +5558,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_EXPR_FIELD_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6006,11 +5590,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_FIELD }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6042,11 +5622,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_FIELD_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6078,11 +5654,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6114,11 +5686,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT_FIELD }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6150,11 +5718,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT_FIELD_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6186,11 +5750,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == REF_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6222,11 +5782,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == REF_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6258,11 +5814,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == REF_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6294,11 +5846,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == RENAME }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6330,11 +5878,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == REST_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6366,11 +5910,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == RET_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6402,11 +5942,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == RETURN_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6438,11 +5974,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == RETURN_TYPE_SYNTAX }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6474,11 +6006,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == SELF_PARAM }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6510,11 +6038,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == SLICE_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6546,11 +6070,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == SLICE_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6582,11 +6102,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == SOURCE_FILE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6618,11 +6134,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == STATIC }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6654,11 +6166,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == STMT_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6690,11 +6198,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == STRUCT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6726,11 +6230,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == TOKEN_TREE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6762,11 +6262,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == TRAIT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6798,11 +6294,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == TRY_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6834,11 +6326,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6870,11 +6358,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_FIELD }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6906,11 +6390,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_FIELD_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6942,11 +6422,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6978,11 +6454,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_STRUCT_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7014,11 +6486,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7050,11 +6518,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ALIAS }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7086,11 +6550,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ANCHOR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7122,11 +6582,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ARG }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7158,11 +6614,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_BOUND }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7194,11 +6646,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_BOUND_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7230,11 +6678,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_PARAM }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7266,11 +6710,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == UNDERSCORE_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7302,11 +6742,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == UNION }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7338,11 +6774,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == USE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7374,11 +6806,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == USE_BOUND_GENERIC_ARGS }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7410,11 +6838,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7446,11 +6870,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7482,11 +6902,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == VARIANT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7518,11 +6934,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == VARIANT_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7554,11 +6966,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == VISIBILITY }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7590,11 +6998,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == WHERE_CLAUSE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7626,11 +7030,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == WHERE_PRED }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7662,11 +7062,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == WHILE_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7698,11 +7094,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == WILDCARD_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7734,11 +7126,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == YEET_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7770,11 +7158,7 @@
     fn can_cast(kind: SyntaxKind) -> bool { kind == YIELD_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
diff --git a/crates/syntax/src/ast/generated/tokens.rs b/crates/syntax/src/ast/generated/tokens.rs
index b2f56c0..3dca0db 100644
--- a/crates/syntax/src/ast/generated/tokens.rs
+++ b/crates/syntax/src/ast/generated/tokens.rs
@@ -1,9 +1,9 @@
 //! Generated by `cargo xtask codegen grammar`, do not edit by hand.
 
 use crate::{
-    ast::AstToken,
     SyntaxKind::{self, *},
     SyntaxToken,
+    ast::AstToken,
 };
 use std::{fmt, hash};
 pub struct Byte {
@@ -17,11 +17,7 @@
 impl AstToken for Byte {
     fn can_cast(kind: SyntaxKind) -> bool { kind == BYTE }
     fn cast(syntax: SyntaxToken) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     fn syntax(&self) -> &SyntaxToken { &self.syntax }
 }
@@ -51,11 +47,7 @@
 impl AstToken for ByteString {
     fn can_cast(kind: SyntaxKind) -> bool { kind == BYTE_STRING }
     fn cast(syntax: SyntaxToken) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     fn syntax(&self) -> &SyntaxToken { &self.syntax }
 }
@@ -85,11 +77,7 @@
 impl AstToken for CString {
     fn can_cast(kind: SyntaxKind) -> bool { kind == C_STRING }
     fn cast(syntax: SyntaxToken) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     fn syntax(&self) -> &SyntaxToken { &self.syntax }
 }
@@ -119,11 +107,7 @@
 impl AstToken for Char {
     fn can_cast(kind: SyntaxKind) -> bool { kind == CHAR }
     fn cast(syntax: SyntaxToken) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     fn syntax(&self) -> &SyntaxToken { &self.syntax }
 }
@@ -153,11 +137,7 @@
 impl AstToken for Comment {
     fn can_cast(kind: SyntaxKind) -> bool { kind == COMMENT }
     fn cast(syntax: SyntaxToken) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     fn syntax(&self) -> &SyntaxToken { &self.syntax }
 }
@@ -187,11 +167,7 @@
 impl AstToken for FloatNumber {
     fn can_cast(kind: SyntaxKind) -> bool { kind == FLOAT_NUMBER }
     fn cast(syntax: SyntaxToken) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     fn syntax(&self) -> &SyntaxToken { &self.syntax }
 }
@@ -221,11 +197,7 @@
 impl AstToken for Ident {
     fn can_cast(kind: SyntaxKind) -> bool { kind == IDENT }
     fn cast(syntax: SyntaxToken) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     fn syntax(&self) -> &SyntaxToken { &self.syntax }
 }
@@ -255,11 +227,7 @@
 impl AstToken for IntNumber {
     fn can_cast(kind: SyntaxKind) -> bool { kind == INT_NUMBER }
     fn cast(syntax: SyntaxToken) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     fn syntax(&self) -> &SyntaxToken { &self.syntax }
 }
@@ -289,11 +257,7 @@
 impl AstToken for String {
     fn can_cast(kind: SyntaxKind) -> bool { kind == STRING }
     fn cast(syntax: SyntaxToken) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     fn syntax(&self) -> &SyntaxToken { &self.syntax }
 }
@@ -323,11 +287,7 @@
 impl AstToken for Whitespace {
     fn can_cast(kind: SyntaxKind) -> bool { kind == WHITESPACE }
     fn cast(syntax: SyntaxToken) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     fn syntax(&self) -> &SyntaxToken { &self.syntax }
 }
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs
index d9223e8..e1a9f3a 100644
--- a/crates/syntax/src/ast/token_ext.rs
+++ b/crates/syntax/src/ast/token_ext.rs
@@ -201,6 +201,10 @@
             None
         }
     }
+    fn map_offset_down(&self, offset: TextSize) -> Option<TextSize> {
+        let contents_range = self.text_range_between_quotes()?;
+        offset.checked_sub(contents_range.start())
+    }
 }
 
 impl IsString for ast::String {
diff --git a/crates/test-fixture/src/lib.rs b/crates/test-fixture/src/lib.rs
index a454979..a718b96 100644
--- a/crates/test-fixture/src/lib.rs
+++ b/crates/test-fixture/src/lib.rs
@@ -24,7 +24,7 @@
 use span::{Edition, FileId, Span};
 use stdx::itertools::Itertools;
 use test_utils::{
-    CURSOR_MARKER, ESCAPED_CURSOR_MARKER, Fixture, FixtureWithProjectMeta, RangeOrOffset,
+    CURSOR_MARKER, ESCAPED_CURSOR_MARKER, Fixture, FixtureWithProjectMeta, MiniCore, RangeOrOffset,
     extract_range_or_offset,
 };
 use triomphe::Arc;
@@ -69,7 +69,12 @@
         proc_macros: Vec<(String, ProcMacro)>,
     ) -> Self {
         let mut db = Self::default();
-        let fixture = ChangeFixture::parse_with_proc_macros(&db, ra_fixture, proc_macros);
+        let fixture = ChangeFixture::parse_with_proc_macros(
+            &db,
+            ra_fixture,
+            MiniCore::RAW_SOURCE,
+            proc_macros,
+        );
         fixture.change.apply(&mut db);
         assert!(fixture.file_position.is_none());
         db
@@ -112,8 +117,10 @@
 
 pub struct ChangeFixture {
     pub file_position: Option<(EditionedFileId, RangeOrOffset)>,
+    pub file_lines: Vec<usize>,
     pub files: Vec<EditionedFileId>,
     pub change: ChangeWithProcMacros,
+    pub sysroot_files: Vec<FileId>,
 }
 
 const SOURCE_ROOT_PREFIX: &str = "/";
@@ -123,12 +130,13 @@
         db: &dyn salsa::Database,
         #[rust_analyzer::rust_fixture] ra_fixture: &str,
     ) -> ChangeFixture {
-        Self::parse_with_proc_macros(db, ra_fixture, Vec::new())
+        Self::parse_with_proc_macros(db, ra_fixture, MiniCore::RAW_SOURCE, Vec::new())
     }
 
     pub fn parse_with_proc_macros(
         db: &dyn salsa::Database,
         #[rust_analyzer::rust_fixture] ra_fixture: &str,
+        minicore_raw: &str,
         mut proc_macro_defs: Vec<(String, ProcMacro)>,
     ) -> ChangeFixture {
         let FixtureWithProjectMeta {
@@ -149,6 +157,8 @@
         let mut source_change = FileChange::default();
 
         let mut files = Vec::new();
+        let mut sysroot_files = Vec::new();
+        let mut file_lines = Vec::new();
         let mut crate_graph = CrateGraphBuilder::default();
         let mut crates = FxIndexMap::default();
         let mut crate_deps = Vec::new();
@@ -173,6 +183,8 @@
         let proc_macro_cwd = Arc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap()));
 
         for entry in fixture {
+            file_lines.push(entry.line);
+
             let mut range_or_offset = None;
             let text = if entry.text.contains(CURSOR_MARKER) {
                 if entry.text.contains(ESCAPED_CURSOR_MARKER) {
@@ -240,7 +252,7 @@
                 assert!(default_crate_root.is_none());
                 default_crate_root = Some(file_id);
                 default_edition = meta.edition;
-                default_cfg.extend(meta.cfg.into_iter());
+                default_cfg.append(meta.cfg);
                 default_env.extend_from_other(&meta.env);
             }
 
@@ -259,7 +271,9 @@
             fs.insert(core_file, VfsPath::new_virtual_path("/sysroot/core/lib.rs".to_owned()));
             roots.push(SourceRoot::new_library(fs));
 
-            source_change.change_file(core_file, Some(mini_core.source_code()));
+            sysroot_files.push(core_file);
+
+            source_change.change_file(core_file, Some(mini_core.source_code(minicore_raw)));
 
             let core_crate = crate_graph.add_crate_root(
                 core_file,
@@ -348,6 +362,8 @@
             );
             roots.push(SourceRoot::new_library(fs));
 
+            sysroot_files.push(proc_lib_file);
+
             source_change.change_file(proc_lib_file, Some(source));
 
             let all_crates = crate_graph.iter().collect::<Vec<_>>();
@@ -396,7 +412,7 @@
         change.source_change.set_roots(roots);
         change.source_change.set_crate_graph(crate_graph);
 
-        ChangeFixture { file_position, files, change }
+        ChangeFixture { file_position, file_lines, files, change, sysroot_files }
     }
 }
 
diff --git a/crates/test-utils/src/fixture.rs b/crates/test-utils/src/fixture.rs
index c024089..559894e 100644
--- a/crates/test-utils/src/fixture.rs
+++ b/crates/test-utils/src/fixture.rs
@@ -132,13 +132,17 @@
     pub library: bool,
     /// Actual file contents. All meta comments are stripped.
     pub text: String,
+    /// The line number in the original fixture of the beginning of this fixture.
+    pub line: usize,
 }
 
+#[derive(Debug)]
 pub struct MiniCore {
     activated_flags: Vec<String>,
     valid_flags: Vec<String>,
 }
 
+#[derive(Debug)]
 pub struct FixtureWithProjectMeta {
     pub fixture: Vec<Fixture>,
     pub mini_core: Option<MiniCore>,
@@ -184,40 +188,49 @@
         let mut mini_core = None;
         let mut res: Vec<Fixture> = Vec::new();
         let mut proc_macro_names = vec![];
+        let mut first_row = 0;
 
         if let Some(meta) = fixture.strip_prefix("//- toolchain:") {
+            first_row += 1;
             let (meta, remain) = meta.split_once('\n').unwrap();
             toolchain = Some(meta.trim().to_owned());
             fixture = remain;
         }
 
         if let Some(meta) = fixture.strip_prefix("//- target_data_layout:") {
+            first_row += 1;
             let (meta, remain) = meta.split_once('\n').unwrap();
             meta.trim().clone_into(&mut target_data_layout);
             fixture = remain;
         }
 
         if let Some(meta) = fixture.strip_prefix("//- target_arch:") {
+            first_row += 1;
             let (meta, remain) = meta.split_once('\n').unwrap();
             meta.trim().clone_into(&mut target_arch);
             fixture = remain;
         }
 
         if let Some(meta) = fixture.strip_prefix("//- proc_macros:") {
+            first_row += 1;
             let (meta, remain) = meta.split_once('\n').unwrap();
             proc_macro_names = meta.split(',').map(|it| it.trim().to_owned()).collect();
             fixture = remain;
         }
 
         if let Some(meta) = fixture.strip_prefix("//- minicore:") {
+            first_row += 1;
             let (meta, remain) = meta.split_once('\n').unwrap();
             mini_core = Some(MiniCore::parse(meta));
             fixture = remain;
         }
 
-        let default = if fixture.contains("//-") { None } else { Some("//- /main.rs") };
+        let default =
+            if fixture.contains("//- /") { None } else { Some((first_row - 1, "//- /main.rs")) };
 
-        for (ix, line) in default.into_iter().chain(fixture.split_inclusive('\n')).enumerate() {
+        for (ix, line) in
+            default.into_iter().chain((first_row..).zip(fixture.split_inclusive('\n')))
+        {
             if line.contains("//-") {
                 assert!(
                     line.starts_with("//-"),
@@ -228,7 +241,7 @@
             }
 
             if let Some(line) = line.strip_prefix("//-") {
-                let meta = Self::parse_meta_line(line);
+                let meta = Self::parse_meta_line(line, (ix + 1).try_into().unwrap());
                 res.push(meta);
             } else {
                 if matches!(line.strip_prefix("// "), Some(l) if l.trim().starts_with('/')) {
@@ -252,7 +265,7 @@
     }
 
     //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo
-    fn parse_meta_line(meta: &str) -> Fixture {
+    fn parse_meta_line(meta: &str, line: usize) -> Fixture {
         let meta = meta.trim();
         let mut components = meta.split_ascii_whitespace();
 
@@ -317,6 +330,7 @@
         Fixture {
             path,
             text: String::new(),
+            line,
             krate,
             deps,
             extern_prelude,
@@ -330,7 +344,7 @@
 }
 
 impl MiniCore {
-    const RAW_SOURCE: &'static str = include_str!("./minicore.rs");
+    pub const RAW_SOURCE: &'static str = include_str!("./minicore.rs");
 
     fn has_flag(&self, flag: &str) -> bool {
         self.activated_flags.iter().any(|it| it == flag)
@@ -363,8 +377,8 @@
         res
     }
 
-    pub fn available_flags() -> impl Iterator<Item = &'static str> {
-        let lines = MiniCore::RAW_SOURCE.split_inclusive('\n');
+    pub fn available_flags(raw_source: &str) -> impl Iterator<Item = &str> {
+        let lines = raw_source.split_inclusive('\n');
         lines
             .map_while(|x| x.strip_prefix("//!"))
             .skip_while(|line| !line.contains("Available flags:"))
@@ -375,9 +389,9 @@
     /// Strips parts of minicore.rs which are flagged by inactive flags.
     ///
     /// This is probably over-engineered to support flags dependencies.
-    pub fn source_code(mut self) -> String {
+    pub fn source_code(mut self, raw_source: &str) -> String {
         let mut buf = String::new();
-        let mut lines = MiniCore::RAW_SOURCE.split_inclusive('\n');
+        let mut lines = raw_source.split_inclusive('\n');
 
         let mut implications = Vec::new();
 
diff --git a/crates/vfs/src/path_interner.rs b/crates/vfs/src/path_interner.rs
index 64f5197..225bfc7 100644
--- a/crates/vfs/src/path_interner.rs
+++ b/crates/vfs/src/path_interner.rs
@@ -28,7 +28,7 @@
     /// - Else, returns a newly allocated id.
     pub(crate) fn intern(&mut self, path: VfsPath) -> FileId {
         let (id, _added) = self.map.insert_full(path);
-        assert!(id < u32::MAX as usize);
+        assert!(id < FileId::MAX as usize);
         FileId(id as u32)
     }
 
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index e35a159..6dd4485 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -21,6 +21,7 @@
                 "@stylistic/eslint-plugin": "^4.1.0",
                 "@stylistic/eslint-plugin-js": "^4.1.0",
                 "@tsconfig/strictest": "^2.0.5",
+                "@types/lodash": "^4.17.20",
                 "@types/node": "~22.13.4",
                 "@types/vscode": "~1.93.0",
                 "@typescript-eslint/eslint-plugin": "^8.25.0",
@@ -1388,6 +1389,13 @@
             "dev": true,
             "license": "MIT"
         },
+        "node_modules/@types/lodash": {
+            "version": "4.17.20",
+            "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.20.tgz",
+            "integrity": "sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==",
+            "dev": true,
+            "license": "MIT"
+        },
         "node_modules/@types/node": {
             "version": "22.13.5",
             "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.5.tgz",
diff --git a/editors/code/package.json b/editors/code/package.json
index 7068723..d659421 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -58,6 +58,7 @@
         "@stylistic/eslint-plugin": "^4.1.0",
         "@stylistic/eslint-plugin-js": "^4.1.0",
         "@tsconfig/strictest": "^2.0.5",
+        "@types/lodash": "^4.17.20",
         "@types/node": "~22.13.4",
         "@types/vscode": "~1.93.0",
         "@typescript-eslint/eslint-plugin": "^8.25.0",
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts
index 073ff2f..cb71a01 100644
--- a/editors/code/src/client.ts
+++ b/editors/code/src/client.ts
@@ -13,7 +13,7 @@
 export async function createClient(
     traceOutputChannel: vscode.OutputChannel,
     outputChannel: vscode.OutputChannel,
-    initializationOptions: vscode.WorkspaceConfiguration,
+    initializationOptions: lc.LanguageClientOptions["initializationOptions"],
     serverOptions: lc.ServerOptions,
     config: Config,
     unlinkedFiles: vscode.Uri[],
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index 3b1b076..5dc2c41 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -4,7 +4,7 @@
 import * as vscode from "vscode";
 import { expectNotUndefined, log, normalizeDriveLetter, unwrapUndefinable } from "./util";
 import type { Env } from "./util";
-import type { Disposable } from "vscode";
+import { cloneDeep, get, pickBy, set } from "lodash";
 
 export type RunnableEnvCfgItem = {
     mask?: string;
@@ -12,13 +12,25 @@
     platform?: string | string[];
 };
 
+export type ConfigurationTree = { [key: string]: ConfigurationValue };
+export type ConfigurationValue =
+    | undefined
+    | null
+    | boolean
+    | number
+    | string
+    | ConfigurationValue[]
+    | ConfigurationTree;
+
 type ShowStatusBar = "always" | "never" | { documentSelector: vscode.DocumentSelector };
 
 export class Config {
     readonly extensionId = "rust-lang.rust-analyzer";
-    configureLang: vscode.Disposable | undefined;
 
-    readonly rootSection = "rust-analyzer";
+    configureLang: vscode.Disposable | undefined;
+    workspaceState: vscode.Memento;
+
+    private readonly rootSection = "rust-analyzer";
     private readonly requiresServerReloadOpts = ["server", "files", "showSyntaxTree"].map(
         (opt) => `${this.rootSection}.${opt}`,
     );
@@ -27,8 +39,13 @@
         (opt) => `${this.rootSection}.${opt}`,
     );
 
-    constructor(disposables: Disposable[]) {
-        vscode.workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, disposables);
+    constructor(ctx: vscode.ExtensionContext) {
+        this.workspaceState = ctx.workspaceState;
+        vscode.workspace.onDidChangeConfiguration(
+            this.onDidChangeConfiguration,
+            this,
+            ctx.subscriptions,
+        );
         this.refreshLogging();
         this.configureLanguage();
     }
@@ -37,6 +54,44 @@
         this.configureLang?.dispose();
     }
 
+    private readonly extensionConfigurationStateKey = "extensionConfigurations";
+
+    /// Returns the rust-analyzer-specific workspace configuration, incl. any
+    /// configuration items overridden by (present) extensions.
+    get extensionConfigurations(): Record<string, Record<string, unknown>> {
+        return pickBy(
+            this.workspaceState.get<Record<string, ConfigurationTree>>(
+                "extensionConfigurations",
+                {},
+            ),
+            // ignore configurations from disabled/removed extensions
+            (_, extensionId) => vscode.extensions.getExtension(extensionId) !== undefined,
+        );
+    }
+
+    async addExtensionConfiguration(
+        extensionId: string,
+        configuration: Record<string, unknown>,
+    ): Promise<void> {
+        const oldConfiguration = this.cfg;
+
+        const extCfgs = this.extensionConfigurations;
+        extCfgs[extensionId] = configuration;
+        await this.workspaceState.update(this.extensionConfigurationStateKey, extCfgs);
+
+        const newConfiguration = this.cfg;
+        const prefix = `${this.rootSection}.`;
+        await this.onDidChangeConfiguration({
+            affectsConfiguration(section: string, _scope?: vscode.ConfigurationScope): boolean {
+                return (
+                    section.startsWith(prefix) &&
+                    get(oldConfiguration, section.slice(prefix.length)) !==
+                        get(newConfiguration, section.slice(prefix.length))
+                );
+            },
+        });
+    }
+
     private refreshLogging() {
         log.info(
             "Extension version:",
@@ -176,10 +231,36 @@
     // We don't do runtime config validation here for simplicity. More on stackoverflow:
     // https://stackoverflow.com/questions/60135780/what-is-the-best-way-to-type-check-the-configuration-for-vscode-extension
 
-    private get cfg(): vscode.WorkspaceConfiguration {
+    // Returns the raw configuration for rust-analyzer as returned by vscode. This
+    // should only be used when modifications to the user/workspace configuration
+    // are required.
+    private get rawCfg(): vscode.WorkspaceConfiguration {
         return vscode.workspace.getConfiguration(this.rootSection);
     }
 
+    // Returns the final configuration to use, with extension configuration overrides merged in.
+    public get cfg(): ConfigurationTree {
+        const finalConfig = cloneDeep<ConfigurationTree>(this.rawCfg);
+        for (const [extensionId, items] of Object.entries(this.extensionConfigurations)) {
+            for (const [k, v] of Object.entries(items)) {
+                const i = this.rawCfg.inspect(k);
+                if (
+                    i?.workspaceValue !== undefined ||
+                    i?.workspaceFolderValue !== undefined ||
+                    i?.globalValue !== undefined
+                ) {
+                    log.trace(
+                        `Ignoring configuration override for ${k} from extension ${extensionId}`,
+                    );
+                    continue;
+                }
+                log.trace(`Extension ${extensionId} overrides configuration ${k} to `, v);
+                set(finalConfig, k, v);
+            }
+        }
+        return finalConfig;
+    }
+
     /**
      * Beware that postfix `!` operator erases both `null` and `undefined`.
      * This is why the following doesn't work as expected:
@@ -187,7 +268,6 @@
      * ```ts
      * const nullableNum = vscode
      *  .workspace
-     *  .getConfiguration
      *  .getConfiguration("rust-analyzer")
      *  .get<number | null>(path)!;
      *
@@ -197,7 +277,7 @@
      * So this getter handles this quirk by not requiring the caller to use postfix `!`
      */
     private get<T>(path: string): T | undefined {
-        return prepareVSCodeConfig(this.cfg.get<T>(path));
+        return prepareVSCodeConfig(get(this.cfg, path)) as T;
     }
 
     get serverPath() {
@@ -223,7 +303,7 @@
     }
 
     async toggleCheckOnSave() {
-        const config = this.cfg.inspect<boolean>("checkOnSave") ?? { key: "checkOnSave" };
+        const config = this.rawCfg.inspect<boolean>("checkOnSave") ?? { key: "checkOnSave" };
         let overrideInLanguage;
         let target;
         let value;
@@ -249,7 +329,12 @@
             overrideInLanguage = config.defaultLanguageValue;
             value = config.defaultValue || config.defaultLanguageValue;
         }
-        await this.cfg.update("checkOnSave", !(value || false), target || null, overrideInLanguage);
+        await this.rawCfg.update(
+            "checkOnSave",
+            !(value || false),
+            target || null,
+            overrideInLanguage,
+        );
     }
 
     get problemMatcher(): string[] {
@@ -367,26 +452,24 @@
     }
 
     async setAskBeforeUpdateTest(value: boolean) {
-        await this.cfg.update("runnables.askBeforeUpdateTest", value, true);
+        await this.rawCfg.update("runnables.askBeforeUpdateTest", value, true);
     }
 }
 
-export function prepareVSCodeConfig<T>(resp: T): T {
+export function prepareVSCodeConfig(resp: ConfigurationValue): ConfigurationValue {
     if (Is.string(resp)) {
-        return substituteVSCodeVariableInString(resp) as T;
-        // eslint-disable-next-line @typescript-eslint/no-explicit-any
-    } else if (resp && Is.array<any>(resp)) {
+        return substituteVSCodeVariableInString(resp);
+    } else if (resp && Is.array(resp)) {
         return resp.map((val) => {
             return prepareVSCodeConfig(val);
-        }) as T;
+        });
     } else if (resp && typeof resp === "object") {
-        // eslint-disable-next-line @typescript-eslint/no-explicit-any
-        const res: { [key: string]: any } = {};
+        const res: ConfigurationTree = {};
         for (const key in resp) {
             const val = resp[key];
             res[key] = prepareVSCodeConfig(val);
         }
-        return res as T;
+        return res;
     }
     return resp;
 }
diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts
index e55754f..a7b7be0 100644
--- a/editors/code/src/ctx.ts
+++ b/editors/code/src/ctx.ts
@@ -125,7 +125,7 @@
         extCtx.subscriptions.push(this);
         this.version = extCtx.extension.packageJSON.version ?? "<unknown>";
         this._serverVersion = "<not running>";
-        this.config = new Config(extCtx.subscriptions);
+        this.config = new Config(extCtx);
         this.statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
         this.updateStatusBarVisibility(vscode.window.activeTextEditor);
         this.statusBarActiveEditorListener = vscode.window.onDidChangeActiveTextEditor((editor) =>
@@ -150,6 +150,13 @@
         });
     }
 
+    async addConfiguration(
+        extensionId: string,
+        configuration: Record<string, unknown>,
+    ): Promise<void> {
+        await this.config.addExtensionConfiguration(extensionId, configuration);
+    }
+
     dispose() {
         this.config.dispose();
         this.statusBar.dispose();
@@ -230,7 +237,7 @@
                 debug: run,
             };
 
-            let rawInitializationOptions = vscode.workspace.getConfiguration("rust-analyzer");
+            let rawInitializationOptions = this.config.cfg;
 
             if (this.workspace.kind === "Detached Files") {
                 rawInitializationOptions = {
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 9962985..190f586 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -13,6 +13,12 @@
 export interface RustAnalyzerExtensionApi {
     // FIXME: this should be non-optional
     readonly client?: lc.LanguageClient;
+
+    // Allows adding a configuration override from another extension.
+    // `extensionId` is used to only merge configuration override from present
+    // extensions. `configuration` is map of rust-analyzer-specific setting
+    // overrides, e.g., `{"cargo.cfgs": ["foo", "bar"]}`.
+    addConfiguration(extensionId: string, configuration: Record<string, unknown>): Promise<void>;
 }
 
 export async function deactivate() {
diff --git a/rustfmt.toml b/rustfmt.toml
index 20bf595..3ee7fda 100644
--- a/rustfmt.toml
+++ b/rustfmt.toml
@@ -1,2 +1,3 @@
+edition = "2024"
 reorder_modules = true
 use_small_heuristics = "Max"
diff --git a/xtask/src/flags.rs b/xtask/src/flags.rs
index 72f6215..8f70a18 100644
--- a/xtask/src/flags.rs
+++ b/xtask/src/flags.rs
@@ -49,6 +49,9 @@
             /// build in release with debug info set to 2.
             optional --dev-rel
 
+            /// Make `never!()`, `always!()` etc. panic instead of just logging an error.
+            optional --force-always-assert
+
             /// Apply PGO optimizations
             optional --pgo pgo: PgoTrainingCrate
         }
@@ -124,6 +127,7 @@
     pub jemalloc: bool,
     pub proc_macro_server: bool,
     pub dev_rel: bool,
+    pub force_always_assert: bool,
     pub pgo: Option<PgoTrainingCrate>,
 }
 
@@ -300,7 +304,12 @@
         } else {
             Malloc::System
         };
-        Some(ServerOpt { malloc, dev_rel: self.dev_rel, pgo: self.pgo.clone() })
+        Some(ServerOpt {
+            malloc,
+            dev_rel: self.dev_rel,
+            pgo: self.pgo.clone(),
+            force_always_assert: self.force_always_assert,
+        })
     }
     pub(crate) fn proc_macro_server(&self) -> Option<ProcMacroServerOpt> {
         if !self.proc_macro_server {
diff --git a/xtask/src/install.rs b/xtask/src/install.rs
index b794f53..975e361 100644
--- a/xtask/src/install.rs
+++ b/xtask/src/install.rs
@@ -39,6 +39,18 @@
     pub(crate) malloc: Malloc,
     pub(crate) dev_rel: bool,
     pub(crate) pgo: Option<PgoTrainingCrate>,
+    pub(crate) force_always_assert: bool,
+}
+
+impl ServerOpt {
+    fn to_features(&self) -> Vec<&'static str> {
+        let mut features = Vec::new();
+        features.extend(self.malloc.to_features());
+        if self.force_always_assert {
+            features.extend(["--features", "force-always-assert"]);
+        }
+        features
+    }
 }
 
 pub(crate) struct ProcMacroServerOpt {
@@ -136,7 +148,7 @@
 }
 
 fn install_server(sh: &Shell, opts: ServerOpt) -> anyhow::Result<()> {
-    let features = opts.malloc.to_features();
+    let features = &opts.to_features();
     let profile = if opts.dev_rel { "dev-rel" } else { "release" };
 
     let mut install_cmd = cmd!(
@@ -148,7 +160,7 @@
         let target = detect_target(sh);
         let build_cmd = cmd!(
             sh,
-            "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target} --profile={profile} --locked --features force-always-assert {features...}"
+            "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target} --profile={profile} --locked {features...}"
         );
 
         let profile = crate::pgo::gather_pgo_profile(sh, build_cmd, &target, train_crate)?;
diff --git a/xtask/src/release.rs b/xtask/src/release.rs
index d06a25c..13cb44e 100644
--- a/xtask/src/release.rs
+++ b/xtask/src/release.rs
@@ -43,7 +43,7 @@
             .unwrap_or_default();
 
         let tags = cmd!(sh, "git tag --list").read()?;
-        let prev_tag = tags.lines().filter(|line| is_release_tag(line)).next_back().unwrap();
+        let prev_tag = tags.lines().rfind(|line| is_release_tag(line)).unwrap();
 
         let contents = changelog::get_changelog(sh, changelog_n, &commit, prev_tag, &today)?;
         let path = changelog_dir.join(format!("{today}-changelog-{changelog_n}.adoc"));
diff --git a/xtask/src/tidy.rs b/xtask/src/tidy.rs
index 0462835..40997eb 100644
--- a/xtask/src/tidy.rs
+++ b/xtask/src/tidy.rs
@@ -259,7 +259,7 @@
         }
 
         fn is_exclude_file(d: &Path) -> bool {
-            let file_names = ["tests.rs", "famous_defs_fixture.rs"];
+            let file_names = ["tests.rs", "famous_defs_fixture.rs", "frontmatter.rs"];
 
             d.file_name()
                 .unwrap_or_default()