about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2023-10-20 20:43:33 +0000
committerMichael Goulet <michael@errs.io>2023-10-20 17:14:49 -0700
commit573f47585354f6c98f9306410bfd4e040bc7fd19 (patch)
tree48fc23a30ef43abe656e73bdbcdbf15e85dcf70e
parent249624b5043013d18c00f0401ca431c1a6baa8cd (diff)
downloadrust-573f47585354f6c98f9306410bfd4e040bc7fd19.tar.gz
rust-573f47585354f6c98f9306410bfd4e040bc7fd19.zip
Uplift ClauseKind and PredicateKind
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs4
-rw-r--r--compiler/rustc_middle/src/ty/context.rs17
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs100
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs98
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs38
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs4
-rw-r--r--compiler/rustc_smir/src/rustc_smir/mod.rs18
-rw-r--r--compiler/rustc_type_ir/src/codec.rs6
-rw-r--r--compiler/rustc_type_ir/src/const_kind.rs7
-rw-r--r--compiler/rustc_type_ir/src/interner.rs16
-rw-r--r--compiler/rustc_type_ir/src/lib.rs2
-rw-r--r--compiler/rustc_type_ir/src/macros.rs1
-rw-r--r--compiler/rustc_type_ir/src/predicate_kind.rs626
-rw-r--r--compiler/rustc_type_ir/src/region_kind.rs7
-rw-r--r--compiler/rustc_type_ir/src/ty_kind.rs8
15 files changed, 735 insertions, 217 deletions
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index e4069e11df2..d52a717b6b0 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -230,9 +230,9 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D>
                 assert!(pos >= SHORTHAND_OFFSET);
                 let shorthand = pos - SHORTHAND_OFFSET;
 
-                decoder.with_position(shorthand, ty::PredicateKind::decode)
+                decoder.with_position(shorthand, <ty::PredicateKind<'tcx> as Decodable<D>>::decode)
             } else {
-                ty::PredicateKind::decode(decoder)
+                <ty::PredicateKind<'tcx> as Decodable<D>>::decode(decoder)
             },
             bound_vars,
         )
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 561699d3170..dfd8104b5bc 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -84,10 +84,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     type AdtDef = ty::AdtDef<'tcx>;
     type GenericArgs = ty::GenericArgsRef<'tcx>;
     type GenericArg = ty::GenericArg<'tcx>;
+    type Term = ty::Term<'tcx>;
+
     type Binder<T> = Binder<'tcx, T>;
-    type Predicate = Predicate<'tcx>;
-    type PredicateKind = ty::PredicateKind<'tcx>;
     type TypeAndMut = TypeAndMut<'tcx>;
+
     type Ty = Ty<'tcx>;
     type Tys = &'tcx List<Ty<'tcx>>;
     type AliasTy = ty::AliasTy<'tcx>;
@@ -95,10 +96,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     type BoundTy = ty::BoundTy;
     type PlaceholderTy = ty::PlaceholderType;
     type InferTy = InferTy;
+
     type ErrorGuaranteed = ErrorGuaranteed;
     type BoundExistentialPredicates = &'tcx List<PolyExistentialPredicate<'tcx>>;
     type PolyFnSig = PolyFnSig<'tcx>;
     type AllocId = crate::mir::interpret::AllocId;
+
     type Const = ty::Const<'tcx>;
     type InferConst = ty::InferConst<'tcx>;
     type AliasConst = ty::UnevaluatedConst<'tcx>;
@@ -107,6 +110,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     type BoundConst = ty::BoundVar;
     type ValueConst = ty::ValTree<'tcx>;
     type ExprConst = ty::Expr<'tcx>;
+
     type Region = Region<'tcx>;
     type EarlyBoundRegion = ty::EarlyBoundRegion;
     type BoundRegion = ty::BoundRegion;
@@ -114,6 +118,15 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     type InferRegion = ty::RegionVid;
     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 SubtypePredicate = ty::SubtypePredicate<'tcx>;
+    type CoercePredicate = ty::CoercePredicate<'tcx>;
+    type ClosureKind = ty::ClosureKind;
+
     fn ty_and_mut_to_parts(
         TypeAndMut { ty, mutbl }: TypeAndMut<'tcx>,
     ) -> (Self::Ty, ty::Mutability) {
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 9b0ceb23e3e..f53214b3223 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -97,12 +97,12 @@ pub use self::rvalue_scopes::RvalueScopes;
 pub use self::sty::BoundRegionKind::*;
 pub use self::sty::{
     AliasTy, Article, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar,
-    BoundVariableKind, CanonicalPolyFnSig, ClosureArgs, ClosureArgsParts, ConstKind, ConstVid,
-    CoroutineArgs, CoroutineArgsParts, EarlyBoundRegion, EffectVid, ExistentialPredicate,
+    BoundVariableKind, CanonicalPolyFnSig, ClauseKind, ClosureArgs, ClosureArgsParts, ConstKind,
+    ConstVid, CoroutineArgs, CoroutineArgsParts, EarlyBoundRegion, EffectVid, ExistentialPredicate,
     ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig, InlineConstArgs,
     InlineConstArgsParts, ParamConst, ParamTy, PolyExistentialPredicate, PolyExistentialProjection,
-    PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, Region, RegionKind, RegionVid,
-    TraitRef, TyKind, TypeAndMut, UpvarArgs, VarianceDiagInfo,
+    PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, PredicateKind, Region,
+    RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut, UpvarArgs, VarianceDiagInfo,
 };
 pub use self::trait_def::TraitDef;
 pub use self::typeck_results::{
@@ -626,98 +626,6 @@ impl<'tcx> Clause<'tcx> {
     }
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
-/// A clause is something that can appear in where bounds or be inferred
-/// by implied bounds.
-pub enum ClauseKind<'tcx> {
-    /// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be
-    /// the `Self` type of the trait reference and `A`, `B`, and `C`
-    /// would be the type parameters.
-    Trait(TraitPredicate<'tcx>),
-
-    /// `where 'a: 'b`
-    RegionOutlives(RegionOutlivesPredicate<'tcx>),
-
-    /// `where T: 'a`
-    TypeOutlives(TypeOutlivesPredicate<'tcx>),
-
-    /// `where <T as TraitRef>::Name == X`, approximately.
-    /// See the `ProjectionPredicate` struct for details.
-    Projection(ProjectionPredicate<'tcx>),
-
-    /// Ensures that a const generic argument to a parameter `const N: u8`
-    /// is of type `u8`.
-    ConstArgHasType(Const<'tcx>, Ty<'tcx>),
-
-    /// No syntax: `T` well-formed.
-    WellFormed(GenericArg<'tcx>),
-
-    /// Constant initializer must evaluate successfully.
-    ConstEvaluatable(ty::Const<'tcx>),
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
-pub enum PredicateKind<'tcx> {
-    /// Prove a clause
-    Clause(ClauseKind<'tcx>),
-
-    /// Trait must be object-safe.
-    ObjectSafe(DefId),
-
-    /// No direct syntax. May be thought of as `where T: FnFoo<...>`
-    /// for some generic args `...` and `T` being a closure type.
-    /// Satisfied (or refuted) once we know the closure's kind.
-    ClosureKind(DefId, GenericArgsRef<'tcx>, ClosureKind),
-
-    /// `T1 <: T2`
-    ///
-    /// This obligation is created most often when we have two
-    /// unresolved type variables and hence don't have enough
-    /// information to process the subtyping obligation yet.
-    Subtype(SubtypePredicate<'tcx>),
-
-    /// `T1` coerced to `T2`
-    ///
-    /// Like a subtyping obligation, this is created most often
-    /// when we have two unresolved type variables and hence
-    /// don't have enough information to process the coercion
-    /// obligation yet. At the moment, we actually process coercions
-    /// very much like subtyping and don't handle the full coercion
-    /// logic.
-    Coerce(CoercePredicate<'tcx>),
-
-    /// Constants must be equal. The first component is the const that is expected.
-    ConstEquate(Const<'tcx>, Const<'tcx>),
-
-    /// A marker predicate that is always ambiguous.
-    /// Used for coherence to mark opaque types as possibly equal to each other but ambiguous.
-    Ambiguous,
-
-    /// Separate from `ClauseKind::Projection` which is used for normalization in new solver.
-    /// This predicate requires two terms to be equal to eachother.
-    ///
-    /// Only used for new solver
-    AliasRelate(Term<'tcx>, Term<'tcx>, AliasRelationDirection),
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, Debug)]
-pub enum AliasRelationDirection {
-    Equate,
-    Subtype,
-}
-
-impl std::fmt::Display for AliasRelationDirection {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        match self {
-            AliasRelationDirection::Equate => write!(f, "=="),
-            AliasRelationDirection::Subtype => write!(f, "<:"),
-        }
-    }
-}
-
 /// The crate outlives map is computed during typeck and contains the
 /// outlives of every item in the local crate. You should not use it
 /// directly, because to do so will make your pass dependent on the
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 38b3096f851..69a1f33d64b 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -2633,6 +2633,13 @@ macro_rules! forward_display_to_print {
 
 macro_rules! define_print_and_forward_display {
     (($self:ident, $cx:ident): $($ty:ty $print:block)+) => {
+        define_print!(($self, $cx): $($ty $print)*);
+        forward_display_to_print!($($ty),+);
+    };
+}
+
+macro_rules! define_print {
+    (($self:ident, $cx:ident): $($ty:ty $print:block)+) => {
         $(impl<'tcx, P: PrettyPrinter<'tcx>> Print<'tcx, P> for $ty {
             fn print(&$self, $cx: P) -> Result<P, PrintError> {
                 #[allow(unused_mut)]
@@ -2643,8 +2650,6 @@ macro_rules! define_print_and_forward_display {
                 Ok($cx)
             }
         })+
-
-        forward_display_to_print!($($ty),+);
     };
 }
 
@@ -2742,6 +2747,51 @@ forward_display_to_print! {
     ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>
 }
 
+define_print! {
+    (self, cx):
+
+    ty::ClauseKind<'tcx> {
+        match *self {
+            ty::ClauseKind::Trait(ref data) => {
+                p!(print(data))
+            }
+            ty::ClauseKind::RegionOutlives(predicate) => p!(print(predicate)),
+            ty::ClauseKind::TypeOutlives(predicate) => p!(print(predicate)),
+            ty::ClauseKind::Projection(predicate) => p!(print(predicate)),
+            ty::ClauseKind::ConstArgHasType(ct, ty) => {
+                p!("the constant `", print(ct), "` has type `", print(ty), "`")
+            },
+            ty::ClauseKind::WellFormed(arg) => p!(print(arg), " well-formed"),
+            ty::ClauseKind::ConstEvaluatable(ct) => {
+                p!("the constant `", print(ct), "` can be evaluated")
+            }
+        }
+    }
+
+    ty::PredicateKind<'tcx> {
+        match *self {
+            ty::PredicateKind::Clause(data) => {
+                p!(print(data))
+            }
+            ty::PredicateKind::Subtype(predicate) => p!(print(predicate)),
+            ty::PredicateKind::Coerce(predicate) => p!(print(predicate)),
+            ty::PredicateKind::ObjectSafe(trait_def_id) => {
+                p!("the trait `", print_def_path(trait_def_id, &[]), "` is object-safe")
+            }
+            ty::PredicateKind::ClosureKind(closure_def_id, _closure_args, kind) => p!(
+                "the closure `",
+                print_value_path(closure_def_id, &[]),
+                write("` implements the trait `{}`", kind)
+            ),
+            ty::PredicateKind::ConstEquate(c1, c2) => {
+                p!("the constant `", print(c1), "` equals `", print(c2), "`")
+            }
+            ty::PredicateKind::Ambiguous => p!("ambiguous"),
+            ty::PredicateKind::AliasRelate(t1, t2, dir) => p!(print(t1), write(" {} ", dir), print(t2)),
+        }
+    }
+}
+
 define_print_and_forward_display! {
     (self, cx):
 
@@ -2870,55 +2920,13 @@ define_print_and_forward_display! {
     }
 
     ty::Predicate<'tcx> {
-        let binder = self.kind();
-        p!(print(binder))
+        p!(print(self.kind()))
     }
 
     ty::Clause<'tcx> {
         p!(print(self.kind()))
     }
 
-    ty::ClauseKind<'tcx> {
-        match *self {
-            ty::ClauseKind::Trait(ref data) => {
-                p!(print(data))
-            }
-            ty::ClauseKind::RegionOutlives(predicate) => p!(print(predicate)),
-            ty::ClauseKind::TypeOutlives(predicate) => p!(print(predicate)),
-            ty::ClauseKind::Projection(predicate) => p!(print(predicate)),
-            ty::ClauseKind::ConstArgHasType(ct, ty) => {
-                p!("the constant `", print(ct), "` has type `", print(ty), "`")
-            },
-            ty::ClauseKind::WellFormed(arg) => p!(print(arg), " well-formed"),
-            ty::ClauseKind::ConstEvaluatable(ct) => {
-                p!("the constant `", print(ct), "` can be evaluated")
-            }
-        }
-    }
-
-    ty::PredicateKind<'tcx> {
-        match *self {
-            ty::PredicateKind::Clause(data) => {
-                p!(print(data))
-            }
-            ty::PredicateKind::Subtype(predicate) => p!(print(predicate)),
-            ty::PredicateKind::Coerce(predicate) => p!(print(predicate)),
-            ty::PredicateKind::ObjectSafe(trait_def_id) => {
-                p!("the trait `", print_def_path(trait_def_id, &[]), "` is object-safe")
-            }
-            ty::PredicateKind::ClosureKind(closure_def_id, _closure_args, kind) => p!(
-                "the closure `",
-                print_value_path(closure_def_id, &[]),
-                write("` implements the trait `{}`", kind)
-            ),
-            ty::PredicateKind::ConstEquate(c1, c2) => {
-                p!("the constant `", print(c1), "` equals `", print(c2), "`")
-            }
-            ty::PredicateKind::Ambiguous => p!("ambiguous"),
-            ty::PredicateKind::AliasRelate(t1, t2, dir) => p!(print(t1), write(" {} ", dir), print(t2)),
-        }
-    }
-
     GenericArg<'tcx> {
         match self.unpack() {
             GenericArgKind::Lifetime(lt) => p!(print(lt)),
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 012bb749412..1509bfbd59e 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -199,43 +199,6 @@ impl<'tcx> fmt::Debug for ty::Clause<'tcx> {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::ClauseKind<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            ty::ClauseKind::ConstArgHasType(ct, ty) => write!(f, "ConstArgHasType({ct:?}, {ty:?})"),
-            ty::ClauseKind::Trait(ref a) => a.fmt(f),
-            ty::ClauseKind::RegionOutlives(ref pair) => pair.fmt(f),
-            ty::ClauseKind::TypeOutlives(ref pair) => pair.fmt(f),
-            ty::ClauseKind::Projection(ref pair) => pair.fmt(f),
-            ty::ClauseKind::WellFormed(ref data) => write!(f, "WellFormed({data:?})"),
-            ty::ClauseKind::ConstEvaluatable(ct) => {
-                write!(f, "ConstEvaluatable({ct:?})")
-            }
-        }
-    }
-}
-
-impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            ty::PredicateKind::Clause(ref a) => a.fmt(f),
-            ty::PredicateKind::Subtype(ref pair) => pair.fmt(f),
-            ty::PredicateKind::Coerce(ref pair) => pair.fmt(f),
-            ty::PredicateKind::ObjectSafe(trait_def_id) => {
-                write!(f, "ObjectSafe({trait_def_id:?})")
-            }
-            ty::PredicateKind::ClosureKind(closure_def_id, closure_args, kind) => {
-                write!(f, "ClosureKind({closure_def_id:?}, {closure_args:?}, {kind:?})")
-            }
-            ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({c1:?}, {c2:?})"),
-            ty::PredicateKind::Ambiguous => write!(f, "Ambiguous"),
-            ty::PredicateKind::AliasRelate(t1, t2, dir) => {
-                write!(f, "AliasRelate({t1:?}, {dir:?}, {t2:?})")
-            }
-        }
-    }
-}
-
 impl<'tcx> fmt::Debug for AliasTy<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         OptWithInfcx::new_no_ctx(self).fmt(f)
@@ -518,7 +481,6 @@ TrivialTypeTraversalAndLiftImpls! {
     ::rustc_hir::Mutability,
     ::rustc_hir::Unsafety,
     ::rustc_target::spec::abi::Abi,
-    crate::ty::AliasRelationDirection,
     crate::ty::ClosureKind,
     crate::ty::ParamConst,
     crate::ty::ParamTy,
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 46aa5d950cb..e8ff5f66d74 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -33,10 +33,12 @@ use std::marker::PhantomData;
 use std::ops::{ControlFlow, Deref, Range};
 use ty::util::IntTypeExt;
 
+use rustc_type_ir::ClauseKind as IrClauseKind;
 use rustc_type_ir::CollectAndApply;
 use rustc_type_ir::ConstKind as IrConstKind;
 use rustc_type_ir::DebugWithInfcx;
 use rustc_type_ir::DynKind;
+use rustc_type_ir::PredicateKind as IrPredicateKind;
 use rustc_type_ir::RegionKind as IrRegionKind;
 use rustc_type_ir::TyKind as IrTyKind;
 use rustc_type_ir::TyKind::*;
@@ -48,6 +50,8 @@ use super::GenericParamDefKind;
 pub type TyKind<'tcx> = IrTyKind<TyCtxt<'tcx>>;
 pub type RegionKind<'tcx> = IrRegionKind<TyCtxt<'tcx>>;
 pub type ConstKind<'tcx> = IrConstKind<TyCtxt<'tcx>>;
+pub type PredicateKind<'tcx> = IrPredicateKind<TyCtxt<'tcx>>;
+pub type ClauseKind<'tcx> = IrClauseKind<TyCtxt<'tcx>>;
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index 8a1b6b6bfe9..9f966a687d4 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -1497,30 +1497,32 @@ impl<'tcx> Stable<'tcx> for ty::ClauseKind<'tcx> {
     type T = stable_mir::ty::ClauseKind;
 
     fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use ty::ClauseKind::*;
+        use ty::ClauseKind;
         match *self {
-            Trait(trait_object) => stable_mir::ty::ClauseKind::Trait(trait_object.stable(tables)),
-            RegionOutlives(region_outlives) => {
+            ClauseKind::Trait(trait_object) => {
+                stable_mir::ty::ClauseKind::Trait(trait_object.stable(tables))
+            }
+            ClauseKind::RegionOutlives(region_outlives) => {
                 stable_mir::ty::ClauseKind::RegionOutlives(region_outlives.stable(tables))
             }
-            TypeOutlives(type_outlives) => {
+            ClauseKind::TypeOutlives(type_outlives) => {
                 let ty::OutlivesPredicate::<_, _>(a, b) = type_outlives;
                 stable_mir::ty::ClauseKind::TypeOutlives(stable_mir::ty::OutlivesPredicate(
                     tables.intern_ty(a),
                     b.stable(tables),
                 ))
             }
-            Projection(projection_predicate) => {
+            ClauseKind::Projection(projection_predicate) => {
                 stable_mir::ty::ClauseKind::Projection(projection_predicate.stable(tables))
             }
-            ConstArgHasType(const_, ty) => stable_mir::ty::ClauseKind::ConstArgHasType(
+            ClauseKind::ConstArgHasType(const_, ty) => stable_mir::ty::ClauseKind::ConstArgHasType(
                 const_.stable(tables),
                 tables.intern_ty(ty),
             ),
-            WellFormed(generic_arg) => {
+            ClauseKind::WellFormed(generic_arg) => {
                 stable_mir::ty::ClauseKind::WellFormed(generic_arg.unpack().stable(tables))
             }
-            ConstEvaluatable(const_) => {
+            ClauseKind::ConstEvaluatable(const_) => {
                 stable_mir::ty::ClauseKind::ConstEvaluatable(const_.stable(tables))
             }
         }
diff --git a/compiler/rustc_type_ir/src/codec.rs b/compiler/rustc_type_ir/src/codec.rs
index 3b638934629..2fbc8f76fa4 100644
--- a/compiler/rustc_type_ir/src/codec.rs
+++ b/compiler/rustc_type_ir/src/codec.rs
@@ -1,4 +1,4 @@
-use crate::Interner;
+use crate::{Interner, PredicateKind};
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_serialize::{Decoder, Encoder};
@@ -30,9 +30,7 @@ pub trait TyEncoder: Encoder {
 
     fn type_shorthands(&mut self) -> &mut FxHashMap<<Self::I as Interner>::Ty, usize>;
 
-    fn predicate_shorthands(
-        &mut self,
-    ) -> &mut FxHashMap<<Self::I as Interner>::PredicateKind, usize>;
+    fn predicate_shorthands(&mut self) -> &mut FxHashMap<PredicateKind<Self::I>, usize>;
 
     fn encode_alloc_id(&mut self, alloc_id: &<Self::I as Interner>::AllocId);
 }
diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs
index f84841c9f64..fe43db9c2ab 100644
--- a/compiler/rustc_type_ir/src/const_kind.rs
+++ b/compiler/rustc_type_ir/src/const_kind.rs
@@ -1,4 +1,5 @@
 use rustc_data_structures::stable_hasher::HashStable;
+use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_serialize::{Decodable, Decoder, Encodable};
 use std::cmp::Ordering;
 use std::fmt;
@@ -86,11 +87,7 @@ where
     I::ErrorGuaranteed: HashStable<CTX>,
     I::ExprConst: HashStable<CTX>,
 {
-    fn hash_stable(
-        &self,
-        hcx: &mut CTX,
-        hasher: &mut rustc_data_structures::stable_hasher::StableHasher,
-    ) {
+    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
         const_kind_discriminant(self).hash_stable(hcx, hasher);
         match self {
             Param(p) => p.hash_stable(hcx, hasher),
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index 60e4c587993..6e5d3ee0b6d 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -14,13 +14,9 @@ pub trait Interner: Sized {
         + Ord
         + IntoIterator<Item = Self::GenericArg>;
     type GenericArg: Clone + DebugWithInfcx<Self> + Hash + Ord;
+    type Term: Clone + Debug + Hash + Ord;
 
     type Binder<T>;
-
-    // Predicates
-    type Predicate;
-    type PredicateKind: Clone + Debug + Hash + PartialEq + Eq;
-
     type TypeAndMut: Clone + Debug + Hash + Ord;
 
     // Kinds of tys
@@ -56,6 +52,16 @@ pub trait Interner: Sized {
     type InferRegion: Clone + DebugWithInfcx<Self> + Hash + Ord;
     type PlaceholderRegion: Clone + Debug + Hash + Ord;
 
+    // Predicates
+    type Predicate: Clone + Debug + Hash + Eq;
+    type TraitPredicate: Clone + Debug + Hash + Eq;
+    type RegionOutlivesPredicate: Clone + Debug + Hash + Eq;
+    type TypeOutlivesPredicate: Clone + Debug + Hash + Eq;
+    type ProjectionPredicate: Clone + Debug + Hash + Eq;
+    type SubtypePredicate: Clone + Debug + Hash + Eq;
+    type CoercePredicate: Clone + Debug + Hash + Eq;
+    type ClosureKind: Clone + Debug + Hash + Eq;
+
     fn ty_and_mut_to_parts(ty_and_mut: Self::TypeAndMut) -> (Self::Ty, Mutability);
 }
 
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index d4ca9da96e4..299943260f4 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -30,6 +30,7 @@ mod const_kind;
 mod debug;
 mod flags;
 mod interner;
+mod predicate_kind;
 mod region_kind;
 
 pub use codec::*;
@@ -37,6 +38,7 @@ pub use const_kind::*;
 pub use debug::{DebugWithInfcx, InferCtxtLike, OptWithInfcx};
 pub use flags::*;
 pub use interner::*;
+pub use predicate_kind::*;
 pub use region_kind::*;
 pub use ty_info::*;
 pub use ty_kind::*;
diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs
index 9e10c65c20d..88314aca6f3 100644
--- a/compiler/rustc_type_ir/src/macros.rs
+++ b/compiler/rustc_type_ir/src/macros.rs
@@ -49,4 +49,5 @@ TrivialTypeTraversalImpls! {
     u64,
     String,
     crate::DebruijnIndex,
+    crate::AliasRelationDirection,
 }
diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs
new file mode 100644
index 00000000000..f6fabe691c6
--- /dev/null
+++ b/compiler/rustc_type_ir/src/predicate_kind.rs
@@ -0,0 +1,626 @@
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_serialize::Decoder;
+use rustc_serialize::{Decodable, Encodable};
+use std::fmt;
+use std::hash;
+use std::ops::ControlFlow;
+
+use crate::fold::{FallibleTypeFolder, TypeFoldable};
+use crate::visit::{TypeVisitable, TypeVisitor};
+use crate::{HashStableContext, Interner};
+use crate::{TyDecoder, TyEncoder};
+
+/// A clause is something that can appear in where bounds or be inferred
+/// by implied bounds.
+pub enum ClauseKind<I: Interner> {
+    /// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be
+    /// the `Self` type of the trait reference and `A`, `B`, and `C`
+    /// would be the type parameters.
+    Trait(I::TraitPredicate),
+
+    /// `where 'a: 'b`
+    RegionOutlives(I::RegionOutlivesPredicate),
+
+    /// `where T: 'a`
+    TypeOutlives(I::TypeOutlivesPredicate),
+
+    /// `where <T as TraitRef>::Name == X`, approximately.
+    /// See the `ProjectionPredicate` struct for details.
+    Projection(I::ProjectionPredicate),
+
+    /// Ensures that a const generic argument to a parameter `const N: u8`
+    /// is of type `u8`.
+    ConstArgHasType(I::Const, I::Ty),
+
+    /// No syntax: `T` well-formed.
+    WellFormed(I::GenericArg),
+
+    /// Constant initializer must evaluate successfully.
+    ConstEvaluatable(I::Const),
+}
+
+impl<I: Interner> Clone for ClauseKind<I> {
+    fn clone(&self) -> Self {
+        match self {
+            Self::Trait(arg0) => Self::Trait(arg0.clone()),
+            Self::RegionOutlives(arg0) => Self::RegionOutlives(arg0.clone()),
+            Self::TypeOutlives(arg0) => Self::TypeOutlives(arg0.clone()),
+            Self::Projection(arg0) => Self::Projection(arg0.clone()),
+            Self::ConstArgHasType(arg0, arg1) => Self::ConstArgHasType(arg0.clone(), arg1.clone()),
+            Self::WellFormed(arg0) => Self::WellFormed(arg0.clone()),
+            Self::ConstEvaluatable(arg0) => Self::ConstEvaluatable(arg0.clone()),
+        }
+    }
+}
+
+impl<I: Interner> Copy for ClauseKind<I>
+where
+    I::Ty: Copy,
+    I::Const: Copy,
+    I::GenericArg: Copy,
+    I::TraitPredicate: Copy,
+    I::ProjectionPredicate: Copy,
+    I::TypeOutlivesPredicate: Copy,
+    I::RegionOutlivesPredicate: Copy,
+{
+}
+
+impl<I: Interner> PartialEq for ClauseKind<I> {
+    fn eq(&self, other: &Self) -> bool {
+        match (self, other) {
+            (Self::Trait(l0), Self::Trait(r0)) => l0 == r0,
+            (Self::RegionOutlives(l0), Self::RegionOutlives(r0)) => l0 == r0,
+            (Self::TypeOutlives(l0), Self::TypeOutlives(r0)) => l0 == r0,
+            (Self::Projection(l0), Self::Projection(r0)) => l0 == r0,
+            (Self::ConstArgHasType(l0, l1), Self::ConstArgHasType(r0, r1)) => l0 == r0 && l1 == r1,
+            (Self::WellFormed(l0), Self::WellFormed(r0)) => l0 == r0,
+            (Self::ConstEvaluatable(l0), Self::ConstEvaluatable(r0)) => l0 == r0,
+            _ => false,
+        }
+    }
+}
+
+impl<I: Interner> Eq for ClauseKind<I> {}
+
+fn clause_kind_discriminant<I: Interner>(value: &ClauseKind<I>) -> usize {
+    match value {
+        ClauseKind::Trait(_) => 0,
+        ClauseKind::RegionOutlives(_) => 1,
+        ClauseKind::TypeOutlives(_) => 2,
+        ClauseKind::Projection(_) => 3,
+        ClauseKind::ConstArgHasType(_, _) => 4,
+        ClauseKind::WellFormed(_) => 5,
+        ClauseKind::ConstEvaluatable(_) => 6,
+    }
+}
+
+impl<I: Interner> hash::Hash for ClauseKind<I> {
+    fn hash<H: hash::Hasher>(&self, state: &mut H) {
+        clause_kind_discriminant(self).hash(state);
+        match self {
+            ClauseKind::Trait(p) => p.hash(state),
+            ClauseKind::RegionOutlives(p) => p.hash(state),
+            ClauseKind::TypeOutlives(p) => p.hash(state),
+            ClauseKind::Projection(p) => p.hash(state),
+            ClauseKind::ConstArgHasType(c, t) => {
+                c.hash(state);
+                t.hash(state);
+            }
+            ClauseKind::WellFormed(t) => t.hash(state),
+            ClauseKind::ConstEvaluatable(c) => c.hash(state),
+        }
+    }
+}
+
+impl<CTX: HashStableContext, I: Interner> HashStable<CTX> for ClauseKind<I>
+where
+    I::Ty: HashStable<CTX>,
+    I::Const: HashStable<CTX>,
+    I::GenericArg: HashStable<CTX>,
+    I::TraitPredicate: HashStable<CTX>,
+    I::ProjectionPredicate: HashStable<CTX>,
+    I::TypeOutlivesPredicate: HashStable<CTX>,
+    I::RegionOutlivesPredicate: HashStable<CTX>,
+{
+    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+        clause_kind_discriminant(self).hash_stable(hcx, hasher);
+        match self {
+            ClauseKind::Trait(p) => p.hash_stable(hcx, hasher),
+            ClauseKind::RegionOutlives(p) => p.hash_stable(hcx, hasher),
+            ClauseKind::TypeOutlives(p) => p.hash_stable(hcx, hasher),
+            ClauseKind::Projection(p) => p.hash_stable(hcx, hasher),
+            ClauseKind::ConstArgHasType(c, t) => {
+                c.hash_stable(hcx, hasher);
+                t.hash_stable(hcx, hasher);
+            }
+            ClauseKind::WellFormed(t) => t.hash_stable(hcx, hasher),
+            ClauseKind::ConstEvaluatable(c) => c.hash_stable(hcx, hasher),
+        }
+    }
+}
+
+impl<I: Interner> TypeFoldable<I> for ClauseKind<I>
+where
+    I::Ty: TypeFoldable<I>,
+    I::Const: TypeFoldable<I>,
+    I::GenericArg: TypeFoldable<I>,
+    I::TraitPredicate: TypeFoldable<I>,
+    I::ProjectionPredicate: TypeFoldable<I>,
+    I::TypeOutlivesPredicate: TypeFoldable<I>,
+    I::RegionOutlivesPredicate: TypeFoldable<I>,
+{
+    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        Ok(match self {
+            ClauseKind::Trait(p) => ClauseKind::Trait(p.try_fold_with(folder)?),
+            ClauseKind::RegionOutlives(p) => ClauseKind::RegionOutlives(p.try_fold_with(folder)?),
+            ClauseKind::TypeOutlives(p) => ClauseKind::TypeOutlives(p.try_fold_with(folder)?),
+            ClauseKind::Projection(p) => ClauseKind::Projection(p.try_fold_with(folder)?),
+            ClauseKind::ConstArgHasType(c, t) => {
+                ClauseKind::ConstArgHasType(c.try_fold_with(folder)?, t.try_fold_with(folder)?)
+            }
+            ClauseKind::WellFormed(p) => ClauseKind::WellFormed(p.try_fold_with(folder)?),
+            ClauseKind::ConstEvaluatable(p) => {
+                ClauseKind::ConstEvaluatable(p.try_fold_with(folder)?)
+            }
+        })
+    }
+}
+
+impl<I: Interner> TypeVisitable<I> for ClauseKind<I>
+where
+    I::Ty: TypeVisitable<I>,
+    I::Const: TypeVisitable<I>,
+    I::GenericArg: TypeVisitable<I>,
+    I::TraitPredicate: TypeVisitable<I>,
+    I::ProjectionPredicate: TypeVisitable<I>,
+    I::TypeOutlivesPredicate: TypeVisitable<I>,
+    I::RegionOutlivesPredicate: TypeVisitable<I>,
+{
+    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        match self {
+            ClauseKind::Trait(p) => p.visit_with(visitor),
+            ClauseKind::RegionOutlives(p) => p.visit_with(visitor),
+            ClauseKind::TypeOutlives(p) => p.visit_with(visitor),
+            ClauseKind::Projection(p) => p.visit_with(visitor),
+            ClauseKind::ConstArgHasType(c, t) => {
+                c.visit_with(visitor)?;
+                t.visit_with(visitor)
+            }
+            ClauseKind::WellFormed(p) => p.visit_with(visitor),
+            ClauseKind::ConstEvaluatable(p) => p.visit_with(visitor),
+        }
+    }
+}
+
+impl<I: Interner, D: TyDecoder<I = I>> Decodable<D> for ClauseKind<I>
+where
+    I::Ty: Decodable<D>,
+    I::Const: Decodable<D>,
+    I::GenericArg: Decodable<D>,
+    I::TraitPredicate: Decodable<D>,
+    I::ProjectionPredicate: Decodable<D>,
+    I::TypeOutlivesPredicate: Decodable<D>,
+    I::RegionOutlivesPredicate: Decodable<D>,
+{
+    fn decode(d: &mut D) -> Self {
+        match Decoder::read_usize(d) {
+            0 => ClauseKind::Trait(Decodable::decode(d)),
+            1 => ClauseKind::RegionOutlives(Decodable::decode(d)),
+            2 => ClauseKind::TypeOutlives(Decodable::decode(d)),
+            3 => ClauseKind::Projection(Decodable::decode(d)),
+            4 => ClauseKind::ConstArgHasType(Decodable::decode(d), Decodable::decode(d)),
+            5 => ClauseKind::WellFormed(Decodable::decode(d)),
+            6 => ClauseKind::ConstEvaluatable(Decodable::decode(d)),
+            _ => panic!(
+                "{}",
+                format!(
+                    "invalid enum variant tag while decoding `{}`, expected 0..{}",
+                    "ClauseKind", 7,
+                )
+            ),
+        }
+    }
+}
+
+impl<I: Interner, E: TyEncoder> Encodable<E> for ClauseKind<I>
+where
+    I::Ty: Encodable<E>,
+    I::Const: Encodable<E>,
+    I::GenericArg: Encodable<E>,
+    I::TraitPredicate: Encodable<E>,
+    I::ProjectionPredicate: Encodable<E>,
+    I::TypeOutlivesPredicate: Encodable<E>,
+    I::RegionOutlivesPredicate: Encodable<E>,
+{
+    fn encode(&self, s: &mut E) {
+        let discriminant = clause_kind_discriminant(self);
+        match self {
+            ClauseKind::Trait(p) => s.emit_enum_variant(discriminant, |s| p.encode(s)),
+            ClauseKind::RegionOutlives(p) => s.emit_enum_variant(discriminant, |s| p.encode(s)),
+            ClauseKind::TypeOutlives(p) => s.emit_enum_variant(discriminant, |s| p.encode(s)),
+            ClauseKind::Projection(p) => s.emit_enum_variant(discriminant, |s| p.encode(s)),
+            ClauseKind::ConstArgHasType(c, t) => s.emit_enum_variant(discriminant, |s| {
+                c.encode(s);
+                t.encode(s);
+            }),
+            ClauseKind::WellFormed(p) => s.emit_enum_variant(discriminant, |s| p.encode(s)),
+            ClauseKind::ConstEvaluatable(p) => s.emit_enum_variant(discriminant, |s| p.encode(s)),
+        }
+    }
+}
+
+pub enum PredicateKind<I: Interner> {
+    /// Prove a clause
+    Clause(ClauseKind<I>),
+
+    /// Trait must be object-safe.
+    ObjectSafe(I::DefId),
+
+    /// No direct syntax. May be thought of as `where T: FnFoo<...>`
+    /// for some generic args `...` and `T` being a closure type.
+    /// Satisfied (or refuted) once we know the closure's kind.
+    ClosureKind(I::DefId, I::GenericArgs, I::ClosureKind),
+
+    /// `T1 <: T2`
+    ///
+    /// This obligation is created most often when we have two
+    /// unresolved type variables and hence don't have enough
+    /// information to process the subtyping obligation yet.
+    Subtype(I::SubtypePredicate),
+
+    /// `T1` coerced to `T2`
+    ///
+    /// Like a subtyping obligation, this is created most often
+    /// when we have two unresolved type variables and hence
+    /// don't have enough information to process the coercion
+    /// obligation yet. At the moment, we actually process coercions
+    /// very much like subtyping and don't handle the full coercion
+    /// logic.
+    Coerce(I::CoercePredicate),
+
+    /// Constants must be equal. The first component is the const that is expected.
+    ConstEquate(I::Const, I::Const),
+
+    /// A marker predicate that is always ambiguous.
+    /// Used for coherence to mark opaque types as possibly equal to each other but ambiguous.
+    Ambiguous,
+
+    /// Separate from `ClauseKind::Projection` which is used for normalization in new solver.
+    /// This predicate requires two terms to be equal to eachother.
+    ///
+    /// Only used for new solver
+    AliasRelate(I::Term, I::Term, AliasRelationDirection),
+}
+
+impl<I: Interner> Copy for PredicateKind<I>
+where
+    I::DefId: Copy,
+    I::Const: Copy,
+    I::GenericArgs: Copy,
+    I::Term: Copy,
+    I::CoercePredicate: Copy,
+    I::SubtypePredicate: Copy,
+    I::ClosureKind: Copy,
+    ClauseKind<I>: Copy,
+{
+}
+
+impl<I: Interner> Clone for PredicateKind<I> {
+    fn clone(&self) -> Self {
+        match self {
+            Self::Clause(arg0) => Self::Clause(arg0.clone()),
+            Self::ObjectSafe(arg0) => Self::ObjectSafe(arg0.clone()),
+            Self::ClosureKind(arg0, arg1, arg2) => {
+                Self::ClosureKind(arg0.clone(), arg1.clone(), arg2.clone())
+            }
+            Self::Subtype(arg0) => Self::Subtype(arg0.clone()),
+            Self::Coerce(arg0) => Self::Coerce(arg0.clone()),
+            Self::ConstEquate(arg0, arg1) => Self::ConstEquate(arg0.clone(), arg1.clone()),
+            Self::Ambiguous => Self::Ambiguous,
+            Self::AliasRelate(arg0, arg1, arg2) => {
+                Self::AliasRelate(arg0.clone(), arg1.clone(), arg2.clone())
+            }
+        }
+    }
+}
+
+impl<I: Interner> PartialEq for PredicateKind<I> {
+    fn eq(&self, other: &Self) -> bool {
+        match (self, other) {
+            (Self::Clause(l0), Self::Clause(r0)) => l0 == r0,
+            (Self::ObjectSafe(l0), Self::ObjectSafe(r0)) => l0 == r0,
+            (Self::ClosureKind(l0, l1, l2), Self::ClosureKind(r0, r1, r2)) => {
+                l0 == r0 && l1 == r1 && l2 == r2
+            }
+            (Self::Subtype(l0), Self::Subtype(r0)) => l0 == r0,
+            (Self::Coerce(l0), Self::Coerce(r0)) => l0 == r0,
+            (Self::ConstEquate(l0, l1), Self::ConstEquate(r0, r1)) => l0 == r0 && l1 == r1,
+            (Self::AliasRelate(l0, l1, l2), Self::AliasRelate(r0, r1, r2)) => {
+                l0 == r0 && l1 == r1 && l2 == r2
+            }
+            _ => core::mem::discriminant(self) == core::mem::discriminant(other),
+        }
+    }
+}
+
+impl<I: Interner> Eq for PredicateKind<I> {}
+
+fn predicate_kind_discriminant<I: Interner>(value: &PredicateKind<I>) -> usize {
+    match value {
+        PredicateKind::Clause(_) => 0,
+        PredicateKind::ObjectSafe(_) => 1,
+        PredicateKind::ClosureKind(_, _, _) => 2,
+        PredicateKind::Subtype(_) => 3,
+        PredicateKind::Coerce(_) => 4,
+        PredicateKind::ConstEquate(_, _) => 5,
+        PredicateKind::Ambiguous => 6,
+        PredicateKind::AliasRelate(_, _, _) => 7,
+    }
+}
+
+impl<I: Interner> hash::Hash for PredicateKind<I> {
+    fn hash<H: hash::Hasher>(&self, state: &mut H) {
+        predicate_kind_discriminant(self).hash(state);
+        match self {
+            PredicateKind::Clause(p) => p.hash(state),
+            PredicateKind::ObjectSafe(d) => d.hash(state),
+            PredicateKind::ClosureKind(d, g, k) => {
+                d.hash(state);
+                g.hash(state);
+                k.hash(state);
+            }
+            PredicateKind::Subtype(p) => p.hash(state),
+            PredicateKind::Coerce(p) => p.hash(state),
+            PredicateKind::ConstEquate(c1, c2) => {
+                c1.hash(state);
+                c2.hash(state);
+            }
+            PredicateKind::Ambiguous => {}
+            PredicateKind::AliasRelate(t1, t2, r) => {
+                t1.hash(state);
+                t2.hash(state);
+                r.hash(state);
+            }
+        }
+    }
+}
+
+impl<CTX: HashStableContext, I: Interner> HashStable<CTX> for PredicateKind<I>
+where
+    I::DefId: HashStable<CTX>,
+    I::Const: HashStable<CTX>,
+    I::GenericArgs: HashStable<CTX>,
+    I::Term: HashStable<CTX>,
+    I::CoercePredicate: HashStable<CTX>,
+    I::SubtypePredicate: HashStable<CTX>,
+    I::ClosureKind: HashStable<CTX>,
+    ClauseKind<I>: HashStable<CTX>,
+{
+    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+        predicate_kind_discriminant(self).hash_stable(hcx, hasher);
+        match self {
+            PredicateKind::Clause(p) => p.hash_stable(hcx, hasher),
+            PredicateKind::ObjectSafe(d) => d.hash_stable(hcx, hasher),
+            PredicateKind::ClosureKind(d, g, k) => {
+                d.hash_stable(hcx, hasher);
+                g.hash_stable(hcx, hasher);
+                k.hash_stable(hcx, hasher);
+            }
+            PredicateKind::Subtype(p) => p.hash_stable(hcx, hasher),
+            PredicateKind::Coerce(p) => p.hash_stable(hcx, hasher),
+            PredicateKind::ConstEquate(c1, c2) => {
+                c1.hash_stable(hcx, hasher);
+                c2.hash_stable(hcx, hasher);
+            }
+            PredicateKind::Ambiguous => {}
+            PredicateKind::AliasRelate(t1, t2, r) => {
+                t1.hash_stable(hcx, hasher);
+                t2.hash_stable(hcx, hasher);
+                r.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl<I: Interner> TypeFoldable<I> for PredicateKind<I>
+where
+    I::DefId: TypeFoldable<I>,
+    I::Const: TypeFoldable<I>,
+    I::GenericArgs: TypeFoldable<I>,
+    I::Term: TypeFoldable<I>,
+    I::CoercePredicate: TypeFoldable<I>,
+    I::SubtypePredicate: TypeFoldable<I>,
+    I::ClosureKind: TypeFoldable<I>,
+    ClauseKind<I>: TypeFoldable<I>,
+{
+    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        Ok(match self {
+            PredicateKind::Clause(c) => PredicateKind::Clause(c.try_fold_with(folder)?),
+            PredicateKind::ObjectSafe(d) => PredicateKind::ObjectSafe(d.try_fold_with(folder)?),
+            PredicateKind::ClosureKind(d, g, k) => PredicateKind::ClosureKind(
+                d.try_fold_with(folder)?,
+                g.try_fold_with(folder)?,
+                k.try_fold_with(folder)?,
+            ),
+            PredicateKind::Subtype(s) => PredicateKind::Subtype(s.try_fold_with(folder)?),
+            PredicateKind::Coerce(s) => PredicateKind::Coerce(s.try_fold_with(folder)?),
+            PredicateKind::ConstEquate(a, b) => {
+                PredicateKind::ConstEquate(a.try_fold_with(folder)?, b.try_fold_with(folder)?)
+            }
+            PredicateKind::Ambiguous => PredicateKind::Ambiguous,
+            PredicateKind::AliasRelate(a, b, d) => PredicateKind::AliasRelate(
+                a.try_fold_with(folder)?,
+                b.try_fold_with(folder)?,
+                d.try_fold_with(folder)?,
+            ),
+        })
+    }
+}
+
+impl<I: Interner> TypeVisitable<I> for PredicateKind<I>
+where
+    I::DefId: TypeVisitable<I>,
+    I::Const: TypeVisitable<I>,
+    I::GenericArgs: TypeVisitable<I>,
+    I::Term: TypeVisitable<I>,
+    I::CoercePredicate: TypeVisitable<I>,
+    I::SubtypePredicate: TypeVisitable<I>,
+    I::ClosureKind: TypeVisitable<I>,
+    ClauseKind<I>: TypeVisitable<I>,
+{
+    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        match self {
+            PredicateKind::Clause(p) => p.visit_with(visitor),
+            PredicateKind::ObjectSafe(d) => d.visit_with(visitor),
+            PredicateKind::ClosureKind(d, g, k) => {
+                d.visit_with(visitor)?;
+                g.visit_with(visitor)?;
+                k.visit_with(visitor)
+            }
+            PredicateKind::Subtype(s) => s.visit_with(visitor),
+            PredicateKind::Coerce(s) => s.visit_with(visitor),
+            PredicateKind::ConstEquate(a, b) => {
+                a.visit_with(visitor)?;
+                b.visit_with(visitor)
+            }
+            PredicateKind::Ambiguous => ControlFlow::Continue(()),
+            PredicateKind::AliasRelate(a, b, d) => {
+                a.visit_with(visitor)?;
+                b.visit_with(visitor)?;
+                d.visit_with(visitor)
+            }
+        }
+    }
+}
+
+impl<I: Interner, D: TyDecoder<I = I>> Decodable<D> for PredicateKind<I>
+where
+    I::DefId: Decodable<D>,
+    I::Const: Decodable<D>,
+    I::GenericArgs: Decodable<D>,
+    I::Term: Decodable<D>,
+    I::CoercePredicate: Decodable<D>,
+    I::SubtypePredicate: Decodable<D>,
+    I::ClosureKind: Decodable<D>,
+    ClauseKind<I>: Decodable<D>,
+{
+    fn decode(d: &mut D) -> Self {
+        match Decoder::read_usize(d) {
+            0 => PredicateKind::Clause(Decodable::decode(d)),
+            1 => PredicateKind::ObjectSafe(Decodable::decode(d)),
+            2 => PredicateKind::ClosureKind(
+                Decodable::decode(d),
+                Decodable::decode(d),
+                Decodable::decode(d),
+            ),
+            3 => PredicateKind::Subtype(Decodable::decode(d)),
+            4 => PredicateKind::Coerce(Decodable::decode(d)),
+            5 => PredicateKind::ConstEquate(Decodable::decode(d), Decodable::decode(d)),
+            6 => PredicateKind::Ambiguous,
+            7 => PredicateKind::AliasRelate(
+                Decodable::decode(d),
+                Decodable::decode(d),
+                Decodable::decode(d),
+            ),
+            _ => panic!(
+                "{}",
+                format!(
+                    "invalid enum variant tag while decoding `{}`, expected 0..{}",
+                    "PredicateKind", 8,
+                )
+            ),
+        }
+    }
+}
+
+impl<I: Interner, E: TyEncoder> Encodable<E> for PredicateKind<I>
+where
+    I::DefId: Encodable<E>,
+    I::Const: Encodable<E>,
+    I::GenericArgs: Encodable<E>,
+    I::Term: Encodable<E>,
+    I::CoercePredicate: Encodable<E>,
+    I::SubtypePredicate: Encodable<E>,
+    I::ClosureKind: Encodable<E>,
+    ClauseKind<I>: Encodable<E>,
+{
+    fn encode(&self, s: &mut E) {
+        let discriminant = predicate_kind_discriminant(self);
+        match self {
+            PredicateKind::Clause(c) => s.emit_enum_variant(discriminant, |s| c.encode(s)),
+            PredicateKind::ObjectSafe(d) => s.emit_enum_variant(discriminant, |s| d.encode(s)),
+            PredicateKind::ClosureKind(d, g, k) => s.emit_enum_variant(discriminant, |s| {
+                d.encode(s);
+                g.encode(s);
+                k.encode(s);
+            }),
+            PredicateKind::Subtype(c) => s.emit_enum_variant(discriminant, |s| c.encode(s)),
+            PredicateKind::Coerce(c) => s.emit_enum_variant(discriminant, |s| c.encode(s)),
+            PredicateKind::ConstEquate(a, b) => s.emit_enum_variant(discriminant, |s| {
+                a.encode(s);
+                b.encode(s);
+            }),
+            PredicateKind::Ambiguous => s.emit_enum_variant(discriminant, |_s| {}),
+            PredicateKind::AliasRelate(a, b, d) => s.emit_enum_variant(discriminant, |s| {
+                a.encode(s);
+                b.encode(s);
+                d.encode(s);
+            }),
+        }
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)]
+#[derive(HashStable_Generic, Encodable, Decodable)]
+pub enum AliasRelationDirection {
+    Equate,
+    Subtype,
+}
+
+impl std::fmt::Display for AliasRelationDirection {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            AliasRelationDirection::Equate => write!(f, "=="),
+            AliasRelationDirection::Subtype => write!(f, "<:"),
+        }
+    }
+}
+
+// FIXME: Convert to DebugWithInfcx impl
+impl<I: Interner> fmt::Debug for ClauseKind<I> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            ClauseKind::ConstArgHasType(ct, ty) => write!(f, "ConstArgHasType({ct:?}, {ty:?})"),
+            ClauseKind::Trait(a) => a.fmt(f),
+            ClauseKind::RegionOutlives(pair) => pair.fmt(f),
+            ClauseKind::TypeOutlives(pair) => pair.fmt(f),
+            ClauseKind::Projection(pair) => pair.fmt(f),
+            ClauseKind::WellFormed(data) => write!(f, "WellFormed({data:?})"),
+            ClauseKind::ConstEvaluatable(ct) => {
+                write!(f, "ConstEvaluatable({ct:?})")
+            }
+        }
+    }
+}
+
+// FIXME: Convert to DebugWithInfcx impl
+impl<I: Interner> fmt::Debug for PredicateKind<I> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            PredicateKind::Clause(a) => a.fmt(f),
+            PredicateKind::Subtype(pair) => pair.fmt(f),
+            PredicateKind::Coerce(pair) => pair.fmt(f),
+            PredicateKind::ObjectSafe(trait_def_id) => {
+                write!(f, "ObjectSafe({trait_def_id:?})")
+            }
+            PredicateKind::ClosureKind(closure_def_id, closure_args, kind) => {
+                write!(f, "ClosureKind({closure_def_id:?}, {closure_args:?}, {kind:?})")
+            }
+            PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({c1:?}, {c2:?})"),
+            PredicateKind::Ambiguous => write!(f, "Ambiguous"),
+            PredicateKind::AliasRelate(t1, t2, dir) => {
+                write!(f, "AliasRelate({t1:?}, {dir:?}, {t2:?})")
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs
index 0006eec4d30..70e2ba3e308 100644
--- a/compiler/rustc_type_ir/src/region_kind.rs
+++ b/compiler/rustc_type_ir/src/region_kind.rs
@@ -1,4 +1,5 @@
 use rustc_data_structures::stable_hasher::HashStable;
+use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_serialize::{Decodable, Decoder, Encodable};
 use std::cmp::Ordering;
 use std::fmt;
@@ -381,11 +382,7 @@ where
     I::PlaceholderRegion: HashStable<CTX>,
 {
     #[inline]
-    fn hash_stable(
-        &self,
-        hcx: &mut CTX,
-        hasher: &mut rustc_data_structures::stable_hasher::StableHasher,
-    ) {
+    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
         std::mem::discriminant(self).hash_stable(hcx, hasher);
         match self {
             ReErased | ReStatic | ReError(_) => {
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index 91bfce9a142..76f85a42b7b 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -640,7 +640,6 @@ where
     I::BoundTy: Encodable<E>,
     I::PlaceholderTy: Encodable<E>,
     I::InferTy: Encodable<E>,
-    I::PredicateKind: Encodable<E>,
     I::AllocId: Encodable<E>,
 {
     fn encode(&self, e: &mut E) {
@@ -753,7 +752,6 @@ where
     I::BoundTy: Decodable<D>,
     I::PlaceholderTy: Decodable<D>,
     I::InferTy: Decodable<D>,
-    I::PredicateKind: Decodable<D>,
     I::AllocId: Decodable<D>,
 {
     fn decode(d: &mut D) -> Self {
@@ -817,11 +815,7 @@ where
     I::ErrorGuaranteed: HashStable<CTX>,
 {
     #[inline]
-    fn hash_stable(
-        &self,
-        __hcx: &mut CTX,
-        __hasher: &mut rustc_data_structures::stable_hasher::StableHasher,
-    ) {
+    fn hash_stable(&self, __hcx: &mut CTX, __hasher: &mut StableHasher) {
         std::mem::discriminant(self).hash_stable(__hcx, __hasher);
         match self {
             Bool => {}