about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_errors/src/diagnostic_impls.rs6
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs18
-rw-r--r--compiler/rustc_middle/src/ty/consts/kind.rs30
-rw-r--r--compiler/rustc_middle/src/ty/context.rs76
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs16
-rw-r--r--compiler/rustc_middle/src/ty/predicate.rs1
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs54
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs36
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs388
-rw-r--r--compiler/rustc_type_ir/src/const_kind.rs41
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs29
-rw-r--r--compiler/rustc_type_ir/src/interner.rs25
-rw-r--r--compiler/rustc_type_ir/src/ir_print.rs6
-rw-r--r--compiler/rustc_type_ir/src/predicate.rs234
-rw-r--r--compiler/rustc_type_ir/src/ty_kind.rs158
15 files changed, 584 insertions, 534 deletions
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index 2cc0167dbaa..d9add1c9b3b 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -106,6 +106,12 @@ impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::ExistentialTrait
     }
 }
 
+impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::UnevaluatedConst<I> {
+    fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
+        format!("{self:?}").into_diag_arg()
+    }
+}
+
 into_diag_arg_for_number!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize);
 
 impl IntoDiagArg for bool {
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 329d5f34a21..27a4abaa0b6 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -7,8 +7,7 @@ use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::LocalDefId;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable};
-use rustc_type_ir::ConstKind as IrConstKind;
-use rustc_type_ir::{TypeFlags, WithCachedTypeInfo};
+use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
 
 mod int;
 mod kind;
@@ -20,7 +19,8 @@ use rustc_span::Span;
 use rustc_span::DUMMY_SP;
 pub use valtree::*;
 
-pub type ConstKind<'tcx> = IrConstKind<TyCtxt<'tcx>>;
+pub type ConstKind<'tcx> = ir::ConstKind<TyCtxt<'tcx>>;
+pub type UnevaluatedConst<'tcx> = ir::UnevaluatedConst<TyCtxt<'tcx>>;
 
 #[cfg(target_pointer_width = "64")]
 rustc_data_structures::static_assert_size!(ConstKind<'_>, 32);
@@ -184,9 +184,21 @@ impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
         Const::new_bound(tcx, debruijn, var, ty)
     }
 
+    fn new_unevaluated(
+        interner: TyCtxt<'tcx>,
+        uv: ty::UnevaluatedConst<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> Self {
+        Const::new_unevaluated(interner, uv, ty)
+    }
+
     fn ty(self) -> Ty<'tcx> {
         self.ty()
     }
+
+    fn into_term(self) -> ty::Term<'tcx> {
+        self.into()
+    }
 }
 
 impl<'tcx> Const<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index 7e49b0ac915..d7ae050ed4d 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -1,30 +1,15 @@
 use super::Const;
 use crate::mir;
 use crate::ty::abstract_const::CastKind;
-use crate::ty::GenericArgsRef;
 use crate::ty::{self, visit::TypeVisitableExt as _, List, Ty, TyCtxt};
-use rustc_hir::def_id::DefId;
-use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
+use rustc_macros::{extension, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
 
-/// An unevaluated (potentially generic) constant used in the type-system.
-#[derive(Copy, Clone, Eq, PartialEq, TyEncodable, TyDecodable)]
-#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
-pub struct UnevaluatedConst<'tcx> {
-    pub def: DefId,
-    pub args: GenericArgsRef<'tcx>,
-}
-
-impl rustc_errors::IntoDiagArg for UnevaluatedConst<'_> {
-    fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
-        format!("{self:?}").into_diag_arg()
-    }
-}
-
-impl<'tcx> UnevaluatedConst<'tcx> {
+#[extension(pub(crate) trait UnevaluatedConstEvalExt<'tcx>)]
+impl<'tcx> ty::UnevaluatedConst<'tcx> {
     /// FIXME(RalfJung): I cannot explain what this does or why it makes sense, but not doing this
     /// hurts performance.
     #[inline]
-    pub(crate) fn prepare_for_eval(
+    fn prepare_for_eval(
         self,
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
@@ -55,13 +40,6 @@ impl<'tcx> UnevaluatedConst<'tcx> {
     }
 }
 
-impl<'tcx> UnevaluatedConst<'tcx> {
-    #[inline]
-    pub fn new(def: DefId, args: GenericArgsRef<'tcx>) -> UnevaluatedConst<'tcx> {
-        UnevaluatedConst { def, args }
-    }
-}
-
 #[derive(Copy, Clone, Eq, PartialEq, Hash)]
 #[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
 pub enum Expr<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index e831db1a41b..d7e185dd5e1 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -76,6 +76,7 @@ use rustc_type_ir::TyKind::*;
 use rustc_type_ir::WithCachedTypeInfo;
 use rustc_type_ir::{CollectAndApply, Interner, TypeFlags};
 
+use std::assert_matches::assert_matches;
 use std::borrow::Borrow;
 use std::cmp::Ordering;
 use std::fmt;
@@ -91,67 +92,124 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     type DefiningOpaqueTypes = &'tcx ty::List<LocalDefId>;
     type AdtDef = ty::AdtDef<'tcx>;
     type GenericArgs = ty::GenericArgsRef<'tcx>;
+    type GenericArgsSlice = &'tcx [ty::GenericArg<'tcx>];
     type GenericArg = ty::GenericArg<'tcx>;
-    type Term = ty::Term<'tcx>;
 
+    type Term = ty::Term<'tcx>;
     type Binder<T: TypeVisitable<TyCtxt<'tcx>>> = Binder<'tcx, T>;
     type BoundVars = &'tcx List<ty::BoundVariableKind>;
     type BoundVar = ty::BoundVariableKind;
-    type CanonicalVars = CanonicalVarInfos<'tcx>;
 
+    type CanonicalVars = CanonicalVarInfos<'tcx>;
     type Ty = Ty<'tcx>;
     type Tys = &'tcx List<Ty<'tcx>>;
-    type AliasTy = ty::AliasTy<'tcx>;
     type ParamTy = ParamTy;
     type BoundTy = ty::BoundTy;
     type PlaceholderTy = ty::PlaceholderType;
-    type ErrorGuaranteed = ErrorGuaranteed;
 
+    type ErrorGuaranteed = ErrorGuaranteed;
     type BoundExistentialPredicates = &'tcx List<PolyExistentialPredicate<'tcx>>;
     type PolyFnSig = PolyFnSig<'tcx>;
     type AllocId = crate::mir::interpret::AllocId;
-    type Pat = Pattern<'tcx>;
 
+    type Pat = Pattern<'tcx>;
     type Const = ty::Const<'tcx>;
     type AliasConst = ty::UnevaluatedConst<'tcx>;
     type PlaceholderConst = ty::PlaceholderConst;
     type ParamConst = ty::ParamConst;
     type BoundConst = ty::BoundVar;
     type ValueConst = ty::ValTree<'tcx>;
-    type ExprConst = ty::Expr<'tcx>;
 
+    type ExprConst = ty::Expr<'tcx>;
     type Region = Region<'tcx>;
     type EarlyParamRegion = ty::EarlyParamRegion;
     type LateParamRegion = ty::LateParamRegion;
     type BoundRegion = ty::BoundRegion;
     type InferRegion = ty::RegionVid;
-    type PlaceholderRegion = ty::PlaceholderRegion;
 
+    type PlaceholderRegion = ty::PlaceholderRegion;
     type Predicate = Predicate<'tcx>;
     type TraitPredicate = ty::TraitPredicate<'tcx>;
     type RegionOutlivesPredicate = ty::RegionOutlivesPredicate<'tcx>;
     type TypeOutlivesPredicate = ty::TypeOutlivesPredicate<'tcx>;
     type ProjectionPredicate = ty::ProjectionPredicate<'tcx>;
-    type AliasTerm = ty::AliasTerm<'tcx>;
     type NormalizesTo = ty::NormalizesTo<'tcx>;
     type SubtypePredicate = ty::SubtypePredicate<'tcx>;
     type CoercePredicate = ty::CoercePredicate<'tcx>;
     type ClosureKind = ty::ClosureKind;
-    type Clauses = ty::Clauses<'tcx>;
 
+    type Clauses = ty::Clauses<'tcx>;
     fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars {
         self.mk_canonical_var_infos(infos)
     }
 
     type GenericsOf = &'tcx ty::Generics;
+
     fn generics_of(self, def_id: DefId) -> &'tcx ty::Generics {
         self.generics_of(def_id)
     }
 
+    fn type_of_instantiated(self, def_id: DefId, args: ty::GenericArgsRef<'tcx>) -> Ty<'tcx> {
+        self.type_of(def_id).instantiate(self, args)
+    }
+
+    fn alias_ty_kind(self, alias: ty::AliasTy<'tcx>) -> ty::AliasTyKind {
+        match self.def_kind(alias.def_id) {
+            DefKind::AssocTy => {
+                if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id))
+                {
+                    ty::Inherent
+                } else {
+                    ty::Projection
+                }
+            }
+            DefKind::OpaqueTy => ty::Opaque,
+            DefKind::TyAlias => ty::Weak,
+            kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
+        }
+    }
+
+    fn alias_term_kind(self, alias: ty::AliasTerm<'tcx>) -> ty::AliasTermKind {
+        match self.def_kind(alias.def_id) {
+            DefKind::AssocTy => {
+                if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id))
+                {
+                    ty::AliasTermKind::InherentTy
+                } else {
+                    ty::AliasTermKind::ProjectionTy
+                }
+            }
+            DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy,
+            DefKind::TyAlias => ty::AliasTermKind::WeakTy,
+            DefKind::AssocConst => ty::AliasTermKind::ProjectionConst,
+            DefKind::AnonConst => ty::AliasTermKind::UnevaluatedConst,
+            kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
+        }
+    }
+
+    fn trait_ref_and_own_args_for_alias(
+        self,
+        def_id: Self::DefId,
+        args: Self::GenericArgs,
+    ) -> (rustc_type_ir::TraitRef<Self>, Self::GenericArgsSlice) {
+        assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::AssocConst);
+        let trait_def_id = self.parent(def_id);
+        assert_matches!(self.def_kind(trait_def_id), DefKind::Trait);
+        let trait_generics = self.generics_of(trait_def_id);
+        (
+            ty::TraitRef::new(self, trait_def_id, args.truncate_to(self, trait_generics)),
+            &args[trait_generics.count()..],
+        )
+    }
+
     fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs {
         self.mk_args(args)
     }
 
+    fn mk_args_from_iter(self, args: impl Iterator<Item = Self::GenericArg>) -> Self::GenericArgs {
+        self.mk_args_from_iter(args)
+    }
+
     fn check_and_mk_args(
         self,
         def_id: DefId,
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index dc5e881843a..93ccc0a7de4 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -96,9 +96,9 @@ pub use self::list::{List, ListWithCachedTypeInfo};
 pub use self::parameterized::ParameterizedOverTcx;
 pub use self::pattern::{Pattern, PatternKind};
 pub use self::predicate::{
-    Clause, ClauseKind, CoercePredicate, ExistentialPredicate, ExistentialPredicateStableCmpExt,
-    ExistentialProjection, ExistentialTraitRef, NormalizesTo, OutlivesPredicate,
-    PolyCoercePredicate, PolyExistentialPredicate, PolyExistentialProjection,
+    AliasTerm, Clause, ClauseKind, CoercePredicate, ExistentialPredicate,
+    ExistentialPredicateStableCmpExt, ExistentialProjection, ExistentialTraitRef, NormalizesTo,
+    OutlivesPredicate, PolyCoercePredicate, PolyExistentialPredicate, PolyExistentialProjection,
     PolyExistentialTraitRef, PolyProjectionPredicate, PolyRegionOutlivesPredicate,
     PolySubtypePredicate, PolyTraitPredicate, PolyTraitRef, PolyTypeOutlivesPredicate, Predicate,
     PredicateKind, ProjectionPredicate, RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef,
@@ -110,11 +110,11 @@ pub use self::region::{
 };
 pub use self::rvalue_scopes::RvalueScopes;
 pub use self::sty::{
-    AliasTerm, AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind,
-    CanonicalPolyFnSig, ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts,
-    CoroutineClosureArgs, CoroutineClosureArgsParts, CoroutineClosureSignature, FnSig, GenSig,
-    InlineConstArgs, InlineConstArgsParts, ParamConst, ParamTy, PolyFnSig, TyKind, TypeAndMut,
-    UpvarArgs, VarianceDiagInfo,
+    AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig,
+    ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, CoroutineClosureArgs,
+    CoroutineClosureArgsParts, CoroutineClosureSignature, FnSig, GenSig, InlineConstArgs,
+    InlineConstArgsParts, ParamConst, ParamTy, PolyFnSig, TyKind, TypeAndMut, UpvarArgs,
+    VarianceDiagInfo,
 };
 pub use self::trait_def::TraitDef;
 pub use self::typeck_results::{
diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs
index e78856517b2..16ca098853e 100644
--- a/compiler/rustc_middle/src/ty/predicate.rs
+++ b/compiler/rustc_middle/src/ty/predicate.rs
@@ -13,6 +13,7 @@ use crate::ty::{
 };
 
 pub type TraitRef<'tcx> = ir::TraitRef<TyCtxt<'tcx>>;
+pub type AliasTerm<'tcx> = ir::AliasTerm<TyCtxt<'tcx>>;
 pub type ProjectionPredicate<'tcx> = ir::ProjectionPredicate<TyCtxt<'tcx>>;
 pub type ExistentialPredicate<'tcx> = ir::ExistentialPredicate<TyCtxt<'tcx>>;
 pub type ExistentialTraitRef<'tcx> = ir::ExistentialTraitRef<TyCtxt<'tcx>>;
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 8d8ed70a757..3577db7234d 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -3038,6 +3038,33 @@ define_print! {
         p!(write("<{} as {}>", self.self_ty(), self.print_only_trait_path()))
     }
 
+    ty::AliasTy<'tcx> {
+        let alias_term: ty::AliasTerm<'tcx> = (*self).into();
+        p!(print(alias_term))
+    }
+
+    ty::AliasTerm<'tcx> {
+        match self.kind(cx.tcx()) {
+            ty::AliasTermKind::InherentTy => p!(pretty_print_inherent_projection(*self)),
+            ty::AliasTermKind::ProjectionTy
+            | ty::AliasTermKind::WeakTy
+            | ty::AliasTermKind::OpaqueTy
+            | ty::AliasTermKind::UnevaluatedConst
+            | ty::AliasTermKind::ProjectionConst => {
+                // If we're printing verbosely, or don't want to invoke queries
+                // (`is_impl_trait_in_trait`), then fall back to printing the def path.
+                // This is likely what you want if you're debugging the compiler anyways.
+                if !(cx.should_print_verbose() || with_reduced_queries())
+                    && cx.tcx().is_impl_trait_in_trait(self.def_id)
+                {
+                    return cx.pretty_print_opaque_impl_type(self.def_id, self.args);
+                } else {
+                    p!(print_def_path(self.def_id, self.args));
+                }
+            }
+        }
+    }
+
     ty::TraitPredicate<'tcx> {
         p!(print(self.trait_ref.self_ty()), ": ");
         p!(pretty_print_bound_constness(self.trait_ref));
@@ -3205,33 +3232,6 @@ define_print_and_forward_display! {
       }
     }
 
-    ty::AliasTy<'tcx> {
-        let alias_term: ty::AliasTerm<'tcx> = (*self).into();
-        p!(print(alias_term))
-    }
-
-    ty::AliasTerm<'tcx> {
-        match self.kind(cx.tcx()) {
-            ty::AliasTermKind::InherentTy => p!(pretty_print_inherent_projection(*self)),
-            ty::AliasTermKind::ProjectionTy
-            | ty::AliasTermKind::WeakTy
-            | ty::AliasTermKind::OpaqueTy
-            | ty::AliasTermKind::UnevaluatedConst
-            | ty::AliasTermKind::ProjectionConst => {
-                // If we're printing verbosely, or don't want to invoke queries
-                // (`is_impl_trait_in_trait`), then fall back to printing the def path.
-                // This is likely what you want if you're debugging the compiler anyways.
-                if !(cx.should_print_verbose() || with_reduced_queries())
-                    && cx.tcx().is_impl_trait_in_trait(self.def_id)
-                {
-                    return cx.pretty_print_opaque_impl_type(self.def_id, self.args);
-                } else {
-                    p!(print_def_path(self.def_id, self.args));
-                }
-            }
-        }
-    }
-
     ty::Predicate<'tcx> {
         p!(print(self.kind()))
     }
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 6abd685343b..7523cd15320 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -7,7 +7,7 @@ use crate::mir::interpret;
 use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
 use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
 use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
-use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
+use crate::ty::{self, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
 use rustc_ast_ir::try_visit;
 use rustc_ast_ir::visit::VisitorResult;
 use rustc_hir::def::Namespace;
@@ -164,23 +164,6 @@ impl<'tcx> fmt::Debug for ty::Clause<'tcx> {
     }
 }
 
-impl<'tcx> fmt::Debug for AliasTy<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        WithInfcx::with_no_infcx(self).fmt(f)
-    }
-}
-impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for AliasTy<'tcx> {
-    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
-        this: WithInfcx<'_, Infcx, &Self>,
-        f: &mut core::fmt::Formatter<'_>,
-    ) -> core::fmt::Result {
-        f.debug_struct("AliasTy")
-            .field("args", &this.map(|data| data.args))
-            .field("def_id", &this.data.def_id)
-            .finish()
-    }
-}
-
 impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Pattern<'tcx> {
     fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
         this: WithInfcx<'_, Infcx, &Self>,
@@ -230,23 +213,6 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::consts::Expr<'tcx> {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::UnevaluatedConst<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        WithInfcx::with_no_infcx(self).fmt(f)
-    }
-}
-impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::UnevaluatedConst<'tcx> {
-    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
-        this: WithInfcx<'_, Infcx, &Self>,
-        f: &mut core::fmt::Formatter<'_>,
-    ) -> core::fmt::Result {
-        f.debug_struct("UnevaluatedConst")
-            .field("def", &this.data.def)
-            .field("args", &this.wrap(this.data.args))
-            .finish()
-    }
-}
-
 impl<'tcx> fmt::Debug for ty::Const<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         WithInfcx::with_no_infcx(self).fmt(f)
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 16301633247..e4396c6f20b 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -28,20 +28,17 @@ use std::iter;
 use std::ops::{ControlFlow, Deref, Range};
 use ty::util::IntTypeExt;
 
-use rustc_type_ir::BoundVar;
-use rustc_type_ir::CollectAndApply;
-use rustc_type_ir::DynKind;
-use rustc_type_ir::TyKind as IrTyKind;
 use rustc_type_ir::TyKind::*;
-use rustc_type_ir::TypeAndMut as IrTypeAndMut;
+use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind};
 
 use super::fold::FnMutDelegate;
 use super::GenericParamDefKind;
 
 // Re-export and re-parameterize some `I = TyCtxt<'tcx>` types here
 #[rustc_diagnostic_item = "TyKind"]
-pub type TyKind<'tcx> = IrTyKind<TyCtxt<'tcx>>;
-pub type TypeAndMut<'tcx> = IrTypeAndMut<TyCtxt<'tcx>>;
+pub type TyKind<'tcx> = ir::TyKind<TyCtxt<'tcx>>;
+pub type TypeAndMut<'tcx> = ir::TypeAndMut<TyCtxt<'tcx>>;
+pub type AliasTy<'tcx> = ir::AliasTy<TyCtxt<'tcx>>;
 
 pub trait Article {
     fn article(&self) -> &'static str;
@@ -1105,371 +1102,6 @@ where
     }
 }
 
-/// Represents the unprojected term of a projection goal.
-///
-/// * For a projection, this would be `<Ty as Trait<...>>::N<...>`.
-/// * For an inherent projection, this would be `Ty::N<...>`.
-/// * For an opaque type, there is no explicit syntax.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
-pub struct AliasTerm<'tcx> {
-    /// The parameters of the associated or opaque item.
-    ///
-    /// For a projection, these are the generic parameters for the trait and the
-    /// GAT parameters, if there are any.
-    ///
-    /// For an inherent projection, they consist of the self type and the GAT parameters,
-    /// if there are any.
-    ///
-    /// For RPIT the generic parameters are for the generics of the function,
-    /// while for TAIT it is used for the generic parameters of the alias.
-    pub args: GenericArgsRef<'tcx>,
-
-    /// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether
-    /// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if
-    /// this is an opaque.
-    ///
-    /// During codegen, `tcx.type_of(def_id)` can be used to get the type of the
-    /// underlying type if the type is an opaque.
-    ///
-    /// Note that if this is an associated type, this is not the `DefId` of the
-    /// `TraitRef` containing this associated type, which is in `tcx.associated_item(def_id).container`,
-    /// aka. `tcx.parent(def_id)`.
-    pub def_id: DefId,
-
-    /// This field exists to prevent the creation of `AliasTerm` without using
-    /// [AliasTerm::new].
-    _use_alias_term_new_instead: (),
-}
-
-// FIXME: Remove these when we uplift `AliasTerm`
-use crate::ty::{DebugWithInfcx, InferCtxtLike, WithInfcx};
-impl<'tcx> std::fmt::Debug for AliasTerm<'tcx> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        WithInfcx::with_no_infcx(self).fmt(f)
-    }
-}
-impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for AliasTerm<'tcx> {
-    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
-        this: WithInfcx<'_, Infcx, &Self>,
-        f: &mut std::fmt::Formatter<'_>,
-    ) -> std::fmt::Result {
-        f.debug_struct("AliasTerm")
-            .field("args", &this.map(|data| data.args))
-            .field("def_id", &this.data.def_id)
-            .finish()
-    }
-}
-
-impl<'tcx> rustc_type_ir::inherent::AliasTerm<TyCtxt<'tcx>> for AliasTerm<'tcx> {
-    fn new(
-        interner: TyCtxt<'tcx>,
-        trait_def_id: DefId,
-        args: impl IntoIterator<Item: Into<ty::GenericArg<'tcx>>>,
-    ) -> Self {
-        AliasTerm::new(interner, trait_def_id, args)
-    }
-
-    fn def_id(self) -> DefId {
-        self.def_id
-    }
-
-    fn args(self) -> ty::GenericArgsRef<'tcx> {
-        self.args
-    }
-
-    fn trait_def_id(self, interner: TyCtxt<'tcx>) -> DefId {
-        self.trait_def_id(interner)
-    }
-
-    fn self_ty(self) -> Ty<'tcx> {
-        self.self_ty()
-    }
-
-    fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
-        self.with_self_ty(tcx, self_ty)
-    }
-}
-
-impl<'tcx> AliasTerm<'tcx> {
-    pub fn new(
-        tcx: TyCtxt<'tcx>,
-        def_id: DefId,
-        args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
-    ) -> AliasTerm<'tcx> {
-        let args = tcx.check_and_mk_args(def_id, args);
-        AliasTerm { def_id, args, _use_alias_term_new_instead: () }
-    }
-
-    pub fn expect_ty(self, tcx: TyCtxt<'tcx>) -> AliasTy<'tcx> {
-        match self.kind(tcx) {
-            ty::AliasTermKind::ProjectionTy
-            | ty::AliasTermKind::InherentTy
-            | ty::AliasTermKind::OpaqueTy
-            | ty::AliasTermKind::WeakTy => {}
-            ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => {
-                bug!("Cannot turn `UnevaluatedConst` into `AliasTy`")
-            }
-        }
-        ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }
-    }
-
-    pub fn kind(self, tcx: TyCtxt<'tcx>) -> ty::AliasTermKind {
-        match tcx.def_kind(self.def_id) {
-            DefKind::AssocTy => {
-                if let DefKind::Impl { of_trait: false } = tcx.def_kind(tcx.parent(self.def_id)) {
-                    ty::AliasTermKind::InherentTy
-                } else {
-                    ty::AliasTermKind::ProjectionTy
-                }
-            }
-            DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy,
-            DefKind::TyAlias => ty::AliasTermKind::WeakTy,
-            DefKind::AnonConst => ty::AliasTermKind::UnevaluatedConst,
-            DefKind::AssocConst => ty::AliasTermKind::ProjectionConst,
-            kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
-        }
-    }
-}
-
-/// The following methods work only with (trait) associated item projections.
-impl<'tcx> AliasTerm<'tcx> {
-    pub fn self_ty(self) -> Ty<'tcx> {
-        self.args.type_at(0)
-    }
-
-    pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
-        AliasTerm::new(
-            tcx,
-            self.def_id,
-            [self_ty.into()].into_iter().chain(self.args.iter().skip(1)),
-        )
-    }
-
-    pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
-        match tcx.def_kind(self.def_id) {
-            DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.def_id),
-            kind => bug!("expected a projection AliasTy; found {kind:?}"),
-        }
-    }
-
-    /// Extracts the underlying trait reference from this projection.
-    /// For example, if this is a projection of `<T as Iterator>::Item`,
-    /// then this function would return a `T: Iterator` trait reference.
-    ///
-    /// NOTE: This will drop the args for generic associated types
-    /// consider calling [Self::trait_ref_and_own_args] to get those
-    /// as well.
-    pub fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
-        let def_id = self.trait_def_id(tcx);
-        ty::TraitRef::new(tcx, def_id, self.args.truncate_to(tcx, tcx.generics_of(def_id)))
-    }
-
-    /// Extracts the underlying trait reference and own args from this projection.
-    /// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
-    /// then this function would return a `T: StreamingIterator` trait reference and `['a]` as the own args
-    pub fn trait_ref_and_own_args(
-        self,
-        tcx: TyCtxt<'tcx>,
-    ) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
-        let trait_def_id = self.trait_def_id(tcx);
-        let trait_generics = tcx.generics_of(trait_def_id);
-        (
-            ty::TraitRef::new(tcx, trait_def_id, self.args.truncate_to(tcx, trait_generics)),
-            &self.args[trait_generics.count()..],
-        )
-    }
-
-    pub fn to_term(self, tcx: TyCtxt<'tcx>) -> ty::Term<'tcx> {
-        match self.kind(tcx) {
-            ty::AliasTermKind::ProjectionTy => Ty::new_alias(
-                tcx,
-                ty::Projection,
-                AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
-            )
-            .into(),
-            ty::AliasTermKind::InherentTy => Ty::new_alias(
-                tcx,
-                ty::Inherent,
-                AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
-            )
-            .into(),
-            ty::AliasTermKind::OpaqueTy => Ty::new_alias(
-                tcx,
-                ty::Opaque,
-                AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
-            )
-            .into(),
-            ty::AliasTermKind::WeakTy => Ty::new_alias(
-                tcx,
-                ty::Weak,
-                AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
-            )
-            .into(),
-            ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => {
-                ty::Const::new_unevaluated(
-                    tcx,
-                    ty::UnevaluatedConst::new(self.def_id, self.args),
-                    tcx.type_of(self.def_id).instantiate(tcx, self.args),
-                )
-                .into()
-            }
-        }
-    }
-}
-
-impl<'tcx> From<AliasTy<'tcx>> for AliasTerm<'tcx> {
-    fn from(ty: AliasTy<'tcx>) -> Self {
-        AliasTerm { args: ty.args, def_id: ty.def_id, _use_alias_term_new_instead: () }
-    }
-}
-
-impl<'tcx> From<ty::UnevaluatedConst<'tcx>> for AliasTerm<'tcx> {
-    fn from(ct: ty::UnevaluatedConst<'tcx>) -> Self {
-        AliasTerm { args: ct.args, def_id: ct.def, _use_alias_term_new_instead: () }
-    }
-}
-
-/// Represents the projection of an associated, opaque, or lazy-type-alias type.
-///
-/// * For a projection, this would be `<Ty as Trait<...>>::N<...>`.
-/// * For an inherent projection, this would be `Ty::N<...>`.
-/// * For an opaque type, there is no explicit syntax.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
-pub struct AliasTy<'tcx> {
-    /// The parameters of the associated or opaque type.
-    ///
-    /// For a projection, these are the generic parameters for the trait and the
-    /// GAT parameters, if there are any.
-    ///
-    /// For an inherent projection, they consist of the self type and the GAT parameters,
-    /// if there are any.
-    ///
-    /// For RPIT the generic parameters are for the generics of the function,
-    /// while for TAIT it is used for the generic parameters of the alias.
-    pub args: GenericArgsRef<'tcx>,
-
-    /// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether
-    /// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if
-    /// this is an opaque.
-    ///
-    /// During codegen, `tcx.type_of(def_id)` can be used to get the type of the
-    /// underlying type if the type is an opaque.
-    ///
-    /// Note that if this is an associated type, this is not the `DefId` of the
-    /// `TraitRef` containing this associated type, which is in `tcx.associated_item(def_id).container`,
-    /// aka. `tcx.parent(def_id)`.
-    pub def_id: DefId,
-
-    /// This field exists to prevent the creation of `AliasT` without using
-    /// [AliasTy::new].
-    _use_alias_ty_new_instead: (),
-}
-
-impl<'tcx> AliasTy<'tcx> {
-    pub fn new(
-        tcx: TyCtxt<'tcx>,
-        def_id: DefId,
-        args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
-    ) -> ty::AliasTy<'tcx> {
-        let args = tcx.check_and_mk_args(def_id, args);
-        ty::AliasTy { def_id, args, _use_alias_ty_new_instead: () }
-    }
-
-    pub fn kind(self, tcx: TyCtxt<'tcx>) -> ty::AliasTyKind {
-        match tcx.def_kind(self.def_id) {
-            DefKind::AssocTy
-                if let DefKind::Impl { of_trait: false } =
-                    tcx.def_kind(tcx.parent(self.def_id)) =>
-            {
-                ty::Inherent
-            }
-            DefKind::AssocTy => ty::Projection,
-            DefKind::OpaqueTy => ty::Opaque,
-            DefKind::TyAlias => ty::Weak,
-            kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
-        }
-    }
-
-    /// Whether this alias type is an opaque.
-    pub fn is_opaque(self, tcx: TyCtxt<'tcx>) -> bool {
-        matches!(self.kind(tcx), ty::Opaque)
-    }
-
-    pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
-        Ty::new_alias(tcx, self.kind(tcx), self)
-    }
-}
-
-/// The following methods work only with (trait) associated type projections.
-impl<'tcx> AliasTy<'tcx> {
-    pub fn self_ty(self) -> Ty<'tcx> {
-        self.args.type_at(0)
-    }
-
-    pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
-        AliasTy::new(tcx, self.def_id, [self_ty.into()].into_iter().chain(self.args.iter().skip(1)))
-    }
-
-    pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
-        match tcx.def_kind(self.def_id) {
-            DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.def_id),
-            kind => bug!("expected a projection AliasTy; found {kind:?}"),
-        }
-    }
-
-    /// Extracts the underlying trait reference and own args from this projection.
-    /// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
-    /// then this function would return a `T: StreamingIterator` trait reference and `['a]` as the own args
-    pub fn trait_ref_and_own_args(
-        self,
-        tcx: TyCtxt<'tcx>,
-    ) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
-        let trait_def_id = self.trait_def_id(tcx);
-        let trait_generics = tcx.generics_of(trait_def_id);
-        (
-            ty::TraitRef::new(tcx, trait_def_id, self.args.truncate_to(tcx, trait_generics)),
-            &self.args[trait_generics.count()..],
-        )
-    }
-
-    /// Extracts the underlying trait reference from this projection.
-    /// For example, if this is a projection of `<T as Iterator>::Item`,
-    /// then this function would return a `T: Iterator` trait reference.
-    ///
-    /// WARNING: This will drop the args for generic associated types
-    /// consider calling [Self::trait_ref_and_own_args] to get those
-    /// as well.
-    pub fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
-        let def_id = self.trait_def_id(tcx);
-        ty::TraitRef::new(tcx, def_id, self.args.truncate_to(tcx, tcx.generics_of(def_id)))
-    }
-}
-
-/// The following methods work only with inherent associated type projections.
-impl<'tcx> AliasTy<'tcx> {
-    /// Transform the generic parameters to have the given `impl` args as the base and the GAT args on top of that.
-    ///
-    /// Does the following transformation:
-    ///
-    /// ```text
-    /// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m]
-    ///
-    ///     I_i impl args
-    ///     P_j GAT args
-    /// ```
-    pub fn rebase_inherent_args_onto_impl(
-        self,
-        impl_args: ty::GenericArgsRef<'tcx>,
-        tcx: TyCtxt<'tcx>,
-    ) -> ty::GenericArgsRef<'tcx> {
-        debug_assert_eq!(self.kind(tcx), ty::Inherent);
-
-        tcx.mk_args_from_iter(impl_args.into_iter().chain(self.args.into_iter().skip(1)))
-    }
-}
-
 #[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
 pub struct GenSig<'tcx> {
     pub resume_ty: Ty<'tcx>,
@@ -2020,6 +1652,18 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
     fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
         Ty::new_bound(tcx, debruijn, ty::BoundTy { var, kind: ty::BoundTyKind::Anon })
     }
+
+    fn new_alias(
+        interner: TyCtxt<'tcx>,
+        kind: ty::AliasTyKind,
+        alias_ty: ty::AliasTy<'tcx>,
+    ) -> Self {
+        Ty::new_alias(interner, kind, alias_ty)
+    }
+
+    fn into_term(self) -> ty::Term<'tcx> {
+        self.into()
+    }
 }
 
 /// Type utilities
diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs
index c748cdf6ed2..af07e9ff96b 100644
--- a/compiler/rustc_type_ir/src/const_kind.rs
+++ b/compiler/rustc_type_ir/src/const_kind.rs
@@ -2,6 +2,7 @@
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 #[cfg(feature = "nightly")]
 use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
+use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
 use std::fmt;
 
 use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx};
@@ -86,6 +87,46 @@ impl<I: Interner> DebugWithInfcx<I> for ConstKind<I> {
     }
 }
 
+/// An unevaluated (potentially generic) constant used in the type-system.
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    Hash(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = "")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
+pub struct UnevaluatedConst<I: Interner> {
+    pub def: I::DefId,
+    pub args: I::GenericArgs,
+}
+
+impl<I: Interner> UnevaluatedConst<I> {
+    #[inline]
+    pub fn new(def: I::DefId, args: I::GenericArgs) -> UnevaluatedConst<I> {
+        UnevaluatedConst { def, args }
+    }
+}
+
+impl<I: Interner> fmt::Debug for UnevaluatedConst<I> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        WithInfcx::with_no_infcx(self).fmt(f)
+    }
+}
+impl<I: Interner> DebugWithInfcx<I> for UnevaluatedConst<I> {
+    fn fmt<Infcx: InferCtxtLike<Interner = I>>(
+        this: WithInfcx<'_, Infcx, &Self>,
+        f: &mut core::fmt::Formatter<'_>,
+    ) -> core::fmt::Result {
+        f.debug_struct("UnevaluatedConst")
+            .field("def", &this.data.def)
+            .field("args", &this.wrap(this.data.args))
+            .finish()
+    }
+}
+
 rustc_index::newtype_index! {
     /// A **`const`** **v**ariable **ID**.
     #[encodable]
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index 5e981636438..0a964801ce7 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -5,7 +5,8 @@ use std::ops::Deref;
 use crate::fold::TypeSuperFoldable;
 use crate::visit::{Flags, TypeSuperVisitable};
 use crate::{
-    BoundVar, ConstKind, DebruijnIndex, DebugWithInfcx, Interner, RegionKind, TyKind, UniverseIndex,
+    AliasTy, AliasTyKind, BoundVar, ConstKind, DebruijnIndex, DebugWithInfcx, Interner, RegionKind,
+    TyKind, UnevaluatedConst, UniverseIndex,
 };
 
 pub trait Ty<I: Interner<Ty = Self>>:
@@ -20,6 +21,10 @@ pub trait Ty<I: Interner<Ty = Self>>:
     + Flags
 {
     fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self;
+
+    fn new_alias(interner: I, kind: AliasTyKind, alias_ty: AliasTy<I>) -> Self;
+
+    fn into_term(self) -> I::Term;
 }
 
 pub trait Region<I: Interner<Region = Self>>:
@@ -43,7 +48,11 @@ pub trait Const<I: Interner<Const = Self>>:
 {
     fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar, ty: I::Ty) -> Self;
 
+    fn new_unevaluated(interner: I, uv: UnevaluatedConst<I>, ty: I::Ty) -> Self;
+
     fn ty(self) -> I::Ty;
+
+    fn into_term(self) -> I::Term;
 }
 
 pub trait GenericsOf<I: Interner<GenericsOf = Self>> {
@@ -89,21 +98,3 @@ pub trait BoundVars<I: Interner> {
 
     fn has_no_bound_vars(&self) -> bool;
 }
-
-pub trait AliasTerm<I: Interner>: Copy + DebugWithInfcx<I> + Hash + Eq + Sized {
-    fn new(
-        interner: I,
-        trait_def_id: I::DefId,
-        args: impl IntoIterator<Item: Into<I::GenericArg>>,
-    ) -> Self;
-
-    fn def_id(self) -> I::DefId;
-
-    fn args(self) -> I::GenericArgs;
-
-    fn trait_def_id(self, interner: I) -> I::DefId;
-
-    fn self_ty(self) -> I::Ty;
-
-    fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> Self;
-}
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index af0e833b9e9..d6680977168 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -6,13 +6,16 @@ use crate::inherent::*;
 use crate::ir_print::IrPrint;
 use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
 use crate::{
-    CanonicalVarInfo, CoercePredicate, DebugWithInfcx, ExistentialProjection, ExistentialTraitRef,
-    NormalizesTo, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef,
+    AliasTerm, AliasTermKind, AliasTy, AliasTyKind, CanonicalVarInfo, CoercePredicate,
+    DebugWithInfcx, ExistentialProjection, ExistentialTraitRef, NormalizesTo, ProjectionPredicate,
+    SubtypePredicate, TraitPredicate, TraitRef,
 };
 
 pub trait Interner:
     Sized
     + Copy
+    + IrPrint<AliasTy<Self>>
+    + IrPrint<AliasTerm<Self>>
     + IrPrint<TraitRef<Self>>
     + IrPrint<TraitPredicate<Self>>
     + IrPrint<ExistentialTraitRef<Self>>
@@ -27,6 +30,7 @@ pub trait Interner:
     type AdtDef: Copy + Debug + Hash + Eq;
 
     type GenericArgs: GenericArgs<Self>;
+    type GenericArgsSlice: Copy + Debug + Hash + Eq;
     type GenericArg: Copy + DebugWithInfcx<Self> + Hash + Eq;
     type Term: Copy + Debug + Hash + Eq;
 
@@ -39,7 +43,6 @@ pub trait Interner:
     // Kinds of tys
     type Ty: Ty<Self>;
     type Tys: Copy + Debug + Hash + Eq + IntoIterator<Item = Self::Ty>;
-    type AliasTy: Copy + DebugWithInfcx<Self> + Hash + Eq + Sized;
     type ParamTy: Copy + Debug + Hash + Eq;
     type BoundTy: Copy + Debug + Hash + Eq;
     type PlaceholderTy: PlaceholderLike;
@@ -74,7 +77,6 @@ pub trait Interner:
     type RegionOutlivesPredicate: Copy + Debug + Hash + Eq;
     type TypeOutlivesPredicate: Copy + Debug + Hash + Eq;
     type ProjectionPredicate: Copy + Debug + Hash + Eq;
-    type AliasTerm: AliasTerm<Self>;
     type NormalizesTo: Copy + Debug + Hash + Eq;
     type SubtypePredicate: Copy + Debug + Hash + Eq;
     type CoercePredicate: Copy + Debug + Hash + Eq;
@@ -86,8 +88,23 @@ pub trait Interner:
     type GenericsOf: GenericsOf<Self>;
     fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf;
 
+    // FIXME: Remove after uplifting `EarlyBinder`
+    fn type_of_instantiated(self, def_id: Self::DefId, args: Self::GenericArgs) -> Self::Ty;
+
+    fn alias_ty_kind(self, alias: AliasTy<Self>) -> AliasTyKind;
+
+    fn alias_term_kind(self, alias: AliasTerm<Self>) -> AliasTermKind;
+
+    fn trait_ref_and_own_args_for_alias(
+        self,
+        def_id: Self::DefId,
+        args: Self::GenericArgs,
+    ) -> (TraitRef<Self>, Self::GenericArgsSlice);
+
     fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs;
 
+    fn mk_args_from_iter(self, args: impl Iterator<Item = Self::GenericArg>) -> Self::GenericArgs;
+
     fn check_and_mk_args(
         self,
         def_id: Self::DefId,
diff --git a/compiler/rustc_type_ir/src/ir_print.rs b/compiler/rustc_type_ir/src/ir_print.rs
index 5885139754a..2a766d0bc09 100644
--- a/compiler/rustc_type_ir/src/ir_print.rs
+++ b/compiler/rustc_type_ir/src/ir_print.rs
@@ -1,8 +1,8 @@
 use std::fmt;
 
 use crate::{
-    CoercePredicate, ExistentialProjection, ExistentialTraitRef, Interner, NormalizesTo,
-    ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef,
+    AliasTerm, AliasTy, CoercePredicate, ExistentialProjection, ExistentialTraitRef, Interner,
+    NormalizesTo, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef,
 };
 
 pub trait IrPrint<T> {
@@ -43,6 +43,8 @@ define_display_via_print!(
     NormalizesTo,
     SubtypePredicate,
     CoercePredicate,
+    AliasTy,
+    AliasTerm,
 );
 
 define_debug_via_print!(TraitRef, ExistentialTraitRef, ExistentialProjection);
diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs
index 71f198d2b8e..1ec237d7cd5 100644
--- a/compiler/rustc_type_ir/src/predicate.rs
+++ b/compiler/rustc_type_ir/src/predicate.rs
@@ -6,7 +6,9 @@ use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Gen
 
 use crate::inherent::*;
 use crate::visit::TypeVisitableExt as _;
-use crate::{DebugWithInfcx, Interner};
+use crate::{
+    AliasTy, AliasTyKind, DebugWithInfcx, InferCtxtLike, Interner, UnevaluatedConst, WithInfcx,
+};
 
 /// A complete reference to a trait. These take numerous guises in syntax,
 /// but perhaps the most recognizable form is in a where-clause:
@@ -272,20 +274,20 @@ impl<I: Interner> ExistentialProjection<I> {
     /// For example, if this is a projection of `exists T. <T as Iterator>::Item == X`,
     /// then this function would return an `exists T. T: Iterator` existential trait
     /// reference.
-    pub fn trait_ref(&self, tcx: I) -> ExistentialTraitRef<I> {
-        let def_id = tcx.parent(self.def_id);
-        let args_count = tcx.generics_of(def_id).count() - 1;
-        let args = tcx.mk_args(&self.args[..args_count]);
+    pub fn trait_ref(&self, interner: I) -> ExistentialTraitRef<I> {
+        let def_id = interner.parent(self.def_id);
+        let args_count = interner.generics_of(def_id).count() - 1;
+        let args = interner.mk_args(&self.args[..args_count]);
         ExistentialTraitRef { def_id, args }
     }
 
-    pub fn with_self_ty(&self, tcx: I, self_ty: I::Ty) -> ProjectionPredicate<I> {
+    pub fn with_self_ty(&self, interner: I, self_ty: I::Ty) -> ProjectionPredicate<I> {
         // otherwise the escaping regions would be captured by the binders
         debug_assert!(!self_ty.has_escaping_bound_vars());
 
         ProjectionPredicate {
-            projection_term: I::AliasTerm::new(
-                tcx,
+            projection_term: AliasTerm::new(
+                interner,
                 self.def_id,
                 [self_ty.into()].into_iter().chain(self.args),
             ),
@@ -293,13 +295,13 @@ impl<I: Interner> ExistentialProjection<I> {
         }
     }
 
-    pub fn erase_self_ty(tcx: I, projection_predicate: ProjectionPredicate<I>) -> Self {
+    pub fn erase_self_ty(interner: I, projection_predicate: ProjectionPredicate<I>) -> Self {
         // Assert there is a Self.
-        projection_predicate.projection_term.args().type_at(0);
+        projection_predicate.projection_term.args.type_at(0);
 
         Self {
-            def_id: projection_predicate.projection_term.def_id(),
-            args: tcx.mk_args(&projection_predicate.projection_term.args()[1..]),
+            def_id: projection_predicate.projection_term.def_id,
+            args: interner.mk_args(&projection_predicate.projection_term.args[1..]),
             term: projection_predicate.term,
         }
     }
@@ -339,6 +341,190 @@ impl AliasTermKind {
     }
 }
 
+/// Represents the unprojected term of a projection goal.
+///
+/// * For a projection, this would be `<Ty as Trait<...>>::N<...>`.
+/// * For an inherent projection, this would be `Ty::N<...>`.
+/// * For an opaque type, there is no explicit syntax.
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    Hash(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = "")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
+pub struct AliasTerm<I: Interner> {
+    /// The parameters of the associated or opaque item.
+    ///
+    /// For a projection, these are the generic parameters for the trait and the
+    /// GAT parameters, if there are any.
+    ///
+    /// For an inherent projection, they consist of the self type and the GAT parameters,
+    /// if there are any.
+    ///
+    /// For RPIT the generic parameters are for the generics of the function,
+    /// while for TAIT it is used for the generic parameters of the alias.
+    pub args: I::GenericArgs,
+
+    /// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether
+    /// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if
+    /// this is an opaque.
+    ///
+    /// During codegen, `interner.type_of(def_id)` can be used to get the type of the
+    /// underlying type if the type is an opaque.
+    ///
+    /// Note that if this is an associated type, this is not the `DefId` of the
+    /// `TraitRef` containing this associated type, which is in `interner.associated_item(def_id).container`,
+    /// aka. `interner.parent(def_id)`.
+    pub def_id: I::DefId,
+
+    /// This field exists to prevent the creation of `AliasTerm` without using
+    /// [AliasTerm::new].
+    _use_alias_term_new_instead: (),
+}
+
+impl<I: Interner> std::fmt::Debug for AliasTerm<I> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        WithInfcx::with_no_infcx(self).fmt(f)
+    }
+}
+impl<I: Interner> DebugWithInfcx<I> for AliasTerm<I> {
+    fn fmt<Infcx: InferCtxtLike<Interner = I>>(
+        this: WithInfcx<'_, Infcx, &Self>,
+        f: &mut std::fmt::Formatter<'_>,
+    ) -> std::fmt::Result {
+        f.debug_struct("AliasTerm")
+            .field("args", &this.map(|data| data.args))
+            .field("def_id", &this.data.def_id)
+            .finish()
+    }
+}
+
+impl<I: Interner> AliasTerm<I> {
+    pub fn new(
+        interner: I,
+        def_id: I::DefId,
+        args: impl IntoIterator<Item: Into<I::GenericArg>>,
+    ) -> AliasTerm<I> {
+        let args = interner.check_and_mk_args(def_id, args);
+        AliasTerm { def_id, args, _use_alias_term_new_instead: () }
+    }
+
+    pub fn expect_ty(self, interner: I) -> AliasTy<I> {
+        match self.kind(interner) {
+            AliasTermKind::ProjectionTy
+            | AliasTermKind::InherentTy
+            | AliasTermKind::OpaqueTy
+            | AliasTermKind::WeakTy => {}
+            AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => {
+                panic!("Cannot turn `UnevaluatedConst` into `AliasTy`")
+            }
+        }
+        AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }
+    }
+
+    pub fn kind(self, interner: I) -> AliasTermKind {
+        interner.alias_term_kind(self)
+    }
+
+    pub fn to_term(self, interner: I) -> I::Term {
+        match self.kind(interner) {
+            AliasTermKind::ProjectionTy => Ty::new_alias(
+                interner,
+                AliasTyKind::Projection,
+                AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
+            )
+            .into_term(),
+            AliasTermKind::InherentTy => Ty::new_alias(
+                interner,
+                AliasTyKind::Inherent,
+                AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
+            )
+            .into_term(),
+            AliasTermKind::OpaqueTy => Ty::new_alias(
+                interner,
+                AliasTyKind::Opaque,
+                AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
+            )
+            .into_term(),
+            AliasTermKind::WeakTy => Ty::new_alias(
+                interner,
+                AliasTyKind::Weak,
+                AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
+            )
+            .into_term(),
+            AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => {
+                I::Const::new_unevaluated(
+                    interner,
+                    UnevaluatedConst::new(self.def_id, self.args),
+                    interner.type_of_instantiated(self.def_id, self.args),
+                )
+                .into_term()
+            }
+        }
+    }
+}
+
+/// The following methods work only with (trait) associated type projections.
+impl<I: Interner> AliasTerm<I> {
+    pub fn self_ty(self) -> I::Ty {
+        self.args.type_at(0)
+    }
+
+    pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self {
+        AliasTerm::new(
+            interner,
+            self.def_id,
+            [self_ty.into()].into_iter().chain(self.args.into_iter().skip(1)),
+        )
+    }
+
+    pub fn trait_def_id(self, interner: I) -> I::DefId {
+        assert!(
+            matches!(
+                self.kind(interner),
+                AliasTermKind::ProjectionTy | AliasTermKind::ProjectionConst
+            ),
+            "expected a projection"
+        );
+        interner.parent(self.def_id)
+    }
+
+    /// Extracts the underlying trait reference and own args from this projection.
+    /// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
+    /// then this function would return a `T: StreamingIterator` trait reference and
+    /// `['a]` as the own args.
+    pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef<I>, I::GenericArgsSlice) {
+        interner.trait_ref_and_own_args_for_alias(self.def_id, self.args)
+    }
+
+    /// Extracts the underlying trait reference from this projection.
+    /// For example, if this is a projection of `<T as Iterator>::Item`,
+    /// then this function would return a `T: Iterator` trait reference.
+    ///
+    /// WARNING: This will drop the args for generic associated types
+    /// consider calling [Self::trait_ref_and_own_args] to get those
+    /// as well.
+    pub fn trait_ref(self, interner: I) -> TraitRef<I> {
+        self.trait_ref_and_own_args(interner).0
+    }
+}
+
+impl<I: Interner> From<AliasTy<I>> for AliasTerm<I> {
+    fn from(ty: AliasTy<I>) -> Self {
+        AliasTerm { args: ty.args, def_id: ty.def_id, _use_alias_term_new_instead: () }
+    }
+}
+
+impl<I: Interner> From<UnevaluatedConst<I>> for AliasTerm<I> {
+    fn from(ct: UnevaluatedConst<I>) -> Self {
+        AliasTerm { args: ct.args, def_id: ct.def, _use_alias_term_new_instead: () }
+    }
+}
+
 /// This kind of predicate has no *direct* correspondent in the
 /// syntax, but it roughly corresponds to the syntactic forms:
 ///
@@ -362,7 +548,7 @@ impl AliasTermKind {
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 pub struct ProjectionPredicate<I: Interner> {
-    pub projection_term: I::AliasTerm,
+    pub projection_term: AliasTerm<I>,
     pub term: I::Term,
 }
 
@@ -371,16 +557,16 @@ impl<I: Interner> ProjectionPredicate<I> {
         self.projection_term.self_ty()
     }
 
-    pub fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> ProjectionPredicate<I> {
-        Self { projection_term: self.projection_term.with_self_ty(tcx, self_ty), ..self }
+    pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> ProjectionPredicate<I> {
+        Self { projection_term: self.projection_term.with_self_ty(interner, self_ty), ..self }
     }
 
-    pub fn trait_def_id(self, tcx: I) -> I::DefId {
-        self.projection_term.trait_def_id(tcx)
+    pub fn trait_def_id(self, interner: I) -> I::DefId {
+        self.projection_term.trait_def_id(interner)
     }
 
     pub fn def_id(self) -> I::DefId {
-        self.projection_term.def_id()
+        self.projection_term.def_id
     }
 }
 
@@ -403,7 +589,7 @@ impl<I: Interner> fmt::Debug for ProjectionPredicate<I> {
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 pub struct NormalizesTo<I: Interner> {
-    pub alias: I::AliasTerm,
+    pub alias: AliasTerm<I>,
     pub term: I::Term,
 }
 
@@ -412,16 +598,16 @@ impl<I: Interner> NormalizesTo<I> {
         self.alias.self_ty()
     }
 
-    pub fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> NormalizesTo<I> {
-        Self { alias: self.alias.with_self_ty(tcx, self_ty), ..self }
+    pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> NormalizesTo<I> {
+        Self { alias: self.alias.with_self_ty(interner, self_ty), ..self }
     }
 
-    pub fn trait_def_id(self, tcx: I) -> I::DefId {
-        self.alias.trait_def_id(tcx)
+    pub fn trait_def_id(self, interner: I) -> I::DefId {
+        self.alias.trait_def_id(interner)
     }
 
     pub fn def_id(self) -> I::DefId {
-        self.alias.def_id()
+        self.alias.def_id
     }
 }
 
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index 6e544d0e6ac..672c890f94e 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -4,11 +4,11 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::unify::{EqUnifyValue, UnifyKey};
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable};
-use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
+use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
 use std::fmt;
 
-use crate::Interner;
-use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, WithInfcx};
+use crate::inherent::*;
+use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, TraitRef, WithInfcx};
 
 use self::TyKind::*;
 
@@ -88,7 +88,7 @@ pub enum TyKind<I: Interner> {
     /// for `struct List<T>` and the args `[i32]`.
     ///
     /// Note that generic parameters in fields only get lazily instantiated
-    /// by using something like `adt_def.all_fields().map(|field| field.ty(tcx, args))`.
+    /// by using something like `adt_def.all_fields().map(|field| field.ty(interner, args))`.
     Adt(I::AdtDef, I::GenericArgs),
 
     /// An unsized FFI type that is opaque to Rust. Written as `extern type T`.
@@ -201,7 +201,7 @@ pub enum TyKind<I: Interner> {
     /// A projection, opaque type, weak type alias, or inherent associated type.
     /// All of these types are represented as pairs of def-id and args, and can
     /// be normalized, so they are grouped conceptually.
-    Alias(AliasTyKind, I::AliasTy),
+    Alias(AliasTyKind, AliasTy<I>),
 
     /// A type parameter; for example, `T` in `fn f<T>(x: T) {}`.
     Param(I::ParamTy),
@@ -422,6 +422,154 @@ impl<I: Interner> fmt::Debug for TyKind<I> {
     }
 }
 
+/// Represents the projection of an associated, opaque, or lazy-type-alias type.
+///
+/// * For a projection, this would be `<Ty as Trait<...>>::N<...>`.
+/// * For an inherent projection, this would be `Ty::N<...>`.
+/// * For an opaque type, there is no explicit syntax.
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    Hash(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = "")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
+pub struct AliasTy<I: Interner> {
+    /// The parameters of the associated or opaque type.
+    ///
+    /// For a projection, these are the generic parameters for the trait and the
+    /// GAT parameters, if there are any.
+    ///
+    /// For an inherent projection, they consist of the self type and the GAT parameters,
+    /// if there are any.
+    ///
+    /// For RPIT the generic parameters are for the generics of the function,
+    /// while for TAIT it is used for the generic parameters of the alias.
+    pub args: I::GenericArgs,
+
+    /// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether
+    /// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if
+    /// this is an opaque.
+    ///
+    /// During codegen, `interner.type_of(def_id)` can be used to get the type of the
+    /// underlying type if the type is an opaque.
+    ///
+    /// Note that if this is an associated type, this is not the `DefId` of the
+    /// `TraitRef` containing this associated type, which is in `interner.associated_item(def_id).container`,
+    /// aka. `interner.parent(def_id)`.
+    pub def_id: I::DefId,
+
+    /// This field exists to prevent the creation of `AliasTy` without using
+    /// [AliasTy::new].
+    pub(crate) _use_alias_ty_new_instead: (),
+}
+
+impl<I: Interner> AliasTy<I> {
+    pub fn new(
+        interner: I,
+        def_id: I::DefId,
+        args: impl IntoIterator<Item: Into<I::GenericArg>>,
+    ) -> AliasTy<I> {
+        let args = interner.check_and_mk_args(def_id, args);
+        AliasTy { def_id, args, _use_alias_ty_new_instead: () }
+    }
+
+    pub fn kind(self, interner: I) -> AliasTyKind {
+        interner.alias_ty_kind(self)
+    }
+
+    /// Whether this alias type is an opaque.
+    pub fn is_opaque(self, interner: I) -> bool {
+        matches!(self.kind(interner), AliasTyKind::Opaque)
+    }
+
+    pub fn to_ty(self, interner: I) -> I::Ty {
+        Ty::new_alias(interner, self.kind(interner), self)
+    }
+}
+
+/// The following methods work only with (trait) associated type projections.
+impl<I: Interner> AliasTy<I> {
+    pub fn self_ty(self) -> I::Ty {
+        self.args.type_at(0)
+    }
+
+    pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self {
+        AliasTy::new(
+            interner,
+            self.def_id,
+            [self_ty.into()].into_iter().chain(self.args.into_iter().skip(1)),
+        )
+    }
+
+    pub fn trait_def_id(self, interner: I) -> I::DefId {
+        assert_eq!(self.kind(interner), AliasTyKind::Projection, "expected a projection");
+        interner.parent(self.def_id)
+    }
+
+    /// Extracts the underlying trait reference and own args from this projection.
+    /// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
+    /// then this function would return a `T: StreamingIterator` trait reference and
+    /// `['a]` as the own args.
+    pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef<I>, I::GenericArgsSlice) {
+        debug_assert_eq!(self.kind(interner), AliasTyKind::Projection);
+        interner.trait_ref_and_own_args_for_alias(self.def_id, self.args)
+    }
+
+    /// Extracts the underlying trait reference from this projection.
+    /// For example, if this is a projection of `<T as Iterator>::Item`,
+    /// then this function would return a `T: Iterator` trait reference.
+    ///
+    /// WARNING: This will drop the args for generic associated types
+    /// consider calling [Self::trait_ref_and_own_args] to get those
+    /// as well.
+    pub fn trait_ref(self, interner: I) -> TraitRef<I> {
+        self.trait_ref_and_own_args(interner).0
+    }
+}
+
+/// The following methods work only with inherent associated type projections.
+impl<I: Interner> AliasTy<I> {
+    /// Transform the generic parameters to have the given `impl` args as the base and the GAT args on top of that.
+    ///
+    /// Does the following transformation:
+    ///
+    /// ```text
+    /// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m]
+    ///
+    ///     I_i impl args
+    ///     P_j GAT args
+    /// ```
+    pub fn rebase_inherent_args_onto_impl(
+        self,
+        impl_args: I::GenericArgs,
+        interner: I,
+    ) -> I::GenericArgs {
+        debug_assert_eq!(self.kind(interner), AliasTyKind::Inherent);
+        interner.mk_args_from_iter(impl_args.into_iter().chain(self.args.into_iter().skip(1)))
+    }
+}
+
+impl<I: Interner> fmt::Debug for AliasTy<I> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        WithInfcx::with_no_infcx(self).fmt(f)
+    }
+}
+impl<I: Interner> DebugWithInfcx<I> for AliasTy<I> {
+    fn fmt<Infcx: InferCtxtLike<Interner = I>>(
+        this: WithInfcx<'_, Infcx, &Self>,
+        f: &mut core::fmt::Formatter<'_>,
+    ) -> core::fmt::Result {
+        f.debug_struct("AliasTy")
+            .field("args", &this.map(|data| data.args))
+            .field("def_id", &this.data.def_id)
+            .finish()
+    }
+}
+
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))]
 pub enum IntTy {