Migrate `Display` impls to the next solver
diff --git a/crates/hir-ty/src/builder.rs b/crates/hir-ty/src/builder.rs
index 706bbe8..5c4eb84 100644
--- a/crates/hir-ty/src/builder.rs
+++ b/crates/hir-ty/src/builder.rs
@@ -1,15 +1,14 @@
 //! `TyBuilder`, a helper for building instances of `Ty` and related types.
 
 use chalk_ir::{
-    AdtId, DebruijnIndex, Scalar,
-    cast::{Cast, CastTo, Caster},
+    DebruijnIndex, Scalar,
+    cast::{Cast, Caster},
 };
-use hir_def::{GenericDefId, GenericParamId, TraitId, TypeAliasId, builtin_type::BuiltinType};
+use hir_def::{GenericDefId, GenericParamId, TraitId, builtin_type::BuiltinType};
 use smallvec::SmallVec;
 
 use crate::{
-    BoundVar, CallableSig, GenericArg, GenericArgData, Interner, ProjectionTy, Substitution,
-    TraitRef, Ty, TyDefId, TyExt, TyKind,
+    BoundVar, GenericArg, GenericArgData, Interner, Substitution, TraitRef, Ty, TyKind,
     consteval::unknown_const_as_generic,
     db::HirDatabase,
     error_lifetime,
@@ -19,18 +18,18 @@
         DbInterner, EarlyBinder,
         mapping::{ChalkToNextSolver, NextSolverToChalk},
     },
-    primitive, to_assoc_type_id, to_chalk_trait_id,
+    primitive, to_chalk_trait_id,
 };
 
 #[derive(Debug, Clone, PartialEq, Eq)]
-pub enum ParamKind {
+pub(crate) enum ParamKind {
     Type,
     Lifetime,
     Const(Ty),
 }
 
 /// This is a builder for `Ty` or anything that needs a `Substitution`.
-pub struct TyBuilder<D> {
+pub(crate) struct TyBuilder<D> {
     /// The `data` field is used to keep track of what we're building (e.g. an
     /// ADT, a `TraitRef`, ...).
     data: D,
@@ -60,10 +59,6 @@
         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(),
@@ -83,35 +78,15 @@
         (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 {
+    pub(crate) fn remaining(&self) -> usize {
         self.param_kinds.len() - self.vec.len()
     }
 
-    pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self {
+    pub(crate) 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()..];
@@ -129,22 +104,6 @@
         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| {
@@ -157,7 +116,7 @@
         })
     }
 
-    pub fn fill(mut self, filler: impl FnMut(&ParamKind) -> GenericArg) -> Self {
+    pub(crate) 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
@@ -174,28 +133,11 @@
 }
 
 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 {
+    pub(crate) 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 {
+    pub(crate) fn builtin(builtin: BuiltinType) -> Ty {
         match builtin {
             BuiltinType::Char => TyKind::Scalar(Scalar::Char).intern(Interner),
             BuiltinType::Bool => TyKind::Scalar(Scalar::Bool).intern(Interner),
@@ -212,16 +154,10 @@
         }
     }
 
-    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 {
+    pub(crate) fn unknown_subst(
+        db: &dyn HirDatabase,
+        def: impl Into<GenericDefId>,
+    ) -> Substitution {
         let interner = DbInterner::conjure();
         let params = generics(db, def.into());
         Substitution::from_iter(
@@ -239,7 +175,7 @@
     }
 
     #[tracing::instrument(skip_all)]
-    pub fn subst_for_def(
+    pub(crate) fn subst_for_def(
         db: &dyn HirDatabase,
         def: impl Into<GenericDefId>,
         parent_subst: Option<Substitution>,
@@ -257,114 +193,25 @@
         TyBuilder::new((), params, parent_subst)
     }
 
-    pub fn build(self) -> Substitution {
+    pub(crate) 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> {
+    pub(crate) 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 {
+    pub(crate) 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 {
+    pub(crate) 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)
@@ -372,24 +219,7 @@
 }
 
 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(
+    pub(crate) fn impl_self_ty(
         db: &'db dyn HirDatabase,
         def: hir_def::ImplId,
     ) -> TyBuilder<EarlyBinder<'db, crate::next_solver::Ty<'db>>> {
diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs
index 6bab30b..a315f69 100644
--- a/crates/hir-ty/src/chalk_ext.rs
+++ b/crates/hir-ty/src/chalk_ext.rs
@@ -3,47 +3,11 @@
 use hir_def::{ItemContainerId, Lookup, TraitId};
 
 use crate::{
-    Binders, CallableSig, DynTy, Interner, ProjectionTy, Substitution, TraitRef, Ty, TyKind,
-    db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, generics::generics,
-    to_chalk_trait_id, utils::ClosureSubst,
+    Binders, DynTy, Interner, ProjectionTy, Substitution, TraitRef, Ty, db::HirDatabase,
+    from_assoc_type_id, from_chalk_trait_id, generics::generics, to_chalk_trait_id,
 };
 
-pub(crate) trait TyExt {
-    fn is_unit(&self) -> bool;
-    fn is_unknown(&self) -> bool;
-
-    fn as_tuple(&self) -> Option<&Substitution>;
-
-    fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig>;
-}
-
-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 as_tuple(&self) -> Option<&Substitution> {
-        match self.kind(Interner) {
-            TyKind::Tuple(_, substs) => Some(substs),
-            _ => 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,
-        }
-    }
-}
-
-pub trait ProjectionTyExt {
+pub(crate) 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;
@@ -88,7 +52,7 @@
     }
 }
 
-pub trait TraitRefExt {
+pub(crate) trait TraitRefExt {
     fn hir_trait_id(&self) -> TraitId;
 }
 
diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs
index 80945ad..7ad76f3 100644
--- a/crates/hir-ty/src/db.rs
+++ b/crates/hir-ty/src/db.rs
@@ -24,7 +24,6 @@
     lower::{Diagnostics, GenericDefaults, GenericPredicates},
     method_resolution::{InherentImpls, TraitImpls, TyFingerprint},
     mir::{BorrowckResult, MirBody, MirLowerError},
-    traits::NextTraitSolveResult,
 };
 
 #[query_group::query_group]
diff --git a/crates/hir-ty/src/diagnostics/match_check.rs b/crates/hir-ty/src/diagnostics/match_check.rs
index af6795e..80b65ac 100644
--- a/crates/hir-ty/src/diagnostics/match_check.rs
+++ b/crates/hir-ty/src/diagnostics/match_check.rs
@@ -18,7 +18,7 @@
 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::{
     InferenceResult,
@@ -299,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, "!"),
@@ -356,7 +356,7 @@
                             .filter(|p| !matches!(*p.pattern.kind, PatKind::Wild))
                             .map(|p| {
                                 printed += 1;
-                                WriteWith(|f| {
+                                WriteWith::new(|f| {
                                     write!(
                                         f,
                                         "{}: ",
@@ -382,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
@@ -420,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/display.rs b/crates/hir-ty/src/display.rs
index bcd93c6..210e1ac 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, CoroutineArgsParts, 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,
+    CallableDefId, FnAbi, ImplTraitId, MemoryMap, TraitEnvironment, consteval,
     db::{HirDatabase, InternedClosure},
-    from_assoc_type_id, from_placeholder_idx,
     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},
+        mapping::ChalkToNextSolver,
     },
-    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,146 @@
 
 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_ns(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(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::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 +752,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 +763,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 +820,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 +838,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 +868,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 +889,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(")")
         }
@@ -972,7 +902,7 @@
                 hir_def::AdtId::StructId(s) => {
                     let data = f.db.struct_signature(s);
                     write!(f, "{}", data.name.display(f.db, f.edition()))?;
-                    let field_types = f.db.field_types(s.into());
+                    let field_types = f.db.field_types_ns(s.into());
                     render_variant_after_name(
                         s.fields(f.db),
                         f,
@@ -1004,7 +934,7 @@
                             .1
                             .display(f.db, f.edition())
                     )?;
-                    let field_types = f.db.field_types(var_id.into());
+                    let field_types = f.db.field_types_ns(var_id.into());
                     render_variant_after_name(
                         var_id.fields(f.db),
                         f,
@@ -1041,7 +971,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 +997,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,33 +1046,17 @@
     }
 }
 
-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")?,
@@ -1164,14 +1074,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 +1100,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 {
@@ -1225,28 +1121,25 @@
                         let impl_trait_id = db.lookup_intern_impl_trait_id(opaque_ty_id);
                         if let ImplTraitId::ReturnTypeImplTrait(func, idx) = impl_trait_id {
                             let datas = db
-                                .return_type_impl_traits(func)
+                                .return_type_impl_traits_ns(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.to_nextsolver(interner)].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 +1152,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 +1192,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 +1236,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 +1286,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 +1331,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 +1345,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,
@@ -1475,32 +1353,41 @@
                 let impl_trait_id = db.lookup_intern_impl_trait_id(opaque_ty_id);
                 match impl_trait_id {
                     ImplTraitId::ReturnTypeImplTrait(func, idx) => {
-                        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, ¶meters);
+                        let datas = db
+                            .return_type_impl_traits_ns(func)
+                            .expect("impl trait id without data");
+                        let data = (*datas).as_ref().map_bound(|rpit| {
+                            &rpit.impl_traits[idx.to_nextsolver(interner)].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
                     }
                     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, ¶meters);
+                        let datas = db
+                            .type_alias_impl_traits_ns(alias)
+                            .expect("impl trait id without data");
+                        let data = (*datas).as_ref().map_bound(|rpit| {
+                            &rpit.impl_traits[idx.to_nextsolver(interner)].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 },
                         )?;
                     }
@@ -1528,14 +1415,13 @@
                             f.end_location_link();
                         }
                         write!(f, " = ")?;
-                        parameters.at(Interner, 0).hir_fmt(f)?;
+                        alias_ty.args.type_at(0).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(
@@ -1556,12 +1442,16 @@
                     }
                     ClosureStyle::ClosureWithSubst => {
                         write!(f, "{{closure#{:?}}}", salsa::plumbing::AsId::as_id(&id).index())?;
-                        return hir_fmt_generics(f, substs.as_slice(Interner), None, None);
+                        return hir_fmt_generics(f, substs.as_slice(), None, None);
                     }
                     _ => (),
                 }
-                let sig = ClosureSubst(&substs).sig_ty(db).callable_sig(db);
+                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);
@@ -1570,22 +1460,22 @@
                         ClosureStyle::RANotation => write!(f, "|")?,
                         _ => unreachable!(),
                     }
-                    if sig.params().is_empty() {
+                    if sig.inputs().is_empty() {
                     } else if f.should_truncate() {
                         write!(f, "{TYPE_HINT_TRUNCATION}")?;
                     } else {
-                        f.write_joined(sig.params(), ", ")?;
+                        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.ret().is_unit() {
+                    if f.closure_style == ClosureStyle::RANotation || !sig.output().is_unit() {
                         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)?;
+                        sig.output().hir_fmt(f)?;
                     }
                 } else {
                     write!(f, "{{closure}}")?;
@@ -1593,6 +1483,8 @@
             }
             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 {
@@ -1608,35 +1500,23 @@
                             )?
                         }
                         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,
+                                .generic_predicates_ns(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(&convert_ty_for_result(interner, *self)),
+                                Either::Left(*self),
                                 &bounds,
                                 SizedByDefault::Sized { anchor: krate },
                             )?;
@@ -1647,42 +1527,34 @@
                     }
                 }
             }
-            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::Bound(debruijn, ty) => {
+                write!(f, "?{}.{}", debruijn.as_usize(), ty.var.as_usize())?
             }
-            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);
+            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_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(),
-                        }),
-                    ));
+                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(&ty),
-                    &bounds,
+                    Either::Left(*self),
+                    &bounds_to_display,
                     SizedByDefault::NotSized,
                 )?;
             }
@@ -1722,11 +1594,11 @@
     }
 }
 
-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 +1615,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_ns(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, ¶meters[..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, ¶meters[..i])
                     }
                 };
                 let mut default_from = 0;
-                for (i, parameter) in parameters.iter().enumerate() {
+                for (i, ¶meter) in parameters.iter().enumerate() {
                     if should_show(parameter, i) {
                         default_from = i + 1;
                     }
@@ -1820,114 +1645,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, ¶meters[..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;
-                    }
-                }
-                ¶meters[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 +1689,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 +1721,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 +1739,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 +1771,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 +1789,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 +1805,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 +1833,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 +1864,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 +1874,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 +1892,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 +1937,49 @@
     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(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::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 +2001,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 +2036,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 +2064,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 +2193,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 +2206,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 +2250,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 +2402,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/generics.rs b/crates/hir-ty/src/generics.rs
index e179e41..2053a09 100644
--- a/crates/hir-ty/src/generics.rs
+++ b/crates/hir-ty/src/generics.rs
@@ -130,11 +130,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()
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 7249868..041799b 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -55,8 +55,7 @@
 use triomphe::Arc;
 
 use crate::{
-    ImplTraitId, IncorrectGenericsLenKind, Interner, PathLoweringDiagnostic, TargetFeatures,
-    TraitEnvironment,
+    ImplTraitId, IncorrectGenericsLenKind, PathLoweringDiagnostic, TargetFeatures,
     db::{HirDatabase, InternedClosureId, InternedOpaqueTyId},
     generics::Generics,
     infer::{
@@ -77,7 +76,7 @@
             DefineOpaqueTypes,
             traits::{Obligation, ObligationCause},
         },
-        mapping::{ChalkToNextSolver, NextSolverToChalk},
+        mapping::ChalkToNextSolver,
     },
     traits::FnTrait,
     utils::TargetFeatureIsSafeInTarget,
@@ -166,31 +165,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)]
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index eb01ef1..7277617 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -81,22 +81,17 @@
 use traits::FnTrait;
 use triomphe::Arc;
 
-#[cfg(not(debug_assertions))]
-use crate::next_solver::ErrorGuaranteed;
 use crate::{
+    builder::{ParamKind, TyBuilder},
+    chalk_ext::*,
     db::HirDatabase,
     display::{DisplayTarget, HirDisplay},
     generics::Generics,
     infer::unify::InferenceTable,
-    next_solver::{
-        DbInterner,
-        mapping::{ChalkToNextSolver, NextSolverToChalk, convert_ty_for_result},
-    },
+    next_solver::DbInterner,
 };
 
 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,
@@ -156,7 +151,6 @@
 
 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
@@ -174,7 +168,6 @@
 
 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>;
@@ -382,7 +375,7 @@
 /// A function signature as seen by type inference: Several parameter types and
 /// one return type.
 #[derive(Clone, PartialEq, Eq, Debug)]
-pub struct CallableSig {
+pub(crate) struct CallableSig {
     params_and_return: Arc<[Ty]>,
     is_varargs: bool,
     safety: Safety,
@@ -534,112 +527,6 @@
     }
 }
 
-/// 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.
@@ -764,7 +651,12 @@
             #[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(crate::next_solver::Ty::new_error(
+                    self.interner,
+                    crate::next_solver::ErrorGuaranteed,
+                ))
+            };
 
             match t.kind() {
                 crate::next_solver::TyKind::Error(_) => {
diff --git a/crates/hir-ty/src/lower_nextsolver.rs b/crates/hir-ty/src/lower_nextsolver.rs
index abca6b6..aced46b 100644
--- a/crates/hir-ty/src/lower_nextsolver.rs
+++ b/crates/hir-ty/src/lower_nextsolver.rs
@@ -17,17 +17,20 @@
 
 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,
+    AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumVariantId,
+    FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
+    LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId,
+    TypeParamId, VariantId,
     expr_store::{
         ExpressionStore,
         path::{GenericArg, Path},
     },
-    hir::generics::{TypeOrConstParamData, WherePredicate},
+    hir::generics::{
+        GenericParamDataRef, TypeOrConstParamData, TypeParamData, TypeParamProvenance,
+        WherePredicate,
+    },
+    item_tree::FieldsShape,
     lang_item::LangItem,
     resolver::{HasResolver, LifetimeNs, Resolver, TypeNs},
     signatures::{FunctionSignature, TraitFlags, TypeAliasFlags},
@@ -36,7 +39,6 @@
         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};
@@ -48,20 +50,17 @@
     AliasTyKind, ConstKind, DebruijnIndex, ExistentialPredicate, ExistentialProjection,
     ExistentialTraitRef, FnSig, OutlivesPredicate,
     TyKind::{self},
-    TypeVisitableExt,
+    TypeFoldable, TypeFolder, TypeVisitableExt, Upcast,
     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,
+    TyLoweringDiagnosticKind, ValueTyDefId,
     consteval::{intern_const_ref, path_to_const, unknown_const_as_generic},
     db::HirDatabase,
     generics::{Generics, generics, trait_self_param_idx},
@@ -69,8 +68,8 @@
     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,
+        EarlyParamRegion, ErrorGuaranteed, GenericArgs, ParamConst, ParamEnv, PolyFnSig, Predicate,
+        Region, SolverDefId, TraitPredicate, TraitRef, Ty, Tys,
         abi::Safety,
         mapping::{ChalkToNextSolver, convert_ty_for_result},
     },
@@ -187,8 +186,9 @@
     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,
+    /// 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, 'a> TyLoweringContext<'db, 'a> {
@@ -213,7 +213,7 @@
             unsized_types: FxHashSet::default(),
             diagnostics: Vec::new(),
             lifetime_elision,
-            disallow_params_after: u32::MAX,
+            lowering_param_default: None,
         }
     }
 
@@ -249,8 +249,8 @@
         self
     }
 
-    pub(crate) fn disallow_params_after(&mut self, after: u32) {
-        self.disallow_params_after = after;
+    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) {
@@ -333,8 +333,13 @@
         self.generics.get_or_init(|| generics(self.db, self.def))
     }
 
+    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, name: Symbol) -> Ty<'db> {
-        if index >= self.disallow_params_after {
+        if self.param_index_is_disallowed(index) {
             // FIXME: Report an error.
             Ty::new_error(self.interner, ErrorGuaranteed)
         } else {
@@ -343,7 +348,7 @@
     }
 
     fn const_param(&mut self, id: ConstParamId, index: u32) -> Const<'db> {
-        if index >= self.disallow_params_after {
+        if self.param_index_is_disallowed(index) {
             // FIXME: Report an error.
             Const::error(self.interner)
         } else {
@@ -352,7 +357,7 @@
     }
 
     fn region_param(&mut self, id: LifetimeParamId, index: u32) -> Region<'db> {
-        if index >= self.disallow_params_after {
+        if self.param_index_is_disallowed(index) {
             // FIXME: Report an error.
             Region::error(self.interner)
         } else {
@@ -394,7 +399,7 @@
                     type_data
                         .name
                         .as_ref()
-                        .map_or_else(|| sym::MISSING_NAME.clone(), |d| d.symbol().clone()),
+                        .map_or_else(|| sym::MISSING_NAME, |d| d.symbol().clone()),
                 )
             }
             &TypeRef::RawPtr(inner, mutability) => {
@@ -1603,8 +1608,6 @@
         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,
@@ -1619,49 +1622,53 @@
 
     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(¶m_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);
-                }
+        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;
             }
 
-            if let Some(g) = generics.parent {
-                generics = crate::next_solver::generics::generics(db, g.into());
-                def_id = g;
-            } else {
-                break;
+            let param_name = param_data
+                .name
+                .as_ref()
+                .map_or_else(|| sym::MISSING_NAME, |name| name.symbol().clone());
+            let param_ty = Ty::new_param(interner, param_id, param_idx, param_name);
+            if explicitly_unsized_tys.contains(¶m_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);
+            });
         }
     }
 
@@ -1860,10 +1867,7 @@
         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);
+        ctx.lowering_param_default(idx as u32);
         match p {
             GenericParamDataRef::TypeParamData(p) => {
                 let ty = p.default.map(|ty| ctx.lower_ty(ty));
diff --git a/crates/hir-ty/src/lower_nextsolver/path.rs b/crates/hir-ty/src/lower_nextsolver/path.rs
index ef2c392..6bfe266 100644
--- a/crates/hir-ty/src/lower_nextsolver/path.rs
+++ b/crates/hir-ty/src/lower_nextsolver/path.rs
@@ -314,7 +314,9 @@
         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();
@@ -333,7 +335,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)
@@ -346,6 +354,8 @@
             | TypeNs::TypeAliasId(_)
             | TypeNs::TraitId(_) => {}
         }
+
+        true
     }
 
     pub(crate) fn resolve_path_in_type_ns_fully(&mut self) -> Option<TypeNs> {
@@ -379,11 +389,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 {
@@ -403,7 +408,9 @@
             });
         }
 
-        self.handle_type_ns_resolution(&resolution);
+        if !self.handle_type_ns_resolution(&resolution) {
+            return None;
+        }
 
         Some((resolution, remaining_index))
     }
@@ -475,7 +482,7 @@
 
                 match resolution {
                     ValueNs::ImplSelf(_) => {
-                        prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy)
+                        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
@@ -499,7 +506,9 @@
                 }
             }
             ResolveValueResult::Partial(resolution, _, _) => {
-                self.handle_type_ns_resolution(resolution);
+                if !self.handle_type_ns_resolution(resolution) {
+                    return None;
+                }
             }
         };
         Some(res)
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/consts.rs b/crates/hir-ty/src/next_solver/consts.rs
index 2fc1fc4..c5a1e7d 100644
--- a/crates/hir-ty/src/next_solver/consts.rs
+++ b/crates/hir-ty/src/next_solver/consts.rs
@@ -82,7 +82,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 {
diff --git a/crates/hir-ty/src/next_solver/predicate.rs b/crates/hir-ty/src/next_solver/predicate.rs
index 9dda9d0..6a0a077 100644
--- a/crates/hir-ty/src/next_solver/predicate.rs
+++ b/crates/hir-ty/src/next_solver/predicate.rs
@@ -647,6 +647,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/traits.rs b/crates/hir-ty/src/traits.rs
index cd125f3..35c8a19 100644
--- a/crates/hir-ty/src/traits.rs
+++ b/crates/hir-ty/src/traits.rs
@@ -12,22 +12,20 @@
 use rustc_next_trait_solver::solve::{HasChanged, SolverDelegateEvalExt};
 use rustc_type_ir::{
     InferCtxtLike, TypingMode,
-    inherent::{IntoKind, SliceLike, Span as _, Ty as _},
+    inherent::{IntoKind, SliceLike, 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,
+    AliasEq, AliasTy, Canonical, DomainGoal, Goal, InEnvironment, Interner, ProjectionTyExt,
+    TraitRefExt, TyKind, WhereClause,
     db::HirDatabase,
-    from_assoc_type_id,
     next_solver::{
         DbInterner, GenericArg, ParamEnv, Predicate, SolverContext, Span,
         infer::{DbInternerInferExt, InferCtxt, traits::ObligationCause},
-        mapping::{ChalkToNextSolver, NextSolverToChalk, convert_canonical_args_for_result},
+        mapping::{ChalkToNextSolver, convert_canonical_args_for_result},
         obligation_ctxt::ObligationCtxt,
         util::mini_canonicalize,
     },
@@ -94,47 +92,6 @@
     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>> {
@@ -165,45 +122,6 @@
     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,
diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs
index e989e4c..1535992 100644
--- a/crates/hir-ty/src/utils.rs
+++ b/crates/hir-ty/src/utils.rs
@@ -25,8 +25,7 @@
 use span::Edition;
 
 use crate::{
-    ChalkTraitId, Const, ConstScalar, Interner, Substitution, TargetFeatures, TraitRef,
-    TraitRefExt, Ty,
+    ChalkTraitId, Const, ConstScalar, Interner, TargetFeatures, TraitRef, TraitRefExt,
     consteval::unknown_const,
     db::HirDatabase,
     layout::{Layout, TagEncoding},
@@ -192,19 +191,6 @@
     })
 }
 
-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,
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index 49bf843..b31bb24 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 = ¶ms[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 predicates = f.db.generic_predicates(self.id.parent());
+        let ty = self.ty(f.db).ty;
+        let predicates = f.db.generic_predicates_ns(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, ¶ms, &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/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index df18006..6c4a074 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -9392,7 +9392,7 @@
             *a*
 
             ```rust
-            a: T
+            a: T<T>
             ```
 
             ---
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..93090e2 100644
--- a/crates/ide/src/navigation_target.rs
+++ b/crates/ide/src/navigation_target.rs
@@ -382,7 +382,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(