Auto merge of #148040 - saethlin:trivial-consts, r=oli-obk

Add a fast path for lowering trivial consts

The objective of this PR is to improve compilation performance for crates that define a lot of trivial consts. This is a flamegraph of a build of a library crate that is just 100,000 trivial consts, taken from a nightly compiler:
<img width="842" height="280" alt="2025-10-25-164005_842x280_scrot" src="https://github.com/user-attachments/assets/e5400aaf-03bd-4461-b905-054aa82ca60f" />
My objective is to target all of the cycles in `eval_to_const_value_raw` that are not part of `mir_built`, because if you look at the `mir_built` for a trivial const, we already have the value available.

In this PR, the definition of a trivial const is this:
```rust
const A: usize = 0;
```
Specifically, we look for if the `mir_built` body is a single basic block containing one assign statement and a return terminator, where the assign statement assigns an `Operand::Constant(Const::Val)`. The MIR dumps for these look like:
```
const A: usize = {
    let mut _0: usize;

    bb0: {
        _0 = const 0_usize;
        return;
    }
}
```

The implementation is built around a new query, `trivial_const(LocalDefId) -> Option<(ConstValue, Ty)>` which returns the contents of the `Const::Val` in the `mir_built` if the `LocalDefId` is a trivial const.

Then I added _debug_ assertions to the beginning of `mir_for_ctfe` and `mir_promoted` to prevent trying to get the body of a trivial const, because that would defeat the optimization here. But these are deliberately _debug_ assertions because the consequence of failing the assertion is that compilation is slow, not corrupt. If we made these hard assertions, I'm sure there are obscure scenarios people will run into where the compiler would ICE instead of continuing on compilation, just a bit slower. I'd like to know about those, but I do not think serving up an ICE is worth it.

With the assertions in place, I just added logic around all the places they were hit, to skip over trying to analyze the bodies of trivial consts.

In the future, I'd like to see this work extended by:
* Pushing detection of trivial consts before MIR building
* Including DefKind::Static and DefKind::InlineConst
* Including consts like `_1 = const 0_usize; _0 = &_1`, which would make a lot of promoteds into trivial consts
* Handling less-trivial consts like `const A: usize = B`, which have `Operand::Constant(Const::Unevaluated)`
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()