about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock8
-rw-r--r--compiler/rustc_borrowck/src/lib.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs4
-rw-r--r--compiler/rustc_const_eval/Cargo.toml1
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/traits.rs10
-rw-r--r--compiler/rustc_lint/Cargo.toml1
-rw-r--r--compiler/rustc_lint/src/builtin.rs4
-rw-r--r--compiler/rustc_lint/src/internal.rs191
-rw-r--r--compiler/rustc_macros/src/serialize.rs4
-rw-r--r--compiler/rustc_metadata/Cargo.toml1
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs8
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs4
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs12
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs4
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs191
-rw-r--r--compiler/rustc_middle/src/ty/context.rs134
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs2
-rw-r--r--compiler/rustc_middle/src/ty/fast_reject.rs8
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/mod.rs3
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs38
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs200
-rw-r--r--compiler/rustc_middle/src/ty/subst.rs14
-rw-r--r--compiler/rustc_middle/src/ty/vtable.rs9
-rw-r--r--compiler/rustc_mir_transform/src/coverage/tests.rs6
-rw-r--r--compiler/rustc_query_impl/Cargo.toml1
-rw-r--r--compiler/rustc_query_impl/src/on_disk_cache.rs12
-rw-r--r--compiler/rustc_query_system/Cargo.toml1
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs4
-rw-r--r--compiler/rustc_ty_utils/Cargo.toml1
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs2
-rw-r--r--compiler/rustc_type_ir/Cargo.toml1
-rw-r--r--compiler/rustc_type_ir/src/codec.rs67
-rw-r--r--compiler/rustc_type_ir/src/lib.rs136
-rw-r--r--compiler/rustc_type_ir/src/sty.rs1040
-rw-r--r--compiler/rustc_typeck/Cargo.toml1
-rw-r--r--compiler/rustc_typeck/src/check/demand.rs2
-rw-r--r--compiler/rustc_typeck/src/check/intrinsicck.rs2
-rw-r--r--compiler/rustc_typeck/src/check/op.rs2
-rw-r--r--compiler/rustc_typeck/src/coherence/builtin.rs2
-rw-r--r--src/test/run-make-fulldeps/obtain-borrowck/driver.rs2
-rw-r--r--src/test/ui-fulldeps/internal-lints/ty_tykind_usage.rs60
-rw-r--r--src/test/ui-fulldeps/internal-lints/ty_tykind_usage.stderr146
45 files changed, 1732 insertions, 630 deletions
diff --git a/Cargo.lock b/Cargo.lock
index eb0197d770f..402e734dc76 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3676,6 +3676,7 @@ dependencies = [
  "rustc_span",
  "rustc_target",
  "rustc_trait_selection",
+ "rustc_type_ir",
  "tracing",
 ]
 
@@ -3969,6 +3970,7 @@ dependencies = [
  "rustc_span",
  "rustc_target",
  "rustc_trait_selection",
+ "rustc_type_ir",
  "tracing",
  "unicode-security",
 ]
@@ -4041,6 +4043,7 @@ dependencies = [
  "rustc_session",
  "rustc_span",
  "rustc_target",
+ "rustc_type_ir",
  "smallvec",
  "snap",
  "tracing",
@@ -4262,6 +4265,7 @@ dependencies = [
  "rustc_serialize",
  "rustc_session",
  "rustc_span",
+ "rustc_type_ir",
  "tracing",
 ]
 
@@ -4283,6 +4287,7 @@ dependencies = [
  "rustc_session",
  "rustc_span",
  "rustc_target",
+ "rustc_type_ir",
  "smallvec",
  "tracing",
 ]
@@ -4472,6 +4477,7 @@ dependencies = [
  "rustc_span",
  "rustc_target",
  "rustc_trait_selection",
+ "rustc_type_ir",
  "tracing",
 ]
 
@@ -4484,6 +4490,7 @@ dependencies = [
  "rustc_index",
  "rustc_macros",
  "rustc_serialize",
+ "smallvec",
 ]
 
 [[package]]
@@ -4509,6 +4516,7 @@ dependencies = [
  "rustc_target",
  "rustc_trait_selection",
  "rustc_ty_utils",
+ "rustc_type_ir",
  "smallvec",
  "tracing",
 ]
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index d3aea1fd61c..bf38ca19484 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -98,7 +98,11 @@ struct Upvar<'tcx> {
     by_ref: bool,
 }
 
-const DEREF_PROJECTION: &[PlaceElem<'_>; 1] = &[ProjectionElem::Deref];
+/// Associate some local constants with the `'tcx` lifetime
+struct TyCtxtConsts<'tcx>(TyCtxt<'tcx>);
+impl<'tcx> TyCtxtConsts<'tcx> {
+    const DEREF_PROJECTION: &'tcx [PlaceElem<'tcx>; 1] = &[ProjectionElem::Deref];
+}
 
 pub fn provide(providers: &mut Providers) {
     *providers = Providers {
@@ -1443,7 +1447,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 // Thread-locals might be dropped after the function exits
                 // We have to dereference the outer reference because
                 // borrows don't conflict behind shared references.
-                root_place.projection = DEREF_PROJECTION;
+                root_place.projection = TyCtxtConsts::DEREF_PROJECTION;
                 (true, true)
             } else {
                 (false, self.locals_are_invalidated_at_exit)
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 97d3acb34ce..dd3adbf70a6 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -33,7 +33,7 @@ use rustc_middle::mir::{self, GeneratorLayout};
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, AdtKind, Instance, ParamEnv, Ty, TyCtxt, COMMON_VTABLE_ENTRIES};
+use rustc_middle::ty::{self, AdtKind, Instance, ParamEnv, Ty, TyCtxt};
 use rustc_session::config::{self, DebugInfo};
 use rustc_span::symbol::Symbol;
 use rustc_span::FileName;
@@ -1392,7 +1392,7 @@ fn build_vtable_type_di_node<'ll, 'tcx>(
 
         tcx.vtable_entries(trait_ref)
     } else {
-        COMMON_VTABLE_ENTRIES
+        TyCtxt::COMMON_VTABLE_ENTRIES
     };
 
     // All function pointers are described as opaque pointers. This could be improved in the future
diff --git a/compiler/rustc_const_eval/Cargo.toml b/compiler/rustc_const_eval/Cargo.toml
index 4ed908a3833..32e8233a041 100644
--- a/compiler/rustc_const_eval/Cargo.toml
+++ b/compiler/rustc_const_eval/Cargo.toml
@@ -24,3 +24,4 @@ rustc_session = { path = "../rustc_session" }
 rustc_target = { path = "../rustc_target" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
 rustc_span = { path = "../rustc_span" }
+rustc_type_ir = { path = "../rustc_type_ir" }
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index 7cd2ba34b04..be34a77bdba 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -8,6 +8,7 @@ use rustc_middle::ty::adjustment::PointerCast;
 use rustc_middle::ty::layout::{IntegerExt, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, FloatTy, Ty, TypeAndMut};
 use rustc_target::abi::{Integer, Variants};
+use rustc_type_ir::sty::TyKind::*;
 
 use super::{
     util::ensure_monomorphic_enough, FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy,
@@ -102,7 +103,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         src: &ImmTy<'tcx, M::PointerTag>,
         cast_ty: Ty<'tcx>,
     ) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
-        use rustc_middle::ty::TyKind::*;
+        use rustc_type_ir::sty::TyKind::*;
         trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, cast_ty);
 
         match src.layout.ty.kind() {
@@ -205,7 +206,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let v = scalar.to_bits(src_layout.size)?;
         let v = if signed { self.sign_extend(v, src_layout) } else { v };
         trace!("cast_from_scalar: {}, {} -> {}", v, src_layout.ty, cast_ty);
-        use rustc_middle::ty::TyKind::*;
 
         Ok(match *cast_ty.kind() {
             Int(_) | Uint(_) => {
@@ -247,7 +247,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     where
         F: Float + Into<Scalar<M::PointerTag>> + FloatConvert<Single> + FloatConvert<Double>,
     {
-        use rustc_middle::ty::TyKind::*;
+        use rustc_type_ir::sty::TyKind::*;
         match *dest_ty.kind() {
             // float -> uint
             Uint(t) => {
diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs
index 235938422a8..c4d1074e437 100644
--- a/compiler/rustc_const_eval/src/interpret/traits.rs
+++ b/compiler/rustc_const_eval/src/interpret/traits.rs
@@ -2,8 +2,8 @@ use std::convert::TryFrom;
 
 use rustc_middle::mir::interpret::{InterpResult, Pointer, PointerArithmetic};
 use rustc_middle::ty::{
-    self, Ty, COMMON_VTABLE_ENTRIES, COMMON_VTABLE_ENTRIES_ALIGN,
-    COMMON_VTABLE_ENTRIES_DROPINPLACE, COMMON_VTABLE_ENTRIES_SIZE,
+    self, Ty, TyCtxt, COMMON_VTABLE_ENTRIES_ALIGN, COMMON_VTABLE_ENTRIES_DROPINPLACE,
+    COMMON_VTABLE_ENTRIES_SIZE,
 };
 use rustc_target::abi::{Align, Size};
 
@@ -38,7 +38,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     }
 
     /// Resolves the function at the specified slot in the provided
-    /// vtable. Currently an index of '3' (`COMMON_VTABLE_ENTRIES.len()`)
+    /// vtable. Currently an index of '3' (`TyCtxt::COMMON_VTABLE_ENTRIES.len()`)
     /// corresponds to the first method declared in the trait of the provided vtable.
     pub fn get_vtable_slot(
         &self,
@@ -64,7 +64,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let vtable = self
             .get_ptr_alloc(
                 vtable,
-                pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES.len()).unwrap(),
+                pointer_size * u64::try_from(TyCtxt::COMMON_VTABLE_ENTRIES.len()).unwrap(),
                 self.tcx.data_layout.pointer_align.abi,
             )?
             .expect("cannot be a ZST");
@@ -99,7 +99,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let vtable = self
             .get_ptr_alloc(
                 vtable,
-                pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES.len()).unwrap(),
+                pointer_size * u64::try_from(TyCtxt::COMMON_VTABLE_ENTRIES.len()).unwrap(),
                 self.tcx.data_layout.pointer_align.abi,
             )?
             .expect("cannot be a ZST");
diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml
index 02f747eeccc..fab60b6f609 100644
--- a/compiler/rustc_lint/Cargo.toml
+++ b/compiler/rustc_lint/Cargo.toml
@@ -21,3 +21,4 @@ rustc_session = { path = "../rustc_session" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
 rustc_parse_format = { path = "../rustc_parse_format" }
 rustc_infer = { path = "../rustc_infer" }
+rustc_type_ir = { path = "../rustc_type_ir" }
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 9317858aed9..6be78c52f99 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -2489,7 +2489,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
             ty: Ty<'tcx>,
             init: InitKind,
         ) -> Option<InitError> {
-            use rustc_middle::ty::TyKind::*;
+            use rustc_type_ir::sty::TyKind::*;
             match ty.kind() {
                 // Primitive types that don't like 0 as a value.
                 Ref(..) => Some(("references must be non-null".to_string(), None)),
@@ -2801,7 +2801,7 @@ impl ClashingExternDeclarations {
                 true
             } else {
                 // Do a full, depth-first comparison between the two.
-                use rustc_middle::ty::TyKind::*;
+                use rustc_type_ir::sty::TyKind::*;
                 let a_kind = a.kind();
                 let b_kind = b.kind();
 
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 27d44da6dfc..b83d63e0da0 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -5,8 +5,8 @@ use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}
 use rustc_ast as ast;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
-use rustc_hir::{Expr, ExprKind, GenericArg, Path, PathSegment, QPath};
-use rustc_hir::{HirId, Item, ItemKind, Node, Ty, TyKind};
+use rustc_hir::{Expr, ExprKind, GenericArg, PatKind, Path, PathSegment, QPath};
+use rustc_hir::{HirId, Item, ItemKind, Node, Pat, Ty, TyKind};
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::hygiene::{ExpnKind, MacroKind};
@@ -123,55 +123,115 @@ declare_lint_pass!(TyTyKind => [
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for TyTyKind {
-    fn check_path(&mut self, cx: &LateContext<'_>, path: &'tcx Path<'tcx>, _: HirId) {
-        let segments = path.segments.iter().rev().skip(1).rev();
-
-        if let Some(last) = segments.last() {
-            let span = path.span.with_hi(last.ident.span.hi());
-            if lint_ty_kind_usage(cx, last) {
-                cx.struct_span_lint(USAGE_OF_TY_TYKIND, span, |lint| {
-                    lint.build("usage of `ty::TyKind::<kind>`")
-                        .span_suggestion(
-                            span,
-                            "try using ty::<kind> directly",
-                            "ty".to_string(),
-                            Applicability::MaybeIncorrect, // ty maybe needs an import
-                        )
-                        .emit();
-                })
-            }
+    fn check_path(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        path: &'tcx rustc_hir::Path<'tcx>,
+        _: rustc_hir::HirId,
+    ) {
+        if let Some(segment) = path.segments.iter().nth_back(1)
+        && let Some(res) = &segment.res
+        && lint_ty_kind_usage(cx, res)
+        {
+            let span = path.span.with_hi(
+                segment.args.map_or(segment.ident.span, |a| a.span_ext).hi()
+            );
+            cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| {
+                lint.build("usage of `ty::TyKind::<kind>`")
+                    .span_suggestion(
+                        span,
+                        "try using `ty::<kind>` directly",
+                        "ty".to_string(),
+                        Applicability::MaybeIncorrect, // ty maybe needs an import
+                    )
+                    .emit();
+            });
         }
     }
 
     fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx Ty<'tcx>) {
         match &ty.kind {
             TyKind::Path(QPath::Resolved(_, path)) => {
-                if let Some(last) = path.segments.iter().last() {
-                    if lint_ty_kind_usage(cx, last) {
-                        cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| {
-                            lint.build("usage of `ty::TyKind`")
-                                .help("try using `Ty` instead")
-                                .emit();
-                        })
-                    } else {
-                        if ty.span.from_expansion() {
-                            return;
-                        }
-                        if let Some(t) = is_ty_or_ty_ctxt(cx, ty) {
-                            if path.segments.len() > 1 {
-                                cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, |lint| {
-                                    lint.build(&format!("usage of qualified `ty::{}`", t))
+                if lint_ty_kind_usage(cx, &path.res) {
+                    cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| {
+                        let hir = cx.tcx.hir();
+                        match hir.find(hir.get_parent_node(ty.hir_id)) {
+                            Some(Node::Pat(Pat {
+                                kind:
+                                    PatKind::Path(qpath)
+                                    | PatKind::TupleStruct(qpath, ..)
+                                    | PatKind::Struct(qpath, ..),
+                                ..
+                            })) => {
+                                if let QPath::TypeRelative(qpath_ty, ..) = qpath
+                                    && qpath_ty.hir_id == ty.hir_id
+                                {
+                                    lint.build("usage of `ty::TyKind::<kind>`")
+                                        .span_suggestion(
+                                            path.span,
+                                            "try using `ty::<kind>` directly",
+                                            "ty".to_string(),
+                                            Applicability::MaybeIncorrect, // ty maybe needs an import
+                                        )
+                                        .emit();
+                                    return;
+                                }
+                            }
+                            Some(Node::Expr(Expr {
+                                kind: ExprKind::Path(qpath),
+                                ..
+                            })) => {
+                                if let QPath::TypeRelative(qpath_ty, ..) = qpath
+                                    && qpath_ty.hir_id == ty.hir_id
+                                {
+                                    lint.build("usage of `ty::TyKind::<kind>`")
                                         .span_suggestion(
                                             path.span,
-                                            "try importing it and using it unqualified",
-                                            t,
-                                            // The import probably needs to be changed
-                                            Applicability::MaybeIncorrect,
+                                            "try using `ty::<kind>` directly",
+                                            "ty".to_string(),
+                                            Applicability::MaybeIncorrect, // ty maybe needs an import
                                         )
                                         .emit();
-                                })
+                                    return;
+                                }
                             }
+                            // Can't unify these two branches because qpath below is `&&` and above is `&`
+                            // and `A | B` paths don't play well together with adjustments, apparently.
+                            Some(Node::Expr(Expr {
+                                kind: ExprKind::Struct(qpath, ..),
+                                ..
+                            })) => {
+                                if let QPath::TypeRelative(qpath_ty, ..) = qpath
+                                    && qpath_ty.hir_id == ty.hir_id
+                                {
+                                    lint.build("usage of `ty::TyKind::<kind>`")
+                                        .span_suggestion(
+                                            path.span,
+                                            "try using `ty::<kind>` directly",
+                                            "ty".to_string(),
+                                            Applicability::MaybeIncorrect, // ty maybe needs an import
+                                        )
+                                        .emit();
+                                    return;
+                                }
+                            }
+                            _ => {}
                         }
+                        lint.build("usage of `ty::TyKind`").help("try using `Ty` instead").emit();
+                    })
+                } else if !ty.span.from_expansion() && let Some(t) = is_ty_or_ty_ctxt(cx, &path) {
+                    if path.segments.len() > 1 {
+                        cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, |lint| {
+                            lint.build(&format!("usage of qualified `ty::{}`", t))
+                                .span_suggestion(
+                                    path.span,
+                                    "try importing it and using it unqualified",
+                                    t,
+                                    // The import probably needs to be changed
+                                    Applicability::MaybeIncorrect,
+                                )
+                                .emit();
+                        })
                     }
                 }
             }
@@ -180,42 +240,37 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
     }
 }
 
-fn lint_ty_kind_usage(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> bool {
-    if let Some(res) = segment.res {
-        if let Some(did) = res.opt_def_id() {
-            return cx.tcx.is_diagnostic_item(sym::TyKind, did);
-        }
+fn lint_ty_kind_usage(cx: &LateContext<'_>, res: &Res) -> bool {
+    if let Some(did) = res.opt_def_id() {
+        cx.tcx.is_diagnostic_item(sym::TyKind, did) || cx.tcx.is_diagnostic_item(sym::IrTyKind, did)
+    } else {
+        false
     }
-
-    false
 }
 
-fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, ty: &Ty<'_>) -> Option<String> {
-    if let TyKind::Path(QPath::Resolved(_, path)) = &ty.kind {
-        match path.res {
-            Res::Def(_, def_id) => {
-                if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(def_id) {
-                    return Some(format!("{}{}", name, gen_args(path.segments.last().unwrap())));
-                }
+fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, path: &Path<'_>) -> Option<String> {
+    match &path.res {
+        Res::Def(_, def_id) => {
+            if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(*def_id) {
+                return Some(format!("{}{}", name, gen_args(path.segments.last().unwrap())));
             }
-            // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait.
-            Res::SelfTy { trait_: None, alias_to: Some((did, _)) } => {
-                if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
-                    if let Some(name @ (sym::Ty | sym::TyCtxt)) =
-                        cx.tcx.get_diagnostic_name(adt.did())
-                    {
-                        // NOTE: This path is currently unreachable as `Ty<'tcx>` is
-                        // defined as a type alias meaning that `impl<'tcx> Ty<'tcx>`
-                        // is not actually allowed.
-                        //
-                        // I(@lcnr) still kept this branch in so we don't miss this
-                        // if we ever change it in the future.
-                        return Some(format!("{}<{}>", name, substs[0]));
-                    }
+        }
+        // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait.
+        Res::SelfTy { trait_: None, alias_to: Some((did, _)) } => {
+            if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
+                if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(adt.did())
+                {
+                    // NOTE: This path is currently unreachable as `Ty<'tcx>` is
+                    // defined as a type alias meaning that `impl<'tcx> Ty<'tcx>`
+                    // is not actually allowed.
+                    //
+                    // I(@lcnr) still kept this branch in so we don't miss this
+                    // if we ever change it in the future.
+                    return Some(format!("{}<{}>", name, substs[0]));
                 }
             }
-            _ => (),
         }
+        _ => (),
     }
 
     None
diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs
index 535158ffd8d..a39b4413981 100644
--- a/compiler/rustc_macros/src/serialize.rs
+++ b/compiler/rustc_macros/src/serialize.rs
@@ -8,7 +8,7 @@ pub fn type_decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2:
     if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") {
         s.add_impl_generic(parse_quote! { 'tcx });
     }
-    s.add_impl_generic(parse_quote! {#decoder_ty: ::rustc_middle::ty::codec::TyDecoder<'tcx>});
+    s.add_impl_generic(parse_quote! {#decoder_ty: ::rustc_type_ir::codec::TyDecoder<I = ::rustc_middle::ty::TyCtxt<'tcx>>});
     s.add_bounds(synstructure::AddBounds::Generics);
 
     decodable_body(s, decoder_ty)
@@ -95,7 +95,7 @@ pub fn type_encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2:
         s.add_impl_generic(parse_quote! {'tcx});
     }
     let encoder_ty = quote! { __E };
-    s.add_impl_generic(parse_quote! {#encoder_ty: ::rustc_middle::ty::codec::TyEncoder<'tcx>});
+    s.add_impl_generic(parse_quote! {#encoder_ty: ::rustc_type_ir::codec::TyEncoder<I = ::rustc_middle::ty::TyCtxt<'tcx>>});
     s.add_bounds(synstructure::AddBounds::Generics);
 
     encodable_body(s, encoder_ty, false)
diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml
index 59796dd6529..41224e33461 100644
--- a/compiler/rustc_metadata/Cargo.toml
+++ b/compiler/rustc_metadata/Cargo.toml
@@ -27,3 +27,4 @@ rustc_ast = { path = "../rustc_ast" }
 rustc_expand = { path = "../rustc_expand" }
 rustc_span = { path = "../rustc_span" }
 rustc_session = { path = "../rustc_session" }
+rustc_type_ir = { path = "../rustc_type_ir" }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 7f0b595347f..775ebb48402 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -377,12 +377,14 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> {
+impl<'a, 'tcx> TyDecoder for DecodeContext<'a, 'tcx> {
     const CLEAR_CROSS_CRATE: bool = true;
 
+    type I = TyCtxt<'tcx>;
+
     #[inline]
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx.expect("missing TyCtxt in DecodeContext")
+    fn interner(&self) -> Self::I {
+        self.tcx()
     }
 
     #[inline]
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 339d2fc0867..5a40986307c 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -313,9 +313,11 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Span {
     }
 }
 
-impl<'a, 'tcx> TyEncoder<'tcx> for EncodeContext<'a, 'tcx> {
+impl<'a, 'tcx> TyEncoder for EncodeContext<'a, 'tcx> {
     const CLEAR_CROSS_CRATE: bool = true;
 
+    type I = TyCtxt<'tcx>;
+
     fn position(&self) -> usize {
         self.opaque.position()
     }
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index 16ef8d68be3..06cd6a66e39 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -203,7 +203,7 @@ enum AllocDiscriminant {
     Static,
 }
 
-pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<'tcx>>(
+pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>>(
     encoder: &mut E,
     tcx: TyCtxt<'tcx>,
     alloc_id: AllocId,
@@ -277,7 +277,7 @@ impl<'s> AllocDecodingSession<'s> {
     /// Decodes an `AllocId` in a thread-safe way.
     pub fn decode_alloc_id<'tcx, D>(&self, decoder: &mut D) -> AllocId
     where
-        D: TyDecoder<'tcx>,
+        D: TyDecoder<I = TyCtxt<'tcx>>,
     {
         // Read the index of the allocation.
         let idx = usize::try_from(decoder.read_u32()).unwrap();
@@ -305,7 +305,7 @@ impl<'s> AllocDecodingSession<'s> {
                         AllocDiscriminant::Alloc => {
                             // If this is an allocation, we need to reserve an
                             // `AllocId` so we can decode cyclic graphs.
-                            let alloc_id = decoder.tcx().reserve_alloc_id();
+                            let alloc_id = decoder.interner().reserve_alloc_id();
                             *entry =
                                 State::InProgress(TinyList::new_single(self.session_id), alloc_id);
                             Some(alloc_id)
@@ -349,7 +349,7 @@ impl<'s> AllocDecodingSession<'s> {
                     // We already have a reserved `AllocId`.
                     let alloc_id = alloc_id.unwrap();
                     trace!("decoded alloc {:?}: {:#?}", alloc_id, alloc);
-                    decoder.tcx().set_alloc_id_same_memory(alloc_id, alloc);
+                    decoder.interner().set_alloc_id_same_memory(alloc_id, alloc);
                     alloc_id
                 }
                 AllocDiscriminant::Fn => {
@@ -357,7 +357,7 @@ impl<'s> AllocDecodingSession<'s> {
                     trace!("creating fn alloc ID");
                     let instance = ty::Instance::decode(decoder);
                     trace!("decoded fn alloc instance: {:?}", instance);
-                    let alloc_id = decoder.tcx().create_fn_alloc(instance);
+                    let alloc_id = decoder.interner().create_fn_alloc(instance);
                     alloc_id
                 }
                 AllocDiscriminant::Static => {
@@ -365,7 +365,7 @@ impl<'s> AllocDecodingSession<'s> {
                     trace!("creating extern static alloc ID");
                     let did = <DefId as Decodable<D>>::decode(decoder);
                     trace!("decoded static def-ID: {:?}", did);
-                    let alloc_id = decoder.tcx().create_static_alloc(did);
+                    let alloc_id = decoder.interner().create_static_alloc(did);
                     alloc_id
                 }
             }
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 9f8b22c8afc..71cea005cf8 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -668,7 +668,7 @@ impl<T> ClearCrossCrate<T> {
 const TAG_CLEAR_CROSS_CRATE_CLEAR: u8 = 0;
 const TAG_CLEAR_CROSS_CRATE_SET: u8 = 1;
 
-impl<'tcx, E: TyEncoder<'tcx>, T: Encodable<E>> Encodable<E> for ClearCrossCrate<T> {
+impl<E: TyEncoder, T: Encodable<E>> Encodable<E> for ClearCrossCrate<T> {
     #[inline]
     fn encode(&self, e: &mut E) -> Result<(), E::Error> {
         if E::CLEAR_CROSS_CRATE {
@@ -684,7 +684,7 @@ impl<'tcx, E: TyEncoder<'tcx>, T: Encodable<E>> Encodable<E> for ClearCrossCrate
         }
     }
 }
-impl<'tcx, D: TyDecoder<'tcx>, T: Decodable<D>> Decodable<D> for ClearCrossCrate<T> {
+impl<D: TyDecoder, T: Decodable<D>> Decodable<D> for ClearCrossCrate<T> {
     #[inline]
     fn decode(d: &mut D) -> ClearCrossCrate<T> {
         if D::CLEAR_CROSS_CRATE {
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 2a5191008a9..1e2d1fbeb4b 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -15,10 +15,12 @@ use crate::mir::{
 use crate::thir;
 use crate::traits;
 use crate::ty::subst::SubstsRef;
-use crate::ty::{self, AdtDef, Ty, TyCtxt};
+use crate::ty::{self, AdtDef, Ty};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
+use rustc_middle::ty::TyCtxt;
+use rustc_serialize::{Decodable, Encodable};
 use rustc_span::Span;
+pub use rustc_type_ir::{TyDecoder, TyEncoder};
 use std::hash::Hash;
 use std::intrinsics;
 use std::marker::DiscriminantKind;
@@ -28,13 +30,13 @@ use std::marker::DiscriminantKind;
 /// This offset is also chosen so that the first byte is never < 0x80.
 pub const SHORTHAND_OFFSET: usize = 0x80;
 
-pub trait EncodableWithShorthand<'tcx, E: TyEncoder<'tcx>>: Copy + Eq + Hash {
+pub trait EncodableWithShorthand<E: TyEncoder>: Copy + Eq + Hash {
     type Variant: Encodable<E>;
     fn variant(&self) -> &Self::Variant;
 }
 
 #[allow(rustc::usage_of_ty_tykind)]
-impl<'tcx, E: TyEncoder<'tcx>> EncodableWithShorthand<'tcx, E> for Ty<'tcx> {
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> EncodableWithShorthand<E> for Ty<'tcx> {
     type Variant = ty::TyKind<'tcx>;
 
     #[inline]
@@ -43,7 +45,7 @@ impl<'tcx, E: TyEncoder<'tcx>> EncodableWithShorthand<'tcx, E> for Ty<'tcx> {
     }
 }
 
-impl<'tcx, E: TyEncoder<'tcx>> EncodableWithShorthand<'tcx, E> for ty::PredicateKind<'tcx> {
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> EncodableWithShorthand<E> for ty::PredicateKind<'tcx> {
     type Variant = ty::PredicateKind<'tcx>;
 
     #[inline]
@@ -52,15 +54,6 @@ impl<'tcx, E: TyEncoder<'tcx>> EncodableWithShorthand<'tcx, E> for ty::Predicate
     }
 }
 
-pub trait TyEncoder<'tcx>: Encoder {
-    const CLEAR_CROSS_CRATE: bool;
-
-    fn position(&self) -> usize;
-    fn type_shorthands(&mut self) -> &mut FxHashMap<Ty<'tcx>, usize>;
-    fn predicate_shorthands(&mut self) -> &mut FxHashMap<ty::PredicateKind<'tcx>, usize>;
-    fn encode_alloc_id(&mut self, alloc_id: &AllocId) -> Result<(), Self::Error>;
-}
-
 /// Trait for decoding to a reference.
 ///
 /// This is a separate trait from `Decodable` so that we can implement it for
@@ -71,7 +64,7 @@ pub trait TyEncoder<'tcx>: Encoder {
 ///
 /// `Decodable` can still be implemented in cases where `Decodable` is required
 /// by a trait bound.
-pub trait RefDecodable<'tcx, D: TyDecoder<'tcx>> {
+pub trait RefDecodable<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> {
     fn decode(d: &mut D) -> &'tcx Self;
 }
 
@@ -82,9 +75,9 @@ pub fn encode_with_shorthand<'tcx, E, T, M>(
     cache: M,
 ) -> Result<(), E::Error>
 where
-    E: TyEncoder<'tcx>,
+    E: TyEncoder<I = TyCtxt<'tcx>>,
     M: for<'b> Fn(&'b mut E) -> &'b mut FxHashMap<T, usize>,
-    T: EncodableWithShorthand<'tcx, E>,
+    T: EncodableWithShorthand<E>,
     // The discriminant and shorthand must have the same size.
     T::Variant: DiscriminantKind<Discriminant = isize>,
 {
@@ -119,100 +112,86 @@ where
     Ok(())
 }
 
-impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for Ty<'tcx> {
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for Ty<'tcx> {
     fn encode(&self, e: &mut E) -> Result<(), E::Error> {
         encode_with_shorthand(e, self, TyEncoder::type_shorthands)
     }
 }
 
-impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Binder<'tcx, ty::PredicateKind<'tcx>> {
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E>
+    for ty::Binder<'tcx, ty::PredicateKind<'tcx>>
+{
     fn encode(&self, e: &mut E) -> Result<(), E::Error> {
         self.bound_vars().encode(e)?;
         encode_with_shorthand(e, &self.skip_binder(), TyEncoder::predicate_shorthands)
     }
 }
 
-impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Predicate<'tcx> {
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Predicate<'tcx> {
     fn encode(&self, e: &mut E) -> Result<(), E::Error> {
         self.kind().encode(e)
     }
 }
 
-impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Region<'tcx> {
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Region<'tcx> {
     fn encode(&self, e: &mut E) -> Result<(), E::Error> {
         self.kind().encode(e)
     }
 }
 
-impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Const<'tcx> {
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Const<'tcx> {
     fn encode(&self, e: &mut E) -> Result<(), E::Error> {
         self.0.0.encode(e)
     }
 }
 
-impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ConstAllocation<'tcx> {
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ConstAllocation<'tcx> {
     fn encode(&self, e: &mut E) -> Result<(), E::Error> {
         self.inner().encode(e)
     }
 }
 
-impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for AdtDef<'tcx> {
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for AdtDef<'tcx> {
     fn encode(&self, e: &mut E) -> Result<(), E::Error> {
         self.0.0.encode(e)
     }
 }
 
-impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for AllocId {
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for AllocId {
     fn encode(&self, e: &mut E) -> Result<(), E::Error> {
         e.encode_alloc_id(self)
     }
 }
 
-pub trait TyDecoder<'tcx>: Decoder {
-    const CLEAR_CROSS_CRATE: bool;
-
-    fn tcx(&self) -> TyCtxt<'tcx>;
-
-    fn peek_byte(&self) -> u8;
-
-    fn position(&self) -> usize;
-
-    fn cached_ty_for_shorthand<F>(&mut self, shorthand: usize, or_insert_with: F) -> Ty<'tcx>
-    where
-        F: FnOnce(&mut Self) -> Ty<'tcx>;
-
-    fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
-    where
-        F: FnOnce(&mut Self) -> R;
-
-    fn positioned_at_shorthand(&self) -> bool {
-        (self.peek_byte() & (SHORTHAND_OFFSET as u8)) != 0
-    }
-
-    fn decode_alloc_id(&mut self) -> AllocId;
-}
-
 #[inline]
-fn decode_arena_allocable<'tcx, D, T: ArenaAllocatable<'tcx> + Decodable<D>>(
+fn decode_arena_allocable<
+    'tcx,
+    D: TyDecoder<I = TyCtxt<'tcx>>,
+    T: ArenaAllocatable<'tcx> + Decodable<D>,
+>(
     decoder: &mut D,
 ) -> &'tcx T
 where
-    D: TyDecoder<'tcx>,
+    D: TyDecoder,
 {
-    decoder.tcx().arena.alloc(Decodable::decode(decoder))
+    decoder.interner().arena.alloc(Decodable::decode(decoder))
 }
 
 #[inline]
-fn decode_arena_allocable_slice<'tcx, D, T: ArenaAllocatable<'tcx> + Decodable<D>>(
+fn decode_arena_allocable_slice<
+    'tcx,
+    D: TyDecoder<I = TyCtxt<'tcx>>,
+    T: ArenaAllocatable<'tcx> + Decodable<D>,
+>(
     decoder: &mut D,
 ) -> &'tcx [T]
 where
-    D: TyDecoder<'tcx>,
+    D: TyDecoder,
 {
-    decoder.tcx().arena.alloc_from_iter(<Vec<T> as Decodable<D>>::decode(decoder))
+    decoder.interner().arena.alloc_from_iter(<Vec<T> as Decodable<D>>::decode(decoder))
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for Ty<'tcx> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for Ty<'tcx> {
     #[allow(rustc::usage_of_ty_tykind)]
     fn decode(decoder: &mut D) -> Ty<'tcx> {
         // Handle shorthands first, if we have a usize > 0x80.
@@ -225,13 +204,15 @@ impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for Ty<'tcx> {
                 decoder.with_position(shorthand, Ty::decode)
             })
         } else {
-            let tcx = decoder.tcx();
-            tcx.mk_ty(ty::TyKind::decode(decoder))
+            let tcx = decoder.interner();
+            tcx.mk_ty(rustc_type_ir::TyKind::decode(decoder))
         }
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Binder<'tcx, ty::PredicateKind<'tcx>> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D>
+    for ty::Binder<'tcx, ty::PredicateKind<'tcx>>
+{
     fn decode(decoder: &mut D) -> ty::Binder<'tcx, ty::PredicateKind<'tcx>> {
         let bound_vars = Decodable::decode(decoder);
         // Handle shorthands first, if we have a usize > 0x80.
@@ -250,64 +231,64 @@ impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Binder<'tcx, ty::PredicateKi
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Predicate<'tcx> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Predicate<'tcx> {
     fn decode(decoder: &mut D) -> ty::Predicate<'tcx> {
         let predicate_kind = Decodable::decode(decoder);
-        decoder.tcx().mk_predicate(predicate_kind)
+        decoder.interner().mk_predicate(predicate_kind)
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for SubstsRef<'tcx> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for SubstsRef<'tcx> {
     fn decode(decoder: &mut D) -> Self {
         let len = decoder.read_usize();
-        let tcx = decoder.tcx();
+        let tcx = decoder.interner();
         tcx.mk_substs(
             (0..len).map::<ty::subst::GenericArg<'tcx>, _>(|_| Decodable::decode(decoder)),
         )
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for mir::Place<'tcx> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for mir::Place<'tcx> {
     fn decode(decoder: &mut D) -> Self {
         let local: mir::Local = Decodable::decode(decoder);
         let len = decoder.read_usize();
-        let projection = decoder.tcx().mk_place_elems(
+        let projection = decoder.interner().mk_place_elems(
             (0..len).map::<mir::PlaceElem<'tcx>, _>(|_| Decodable::decode(decoder)),
         );
         mir::Place { local, projection }
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Region<'tcx> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Region<'tcx> {
     fn decode(decoder: &mut D) -> Self {
-        decoder.tcx().mk_region(Decodable::decode(decoder))
+        decoder.interner().mk_region(Decodable::decode(decoder))
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for CanonicalVarInfos<'tcx> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for CanonicalVarInfos<'tcx> {
     fn decode(decoder: &mut D) -> Self {
         let len = decoder.read_usize();
         let interned: Vec<CanonicalVarInfo<'tcx>> =
             (0..len).map(|_| Decodable::decode(decoder)).collect();
-        decoder.tcx().intern_canonical_var_infos(interned.as_slice())
+        decoder.interner().intern_canonical_var_infos(interned.as_slice())
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for AllocId {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for AllocId {
     fn decode(decoder: &mut D) -> Self {
         decoder.decode_alloc_id()
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::SymbolName<'tcx> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::SymbolName<'tcx> {
     fn decode(decoder: &mut D) -> Self {
-        ty::SymbolName::new(decoder.tcx(), &decoder.read_str())
+        ty::SymbolName::new(decoder.interner(), &decoder.read_str())
     }
 }
 
 macro_rules! impl_decodable_via_ref {
     ($($t:ty),+) => {
-        $(impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for $t {
+        $(impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for $t {
             fn decode(decoder: &mut D) -> Self {
                 RefDecodable::decode(decoder)
             }
@@ -315,78 +296,86 @@ macro_rules! impl_decodable_via_ref {
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List<Ty<'tcx>> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<Ty<'tcx>> {
     fn decode(decoder: &mut D) -> &'tcx Self {
         let len = decoder.read_usize();
-        decoder.tcx().mk_type_list((0..len).map::<Ty<'tcx>, _>(|_| Decodable::decode(decoder)))
+        decoder.interner().mk_type_list((0..len).map::<Ty<'tcx>, _>(|_| Decodable::decode(decoder)))
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D>
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
     for ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>
 {
     fn decode(decoder: &mut D) -> &'tcx Self {
         let len = decoder.read_usize();
-        decoder.tcx().mk_poly_existential_predicates(
+        decoder.interner().mk_poly_existential_predicates(
             (0..len).map::<ty::Binder<'tcx, _>, _>(|_| Decodable::decode(decoder)),
         )
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Const<'tcx> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Const<'tcx> {
     fn decode(decoder: &mut D) -> Self {
-        decoder.tcx().mk_const(Decodable::decode(decoder))
+        decoder.interner().mk_const(Decodable::decode(decoder))
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [ty::ValTree<'tcx>] {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for [ty::ValTree<'tcx>] {
     fn decode(decoder: &mut D) -> &'tcx Self {
-        decoder.tcx().arena.alloc_from_iter(
+        decoder.interner().arena.alloc_from_iter(
             (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(),
         )
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ConstAllocation<'tcx> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ConstAllocation<'tcx> {
     fn decode(decoder: &mut D) -> Self {
-        decoder.tcx().intern_const_alloc(Decodable::decode(decoder))
+        decoder.interner().intern_const_alloc(Decodable::decode(decoder))
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for AdtDef<'tcx> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for AdtDef<'tcx> {
     fn decode(decoder: &mut D) -> Self {
-        decoder.tcx().intern_adt_def(Decodable::decode(decoder))
+        decoder.interner().intern_adt_def(Decodable::decode(decoder))
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [(ty::Predicate<'tcx>, Span)] {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
+    for [(ty::Predicate<'tcx>, Span)]
+{
     fn decode(decoder: &mut D) -> &'tcx Self {
-        decoder.tcx().arena.alloc_from_iter(
+        decoder.interner().arena.alloc_from_iter(
             (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(),
         )
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [thir::abstract_const::Node<'tcx>] {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
+    for [thir::abstract_const::Node<'tcx>]
+{
     fn decode(decoder: &mut D) -> &'tcx Self {
-        decoder.tcx().arena.alloc_from_iter(
+        decoder.interner().arena.alloc_from_iter(
             (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(),
         )
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [thir::abstract_const::NodeId] {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
+    for [thir::abstract_const::NodeId]
+{
     fn decode(decoder: &mut D) -> &'tcx Self {
-        decoder.tcx().arena.alloc_from_iter(
+        decoder.interner().arena.alloc_from_iter(
             (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(),
         )
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List<ty::BoundVariableKind> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
+    for ty::List<ty::BoundVariableKind>
+{
     fn decode(decoder: &mut D) -> &'tcx Self {
         let len = decoder.read_usize();
-        decoder.tcx().mk_bound_variable_kinds(
+        decoder.interner().mk_bound_variable_kinds(
             (0..len).map::<ty::BoundVariableKind, _>(|_| Decodable::decode(decoder)),
         )
     }
@@ -420,14 +409,14 @@ macro_rules! impl_arena_allocatable_decoder {
     ([]$args:tt) => {};
     ([decode $(, $attrs:ident)*]
      [$name:ident: $ty:ty]) => {
-        impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for $ty {
+        impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for $ty {
             #[inline]
             fn decode(decoder: &mut D) -> &'tcx Self {
                 decode_arena_allocable(decoder)
             }
         }
 
-        impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [$ty] {
+        impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for [$ty] {
             #[inline]
             fn decode(decoder: &mut D) -> &'tcx Self {
                 decode_arena_allocable_slice(decoder)
@@ -449,17 +438,17 @@ arena_types!(impl_arena_allocatable_decoders);
 
 macro_rules! impl_arena_copy_decoder {
     (<$tcx:tt> $($ty:ty,)*) => {
-        $(impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for $ty {
+        $(impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for $ty {
             #[inline]
             fn decode(decoder: &mut D) -> &'tcx Self {
-                decoder.tcx().arena.alloc(Decodable::decode(decoder))
+                decoder.interner().arena.alloc(Decodable::decode(decoder))
             }
         }
 
-        impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [$ty] {
+        impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for [$ty] {
             #[inline]
             fn decode(decoder: &mut D) -> &'tcx Self {
-                decoder.tcx().arena.alloc_from_iter(<Vec<_> as Decodable<D>>::decode(decoder))
+                decoder.interner().arena.alloc_from_iter(<Vec<_> as Decodable<D>>::decode(decoder))
             }
         })*
     };
@@ -518,13 +507,13 @@ macro_rules! implement_ty_decoder {
 macro_rules! impl_binder_encode_decode {
     ($($t:ty),+ $(,)?) => {
         $(
-            impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Binder<'tcx, $t> {
+            impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Binder<'tcx, $t> {
                 fn encode(&self, e: &mut E) -> Result<(), E::Error> {
                     self.bound_vars().encode(e)?;
                     self.as_ref().skip_binder().encode(e)
                 }
             }
-            impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Binder<'tcx, $t> {
+            impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Binder<'tcx, $t> {
                 fn decode(decoder: &mut D) -> Self {
                     let bound_vars = Decodable::decode(decoder);
                     ty::Binder::bind_with_vars(Decodable::decode(decoder), bound_vars)
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 3c08db5dc68..a0d92e2a5dd 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -16,7 +16,6 @@ use crate::thir::Thir;
 use crate::traits;
 use crate::ty::query::{self, TyCtxtAt};
 use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSubsts};
-use crate::ty::TyKind::*;
 use crate::ty::{
     self, AdtDef, AdtDefData, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig,
     ClosureSizeProfileData, Const, ConstS, ConstVid, DefIdTree, ExistentialPredicate, FloatTy,
@@ -60,9 +59,9 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::{Layout, LayoutS, TargetDataLayout, VariantIdx};
 use rustc_target::spec::abi;
+use rustc_type_ir::sty::TyKind::*;
+use rustc_type_ir::{InternAs, InternIteratorElement, Interner, TypeFlags};
 
-use rustc_type_ir::TypeFlags;
-use smallvec::SmallVec;
 use std::any::Any;
 use std::borrow::Borrow;
 use std::cmp::Ordering;
@@ -91,6 +90,31 @@ pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync {
     fn serialize(&self, tcx: TyCtxt<'tcx>, encoder: &mut FileEncoder) -> FileEncodeResult;
 }
 
+#[allow(rustc::usage_of_ty_tykind)]
+impl<'tcx> Interner for TyCtxt<'tcx> {
+    type AdtDef = ty::AdtDef<'tcx>;
+    type SubstsRef = ty::SubstsRef<'tcx>;
+    type DefId = DefId;
+    type Ty = Ty<'tcx>;
+    type Const = ty::Const<'tcx>;
+    type Region = Region<'tcx>;
+    type TypeAndMut = TypeAndMut<'tcx>;
+    type Mutability = hir::Mutability;
+    type Movability = hir::Movability;
+    type PolyFnSig = PolyFnSig<'tcx>;
+    type ListBinderExistentialPredicate = &'tcx List<Binder<'tcx, ExistentialPredicate<'tcx>>>;
+    type BinderListTy = Binder<'tcx, &'tcx List<Ty<'tcx>>>;
+    type ListTy = &'tcx List<Ty<'tcx>>;
+    type ProjectionTy = ty::ProjectionTy<'tcx>;
+    type ParamTy = ParamTy;
+    type BoundTy = ty::BoundTy;
+    type PlaceholderType = ty::PlaceholderType;
+    type InferTy = InferTy;
+    type DelaySpanBugEmitted = DelaySpanBugEmitted;
+    type PredicateKind = ty::PredicateKind<'tcx>;
+    type AllocId = crate::mir::interpret::AllocId;
+}
+
 /// A type that is not publicly constructable. This prevents people from making [`TyKind::Error`]s
 /// except through the error-reporting functions on a [`tcx`][TyCtxt].
 #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
@@ -1677,7 +1701,7 @@ macro_rules! nop_lift {
         impl<'a, 'tcx> Lift<'tcx> for $ty {
             type Lifted = $lifted;
             fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-                if tcx.interners.$set.contains_pointer_to(&InternedInSet(self.0.0)) {
+                if tcx.interners.$set.contains_pointer_to(&InternedInSet(&*self.0.0)) {
                     // SAFETY: `self` is interned and therefore valid
                     // for the entire lifetime of the `TyCtxt`.
                     Some(unsafe { mem::transmute(self) })
@@ -2848,108 +2872,6 @@ impl<'tcx> TyCtxtAt<'tcx> {
     }
 }
 
-pub trait InternAs<T: ?Sized, R> {
-    type Output;
-    fn intern_with<F>(self, f: F) -> Self::Output
-    where
-        F: FnOnce(&T) -> R;
-}
-
-impl<I, T, R, E> InternAs<[T], R> for I
-where
-    E: InternIteratorElement<T, R>,
-    I: Iterator<Item = E>,
-{
-    type Output = E::Output;
-    fn intern_with<F>(self, f: F) -> Self::Output
-    where
-        F: FnOnce(&[T]) -> R,
-    {
-        E::intern_with(self, f)
-    }
-}
-
-pub trait InternIteratorElement<T, R>: Sized {
-    type Output;
-    fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output;
-}
-
-impl<T, R> InternIteratorElement<T, R> for T {
-    type Output = R;
-    fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(
-        mut iter: I,
-        f: F,
-    ) -> Self::Output {
-        // This code is hot enough that it's worth specializing for the most
-        // common length lists, to avoid the overhead of `SmallVec` creation.
-        // Lengths 0, 1, and 2 typically account for ~95% of cases. If
-        // `size_hint` is incorrect a panic will occur via an `unwrap` or an
-        // `assert`.
-        match iter.size_hint() {
-            (0, Some(0)) => {
-                assert!(iter.next().is_none());
-                f(&[])
-            }
-            (1, Some(1)) => {
-                let t0 = iter.next().unwrap();
-                assert!(iter.next().is_none());
-                f(&[t0])
-            }
-            (2, Some(2)) => {
-                let t0 = iter.next().unwrap();
-                let t1 = iter.next().unwrap();
-                assert!(iter.next().is_none());
-                f(&[t0, t1])
-            }
-            _ => f(&iter.collect::<SmallVec<[_; 8]>>()),
-        }
-    }
-}
-
-impl<'a, T, R> InternIteratorElement<T, R> for &'a T
-where
-    T: Clone + 'a,
-{
-    type Output = R;
-    fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output {
-        // This code isn't hot.
-        f(&iter.cloned().collect::<SmallVec<[_; 8]>>())
-    }
-}
-
-impl<T, R, E> InternIteratorElement<T, R> for Result<T, E> {
-    type Output = Result<R, E>;
-    fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(
-        mut iter: I,
-        f: F,
-    ) -> Self::Output {
-        // This code is hot enough that it's worth specializing for the most
-        // common length lists, to avoid the overhead of `SmallVec` creation.
-        // Lengths 0, 1, and 2 typically account for ~95% of cases. If
-        // `size_hint` is incorrect a panic will occur via an `unwrap` or an
-        // `assert`, unless a failure happens first, in which case the result
-        // will be an error anyway.
-        Ok(match iter.size_hint() {
-            (0, Some(0)) => {
-                assert!(iter.next().is_none());
-                f(&[])
-            }
-            (1, Some(1)) => {
-                let t0 = iter.next().unwrap()?;
-                assert!(iter.next().is_none());
-                f(&[t0])
-            }
-            (2, Some(2)) => {
-                let t0 = iter.next().unwrap()?;
-                let t1 = iter.next().unwrap()?;
-                assert!(iter.next().is_none());
-                f(&[t0, t1])
-            }
-            _ => f(&iter.collect::<Result<SmallVec<[_; 8]>, _>>()?),
-        })
-    }
-}
-
 // We are comparing types with different invariant lifetimes, so `ptr::eq`
 // won't work for us.
 fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool {
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index a6717746979..462fc27009d 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -1,7 +1,6 @@
 //! Diagnostics related methods for `Ty`.
 
 use crate::ty::subst::{GenericArg, GenericArgKind};
-use crate::ty::TyKind::*;
 use crate::ty::{
     ConstKind, DefIdTree, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef,
     InferTy, ProjectionTy, Term, Ty, TyCtxt, TypeAndMut,
@@ -13,6 +12,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::WherePredicate;
 use rustc_span::Span;
+use rustc_type_ir::sty::TyKind::*;
 
 impl<'tcx> IntoDiagnosticArg for Ty<'tcx> {
     fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index f7ced066062..208cd9ba16a 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -207,10 +207,10 @@ pub struct DeepRejectCtxt {
 }
 
 impl DeepRejectCtxt {
-    pub fn generic_args_may_unify(
+    pub fn generic_args_may_unify<'tcx>(
         self,
-        obligation_arg: ty::GenericArg<'_>,
-        impl_arg: ty::GenericArg<'_>,
+        obligation_arg: ty::GenericArg<'tcx>,
+        impl_arg: ty::GenericArg<'tcx>,
     ) -> bool {
         match (obligation_arg.unpack(), impl_arg.unpack()) {
             // We don't fast reject based on regions for now.
@@ -225,7 +225,7 @@ impl DeepRejectCtxt {
         }
     }
 
-    pub fn types_may_unify(self, obligation_ty: Ty<'_>, impl_ty: Ty<'_>) -> bool {
+    pub fn types_may_unify<'tcx>(self, obligation_ty: Ty<'tcx>, impl_ty: Ty<'tcx>) -> bool {
         match impl_ty.kind() {
             // Start by checking whether the type in the impl may unify with
             // pretty much everything. Just return `true` in that case.
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
index b8088766cca..3d22f5a04a2 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
@@ -2,11 +2,12 @@ pub use self::def_id_forest::DefIdForest;
 
 use crate::ty;
 use crate::ty::context::TyCtxt;
-use crate::ty::TyKind::*;
 use crate::ty::{AdtDef, FieldDef, Ty, VariantDef};
 use crate::ty::{AdtKind, Visibility};
 use crate::ty::{DefId, SubstsRef};
 
+use rustc_type_ir::sty::TyKind::*;
+
 mod def_id_forest;
 
 // The methods in this module calculate `DefIdForest`s of modules in which an
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index b61a3827602..14e5dc0dd77 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -51,6 +51,7 @@ use std::{fmt, str};
 
 pub use crate::ty::diagnostics::*;
 pub use rustc_type_ir::InferTy::*;
+pub use rustc_type_ir::TyKind::*;
 pub use rustc_type_ir::*;
 
 pub use self::binding::BindingMode;
@@ -76,15 +77,14 @@ pub use self::parameterized::ParameterizedOverTcx;
 pub use self::rvalue_scopes::RvalueScopes;
 pub use self::sty::BoundRegionKind::*;
 pub use self::sty::RegionKind::*;
-pub use self::sty::TyKind::*;
 pub use self::sty::{
-    Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar, BoundVariableKind,
-    CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid, EarlyBinder, EarlyBoundRegion,
-    ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig,
-    GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts, InlineConstSubstsParts, ParamConst,
-    ParamTy, PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig,
-    PolyTraitRef, ProjectionTy, Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut,
-    UpvarSubsts, VarianceDiagInfo,
+    Article, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar,
+    BoundVariableKind, CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid,
+    EarlyBinder, EarlyBoundRegion, ExistentialPredicate, ExistentialProjection,
+    ExistentialTraitRef, FnSig, FreeRegion, GenSig, GeneratorSubsts, GeneratorSubstsParts,
+    InlineConstSubsts, InlineConstSubstsParts, ParamConst, ParamTy, PolyExistentialProjection,
+    PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, ProjectionTy, Region, RegionKind,
+    RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo,
 };
 pub use self::trait_def::TraitDef;
 
@@ -463,16 +463,18 @@ static_assert_size!(WithStableHash<TyS<'_>>, 56);
 #[rustc_pass_by_value]
 pub struct Ty<'tcx>(Interned<'tcx, WithStableHash<TyS<'tcx>>>);
 
-// Statics only used for internal testing.
-pub static BOOL_TY: Ty<'static> = Ty(Interned::new_unchecked(&WithStableHash {
-    internee: BOOL_TYS,
-    stable_hash: Fingerprint::ZERO,
-}));
-const BOOL_TYS: TyS<'static> = TyS {
-    kind: ty::Bool,
-    flags: TypeFlags::empty(),
-    outer_exclusive_binder: DebruijnIndex::from_usize(0),
-};
+impl<'tcx> TyCtxt<'tcx> {
+    /// A "bool" type used in rustc_mir_transform unit tests when we
+    /// have not spun up a TyCtxt.
+    pub const BOOL_TY_FOR_UNIT_TESTING: Ty<'tcx> = Ty(Interned::new_unchecked(&WithStableHash {
+        internee: TyS {
+            kind: ty::Bool,
+            flags: TypeFlags::empty(),
+            outer_exclusive_binder: DebruijnIndex::from_usize(0),
+        },
+        stable_hash: Fingerprint::ZERO,
+    }));
+}
 
 impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TyS<'tcx> {
     #[inline]
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 2dabc696388..faeb729c884 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -2,16 +2,14 @@
 
 #![allow(rustc::usage_of_ty_tykind)]
 
-use self::TyKind::*;
-
 use crate::infer::canonical::Canonical;
 use crate::ty::fold::ValidateBoundVars;
 use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
-use crate::ty::InferTy::{self, *};
+use crate::ty::InferTy::*;
 use crate::ty::{
     self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeVisitor,
 };
-use crate::ty::{DelaySpanBugEmitted, List, ParamEnv};
+use crate::ty::{List, ParamEnv};
 use polonius_engine::Atom;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::intern::Interned;
@@ -29,6 +27,13 @@ use std::marker::PhantomData;
 use std::ops::{ControlFlow, Deref, Range};
 use ty::util::IntTypeExt;
 
+use rustc_type_ir::sty::TyKind::*;
+use rustc_type_ir::TyKind as IrTyKind;
+
+// Re-export the `TyKind` from `rustc_type_ir` here for convenience
+#[rustc_diagnostic_item = "TyKind"]
+pub type TyKind<'tcx> = IrTyKind<TyCtxt<'tcx>>;
+
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable, Lift)]
 pub struct TypeAndMut<'tcx> {
@@ -78,190 +83,13 @@ impl BoundRegionKind {
     }
 }
 
-/// Defines the kinds of types used by the type system.
-///
-/// Types written by the user start out as [hir::TyKind](rustc_hir::TyKind) and get
-/// converted to this representation using `AstConv::ast_ty_to_ty`.
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable, Debug)]
-#[derive(HashStable)]
-#[rustc_diagnostic_item = "TyKind"]
-pub enum TyKind<'tcx> {
-    /// The primitive boolean type. Written as `bool`.
-    Bool,
-
-    /// The primitive character type; holds a Unicode scalar value
-    /// (a non-surrogate code point). Written as `char`.
-    Char,
-
-    /// A primitive signed integer type. For example, `i32`.
-    Int(ty::IntTy),
-
-    /// A primitive unsigned integer type. For example, `u32`.
-    Uint(ty::UintTy),
-
-    /// A primitive floating-point type. For example, `f64`.
-    Float(ty::FloatTy),
-
-    /// Algebraic data types (ADT). For example: structures, enumerations and unions.
-    ///
-    /// For example, the type `List<i32>` would be represented using the `AdtDef`
-    /// for `struct List<T>` and the substs `[i32]`.
-    ///
-    /// Note that generic parameters in fields only get lazily substituted
-    /// by using something like `adt_def.all_fields().map(|field| field.ty(tcx, substs))`.
-    Adt(AdtDef<'tcx>, SubstsRef<'tcx>),
-
-    /// An unsized FFI type that is opaque to Rust. Written as `extern type T`.
-    Foreign(DefId),
-
-    /// The pointee of a string slice. Written as `str`.
-    Str,
-
-    /// An array with the given length. Written as `[T; N]`.
-    Array(Ty<'tcx>, ty::Const<'tcx>),
-
-    /// The pointee of an array slice. Written as `[T]`.
-    Slice(Ty<'tcx>),
-
-    /// A raw pointer. Written as `*mut T` or `*const T`
-    RawPtr(TypeAndMut<'tcx>),
-
-    /// A reference; a pointer with an associated lifetime. Written as
-    /// `&'a mut T` or `&'a T`.
-    Ref(Region<'tcx>, Ty<'tcx>, hir::Mutability),
-
-    /// The anonymous type of a function declaration/definition. Each
-    /// function has a unique type.
-    ///
-    /// For the function `fn foo() -> i32 { 3 }` this type would be
-    /// shown to the user as `fn() -> i32 {foo}`.
-    ///
-    /// For example the type of `bar` here:
-    /// ```rust
-    /// fn foo() -> i32 { 1 }
-    /// let bar = foo; // bar: fn() -> i32 {foo}
-    /// ```
-    FnDef(DefId, SubstsRef<'tcx>),
-
-    /// A pointer to a function. Written as `fn() -> i32`.
-    ///
-    /// Note that both functions and closures start out as either
-    /// [FnDef] or [Closure] which can be then be coerced to this variant.
-    ///
-    /// For example the type of `bar` here:
-    ///
-    /// ```rust
-    /// fn foo() -> i32 { 1 }
-    /// let bar: fn() -> i32 = foo;
-    /// ```
-    FnPtr(PolyFnSig<'tcx>),
-
-    /// A trait object. Written as `dyn for<'b> Trait<'b, Assoc = u32> + Send + 'a`.
-    Dynamic(&'tcx List<Binder<'tcx, ExistentialPredicate<'tcx>>>, ty::Region<'tcx>),
-
-    /// The anonymous type of a closure. Used to represent the type of `|a| a`.
-    ///
-    /// Closure substs contain both the - potentially substituted - generic parameters
-    /// of its parent and some synthetic parameters. See the documentation for
-    /// [ClosureSubsts] for more details.
-    Closure(DefId, SubstsRef<'tcx>),
-
-    /// The anonymous type of a generator. Used to represent the type of
-    /// `|a| yield a`.
-    ///
-    /// For more info about generator substs, visit the documentation for
-    /// [GeneratorSubsts].
-    Generator(DefId, SubstsRef<'tcx>, hir::Movability),
-
-    /// A type representing the types stored inside a generator.
-    /// This should only appear as part of the [GeneratorSubsts].
-    ///
-    /// Note that the captured variables for generators are stored separately
-    /// using a tuple in the same way as for closures.
-    ///
-    /// Unlike upvars, the witness can reference lifetimes from
-    /// inside of the generator itself. To deal with them in
-    /// the type of the generator, we convert them to higher ranked
-    /// lifetimes bound by the witness itself.
-    ///
-    /// Looking at the following example, the witness for this generator
-    /// may end up as something like `for<'a> [Vec<i32>, &'a Vec<i32>]`:
-    ///
-    /// ```ignore UNSOLVED (ask @compiler-errors, should this error? can we just swap the yields?)
-    /// #![feature(generators)]
-    /// |a| {
-    ///     let x = &vec![3];
-    ///     yield a;
-    ///     yield x[0];
-    /// }
-    /// # ;
-    /// ```
-    GeneratorWitness(Binder<'tcx, &'tcx List<Ty<'tcx>>>),
-
-    /// The never type `!`.
-    Never,
-
-    /// A tuple type. For example, `(i32, bool)`.
-    Tuple(&'tcx List<Ty<'tcx>>),
-
-    /// The projection of an associated type. For example,
-    /// `<T as Trait<..>>::N`.
-    Projection(ProjectionTy<'tcx>),
-
-    /// Opaque (`impl Trait`) type found in a return type.
-    ///
-    /// The `DefId` comes either from
-    /// * the `impl Trait` ast::Ty node,
-    /// * or the `type Foo = impl Trait` declaration
-    ///
-    /// For RPIT the substitutions are for the generics of the function,
-    /// while for TAIT it is used for the generic parameters of the alias.
-    ///
-    /// During codegen, `tcx.type_of(def_id)` can be used to get the underlying type.
-    Opaque(DefId, SubstsRef<'tcx>),
-
-    /// A type parameter; for example, `T` in `fn f<T>(x: T) {}`.
-    Param(ParamTy),
-
-    /// Bound type variable, used to represent the `'a` in `for<'a> fn(&'a ())`.
-    ///
-    /// For canonical queries, we replace inference variables with bound variables,
-    /// so e.g. when checking whether `&'_ (): Trait<_>` holds, we canonicalize that to
-    /// `for<'a, T> &'a (): Trait<T>` and then convert the introduced bound variables
-    /// back to inference variables in a new inference context when inside of the query.
-    ///
-    /// See the `rustc-dev-guide` for more details about
-    /// [higher-ranked trait bounds][1] and [canonical queries][2].
-    ///
-    /// [1]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
-    /// [2]: https://rustc-dev-guide.rust-lang.org/traits/canonical-queries.html
-    Bound(ty::DebruijnIndex, BoundTy),
-
-    /// A placeholder type, used during higher ranked subtyping to instantiate
-    /// bound variables.
-    Placeholder(ty::PlaceholderType),
-
-    /// A type variable used during type checking.
-    ///
-    /// Similar to placeholders, inference variables also live in a universe to
-    /// correctly deal with higher ranked types. Though unlike placeholders,
-    /// that universe is stored in the `InferCtxt` instead of directly
-    /// inside of the type.
-    Infer(InferTy),
-
-    /// A placeholder for a type which could not be computed; this is
-    /// propagated to avoid useless error messages.
-    Error(DelaySpanBugEmitted),
+pub trait Article {
+    fn article(&self) -> &'static str;
 }
 
-impl<'tcx> TyKind<'tcx> {
-    #[inline]
-    pub fn is_primitive(&self) -> bool {
-        matches!(self, Bool | Char | Int(_) | Uint(_) | Float(_))
-    }
-
+impl<'tcx> Article for TyKind<'tcx> {
     /// Get the article ("a" or "an") to use with this type.
-    pub fn article(&self) -> &'static str {
+    fn article(&self) -> &'static str {
         match self {
             Int(_) | Float(_) | Array(_, _) => "an",
             Adt(def, _) if def.is_enum() => "an",
@@ -930,7 +758,7 @@ impl<'tcx> List<ty::Binder<'tcx, ExistentialPredicate<'tcx>>> {
     }
 
     #[inline]
-    pub fn auto_traits<'a>(&'a self) -> impl Iterator<Item = DefId> + 'a {
+    pub fn auto_traits<'a>(&'a self) -> impl Iterator<Item = DefId> + Captures<'tcx> + 'a {
         self.iter().filter_map(|predicate| match predicate.skip_binder() {
             ExistentialPredicate::AutoTrait(did) => Some(did),
             _ => None,
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index 31a318cc68f..290485ab5fe 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -4,7 +4,7 @@ use crate::mir;
 use crate::ty::codec::{TyDecoder, TyEncoder};
 use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeVisitor};
 use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts};
-use crate::ty::{self, EarlyBinder, Lift, List, ParamConst, Ty, TyCtxt};
+use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
 
 use rustc_data_structures::intern::{Interned, WithStableHash};
 use rustc_hir::def_id::DefId;
@@ -79,17 +79,17 @@ impl<'tcx> GenericArgKind<'tcx> {
         let (tag, ptr) = match self {
             GenericArgKind::Lifetime(lt) => {
                 // Ensure we can use the tag bits.
-                assert_eq!(mem::align_of_val(lt.0.0) & TAG_MASK, 0);
+                assert_eq!(mem::align_of_val(&*lt.0.0) & TAG_MASK, 0);
                 (REGION_TAG, lt.0.0 as *const ty::RegionKind as usize)
             }
             GenericArgKind::Type(ty) => {
                 // Ensure we can use the tag bits.
-                assert_eq!(mem::align_of_val(ty.0.0) & TAG_MASK, 0);
+                assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0);
                 (TYPE_TAG, ty.0.0 as *const WithStableHash<ty::TyS<'tcx>> as usize)
             }
             GenericArgKind::Const(ct) => {
                 // Ensure we can use the tag bits.
-                assert_eq!(mem::align_of_val(ct.0.0) & TAG_MASK, 0);
+                assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0);
                 (CONST_TAG, ct.0.0 as *const ty::ConstS<'tcx> as usize)
             }
         };
@@ -216,13 +216,13 @@ impl<'tcx> TypeFoldable<'tcx> for GenericArg<'tcx> {
     }
 }
 
-impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for GenericArg<'tcx> {
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for GenericArg<'tcx> {
     fn encode(&self, e: &mut E) -> Result<(), E::Error> {
         self.unpack().encode(e)
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for GenericArg<'tcx> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for GenericArg<'tcx> {
     fn decode(d: &mut D) -> GenericArg<'tcx> {
         GenericArgKind::decode(d).pack()
     }
@@ -506,7 +506,7 @@ pub trait Subst<'tcx>: Sized {
     fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self::Inner;
 }
 
-impl<'tcx, T: TypeFoldable<'tcx>> Subst<'tcx> for EarlyBinder<T> {
+impl<'tcx, T: TypeFoldable<'tcx>> Subst<'tcx> for ty::EarlyBinder<T> {
     type Inner = T;
 
     fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self::Inner {
diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs
index f766cad2b3d..04a9fd1f713 100644
--- a/compiler/rustc_middle/src/ty/vtable.rs
+++ b/compiler/rustc_middle/src/ty/vtable.rs
@@ -36,8 +36,11 @@ impl<'tcx> fmt::Debug for VtblEntry<'tcx> {
     }
 }
 
-pub const COMMON_VTABLE_ENTRIES: &[VtblEntry<'_>] =
-    &[VtblEntry::MetadataDropInPlace, VtblEntry::MetadataSize, VtblEntry::MetadataAlign];
+// Needs to be associated with the `'tcx` lifetime
+impl<'tcx> TyCtxt<'tcx> {
+    pub const COMMON_VTABLE_ENTRIES: &'tcx [VtblEntry<'tcx>] =
+        &[VtblEntry::MetadataDropInPlace, VtblEntry::MetadataSize, VtblEntry::MetadataAlign];
+}
 
 pub const COMMON_VTABLE_ENTRIES_DROPINPLACE: usize = 0;
 pub const COMMON_VTABLE_ENTRIES_SIZE: usize = 1;
@@ -57,7 +60,7 @@ pub(super) fn vtable_allocation_provider<'tcx>(
 
         tcx.vtable_entries(trait_ref)
     } else {
-        COMMON_VTABLE_ENTRIES
+        TyCtxt::COMMON_VTABLE_ENTRIES
     };
 
     let layout = tcx
diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs
index 4615f9be33f..213bb6608e1 100644
--- a/compiler/rustc_mir_transform/src/coverage/tests.rs
+++ b/compiler/rustc_mir_transform/src/coverage/tests.rs
@@ -37,7 +37,7 @@ use rustc_data_structures::graph::WithSuccessors;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::mir::coverage::CoverageKind;
 use rustc_middle::mir::*;
-use rustc_middle::ty::{self, BOOL_TY};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::{self, BytePos, Pos, Span, DUMMY_SP};
 
 // All `TEMP_BLOCK` targets should be replaced before calling `to_body() -> mir::Body`.
@@ -47,6 +47,7 @@ struct MockBlocks<'tcx> {
     blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
     dummy_place: Place<'tcx>,
     next_local: usize,
+    bool_ty: Ty<'tcx>,
 }
 
 impl<'tcx> MockBlocks<'tcx> {
@@ -55,6 +56,7 @@ impl<'tcx> MockBlocks<'tcx> {
             blocks: IndexVec::new(),
             dummy_place: Place { local: RETURN_PLACE, projection: ty::List::empty() },
             next_local: 0,
+            bool_ty: TyCtxt::BOOL_TY_FOR_UNIT_TESTING,
         }
     }
 
@@ -155,7 +157,7 @@ impl<'tcx> MockBlocks<'tcx> {
     fn switchint(&mut self, some_from_block: Option<BasicBlock>) -> BasicBlock {
         let switchint_kind = TerminatorKind::SwitchInt {
             discr: Operand::Move(Place::from(self.new_temp())),
-            switch_ty: BOOL_TY, // just a dummy value
+            switch_ty: self.bool_ty, // just a dummy value
             targets: SwitchTargets::static_if(0, TEMP_BLOCK, TEMP_BLOCK),
         };
         self.add_block_from(some_from_block, switchint_kind)
diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml
index 5673bb83b15..856f09b6fcc 100644
--- a/compiler/rustc_query_impl/Cargo.toml
+++ b/compiler/rustc_query_impl/Cargo.toml
@@ -20,6 +20,7 @@ rustc_query_system = { path = "../rustc_query_system" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
+rustc_type_ir = { path = "../rustc_type_ir" }
 tracing = "0.1"
 
 [features]
diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs
index c4920408527..8e4b3269402 100644
--- a/compiler/rustc_query_impl/src/on_disk_cache.rs
+++ b/compiler/rustc_query_impl/src/on_disk_cache.rs
@@ -547,11 +547,12 @@ where
     value
 }
 
-impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> {
+impl<'a, 'tcx> TyDecoder for CacheDecoder<'a, 'tcx> {
+    type I = TyCtxt<'tcx>;
     const CLEAR_CROSS_CRATE: bool = false;
 
     #[inline]
-    fn tcx(&self) -> TyCtxt<'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
@@ -569,7 +570,7 @@ impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> {
     where
         F: FnOnce(&mut Self) -> Ty<'tcx>,
     {
-        let tcx = self.tcx();
+        let tcx = self.tcx;
 
         let cache_key = ty::CReaderCacheKey { cnum: None, pos: shorthand };
 
@@ -750,7 +751,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefId {
         // If we get to this point, then all of the query inputs were green,
         // which means that the definition with this hash is guaranteed to
         // still exist in the current compilation session.
-        d.tcx().def_path_hash_to_def_id(def_path_hash, &mut || {
+        d.tcx.def_path_hash_to_def_id(def_path_hash, &mut || {
             panic!("Failed to convert DefPathHash {:?}", def_path_hash)
         })
     }
@@ -927,10 +928,11 @@ where
     }
 }
 
-impl<'a, 'tcx, E> TyEncoder<'tcx> for CacheEncoder<'a, 'tcx, E>
+impl<'a, 'tcx, E> TyEncoder for CacheEncoder<'a, 'tcx, E>
 where
     E: 'a + OpaqueEncoder,
 {
+    type I = TyCtxt<'tcx>;
     const CLEAR_CROSS_CRATE: bool = false;
 
     fn position(&self) -> usize {
diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml
index b5a37cf324b..85fbb08eeeb 100644
--- a/compiler/rustc_query_system/Cargo.toml
+++ b/compiler/rustc_query_system/Cargo.toml
@@ -21,6 +21,7 @@ rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
+rustc_type_ir = { path = "../rustc_type_ir" }
 parking_lot = "0.11"
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 6989763f75a..e4c52f8d25a 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -205,6 +205,7 @@ symbols! {
         IntoIterator,
         IoRead,
         IoWrite,
+        IrTyKind,
         Is,
         ItemContext,
         Iterator,
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index dcfdff68640..03757b5447e 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -32,9 +32,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
-use rustc_middle::ty::{
-    self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry, COMMON_VTABLE_ENTRIES,
-};
+use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry};
 use rustc_span::{sym, Span};
 use smallvec::SmallVec;
 
@@ -695,7 +693,7 @@ fn vtable_entries<'tcx>(
     let vtable_segment_callback = |segment| -> ControlFlow<()> {
         match segment {
             VtblSegment::MetadataDSA => {
-                entries.extend(COMMON_VTABLE_ENTRIES);
+                entries.extend(TyCtxt::COMMON_VTABLE_ENTRIES);
             }
             VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
                 let existential_trait_ref = trait_ref
@@ -785,7 +783,7 @@ fn vtable_trait_first_method_offset<'tcx>(
         move |segment| {
             match segment {
                 VtblSegment::MetadataDSA => {
-                    vtable_base += COMMON_VTABLE_ENTRIES.len();
+                    vtable_base += TyCtxt::COMMON_VTABLE_ENTRIES.len();
                 }
                 VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
                     if tcx.erase_regions(trait_ref) == trait_to_be_found_erased {
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index d607f4e7642..34dc81b14d2 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -12,7 +12,7 @@ use rustc_index::bit_set::GrowableBitSet;
 use rustc_infer::infer::InferOk;
 use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
-use rustc_middle::ty::{self, EarlyBinder, GenericParamDefKind, Ty};
+use rustc_middle::ty::{self, EarlyBinder, GenericParamDefKind, Ty, TyCtxt};
 use rustc_middle::ty::{ToPolyTraitRef, ToPredicate};
 use rustc_span::def_id::DefId;
 
@@ -834,7 +834,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             move |segment| {
                 match segment {
                     VtblSegment::MetadataDSA => {
-                        vptr_offset += ty::COMMON_VTABLE_ENTRIES.len();
+                        vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len();
                     }
                     VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
                         vptr_offset += util::count_own_vtable_entries(tcx, trait_ref);
diff --git a/compiler/rustc_ty_utils/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml
index 78df95e680e..d03d675bfd2 100644
--- a/compiler/rustc_ty_utils/Cargo.toml
+++ b/compiler/rustc_ty_utils/Cargo.toml
@@ -14,3 +14,4 @@ rustc_span = { path = "../rustc_span" }
 rustc_session = { path = "../rustc_session" }
 rustc_target = { path = "../rustc_target" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
+rustc_type_ir = { path = "../rustc_type_ir" }
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 23700e653e3..8d04b8816ff 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -13,7 +13,7 @@ fn sized_constraint_for_ty<'tcx>(
     adtdef: ty::AdtDef<'tcx>,
     ty: Ty<'tcx>,
 ) -> Vec<Ty<'tcx>> {
-    use ty::TyKind::*;
+    use rustc_type_ir::sty::TyKind::*;
 
     let result = match ty.kind() {
         Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..)
diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml
index 439e6cdf706..b8066f2e5d8 100644
--- a/compiler/rustc_type_ir/Cargo.toml
+++ b/compiler/rustc_type_ir/Cargo.toml
@@ -12,3 +12,4 @@ rustc_index = { path = "../rustc_index" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_macros = { path = "../rustc_macros" }
+smallvec = { version = "1.0", features = ["union", "may_dangle"] }
diff --git a/compiler/rustc_type_ir/src/codec.rs b/compiler/rustc_type_ir/src/codec.rs
new file mode 100644
index 00000000000..09f781fae75
--- /dev/null
+++ b/compiler/rustc_type_ir/src/codec.rs
@@ -0,0 +1,67 @@
+use crate::Interner;
+
+use rustc_data_structures::stable_map::FxHashMap;
+use rustc_serialize::{Decoder, Encoder};
+
+/// The shorthand encoding uses an enum's variant index `usize`
+/// and is offset by this value so it never matches a real variant.
+/// This offset is also chosen so that the first byte is never < 0x80.
+pub const SHORTHAND_OFFSET: usize = 0x80;
+
+/// Trait for decoding to a reference.
+///
+/// This is a separate trait from `Decodable` so that we can implement it for
+/// upstream types, such as `FxHashSet`.
+///
+/// The `TyDecodable` derive macro will use this trait for fields that are
+/// references (and don't use a type alias to hide that).
+///
+/// `Decodable` can still be implemented in cases where `Decodable` is required
+/// by a trait bound.
+pub trait RefDecodable<'tcx, D: TyDecoder> {
+    fn decode(d: &mut D) -> &'tcx Self;
+}
+
+pub trait TyEncoder: Encoder {
+    type I: Interner;
+    const CLEAR_CROSS_CRATE: bool;
+
+    fn position(&self) -> usize;
+    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 encode_alloc_id(
+        &mut self,
+        alloc_id: &<Self::I as Interner>::AllocId,
+    ) -> Result<(), Self::Error>;
+}
+
+pub trait TyDecoder: Decoder {
+    type I: Interner;
+    const CLEAR_CROSS_CRATE: bool;
+
+    fn interner(&self) -> Self::I;
+
+    fn peek_byte(&self) -> u8;
+
+    fn position(&self) -> usize;
+
+    fn cached_ty_for_shorthand<F>(
+        &mut self,
+        shorthand: usize,
+        or_insert_with: F,
+    ) -> <Self::I as Interner>::Ty
+    where
+        F: FnOnce(&mut Self) -> <Self::I as Interner>::Ty;
+
+    fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
+    where
+        F: FnOnce(&mut Self) -> R;
+
+    fn positioned_at_shorthand(&self) -> bool {
+        (self.peek_byte() & (SHORTHAND_OFFSET as u8)) != 0
+    }
+
+    fn decode_alloc_id(&mut self) -> <Self::I as Interner>::AllocId;
+}
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index c63e9c31d53..6380001b57c 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -1,4 +1,5 @@
 #![feature(min_specialization)]
+#![feature(rustc_attrs)]
 
 #[macro_use]
 extern crate bitflags;
@@ -7,9 +8,144 @@ extern crate rustc_macros;
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::unify::{EqUnifyValue, UnifyKey};
+use smallvec::SmallVec;
 use std::fmt;
+use std::fmt::Debug;
+use std::hash::Hash;
 use std::mem::discriminant;
 
+pub mod codec;
+pub mod sty;
+
+pub use codec::*;
+pub use sty::*;
+
+pub trait Interner {
+    type AdtDef: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type SubstsRef: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type DefId: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type Ty: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type Const: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type Region: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type TypeAndMut: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type Mutability: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type Movability: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type PolyFnSig: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type ListBinderExistentialPredicate: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type BinderListTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type ListTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type ProjectionTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type ParamTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type BoundTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type PlaceholderType: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type InferTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type DelaySpanBugEmitted: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type PredicateKind: Clone + Debug + Hash + PartialEq + Eq;
+    type AllocId: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+}
+
+pub trait InternAs<T: ?Sized, R> {
+    type Output;
+    fn intern_with<F>(self, f: F) -> Self::Output
+    where
+        F: FnOnce(&T) -> R;
+}
+
+impl<I, T, R, E> InternAs<[T], R> for I
+where
+    E: InternIteratorElement<T, R>,
+    I: Iterator<Item = E>,
+{
+    type Output = E::Output;
+    fn intern_with<F>(self, f: F) -> Self::Output
+    where
+        F: FnOnce(&[T]) -> R,
+    {
+        E::intern_with(self, f)
+    }
+}
+
+pub trait InternIteratorElement<T, R>: Sized {
+    type Output;
+    fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output;
+}
+
+impl<T, R> InternIteratorElement<T, R> for T {
+    type Output = R;
+    fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(
+        mut iter: I,
+        f: F,
+    ) -> Self::Output {
+        // This code is hot enough that it's worth specializing for the most
+        // common length lists, to avoid the overhead of `SmallVec` creation.
+        // Lengths 0, 1, and 2 typically account for ~95% of cases. If
+        // `size_hint` is incorrect a panic will occur via an `unwrap` or an
+        // `assert`.
+        match iter.size_hint() {
+            (0, Some(0)) => {
+                assert!(iter.next().is_none());
+                f(&[])
+            }
+            (1, Some(1)) => {
+                let t0 = iter.next().unwrap();
+                assert!(iter.next().is_none());
+                f(&[t0])
+            }
+            (2, Some(2)) => {
+                let t0 = iter.next().unwrap();
+                let t1 = iter.next().unwrap();
+                assert!(iter.next().is_none());
+                f(&[t0, t1])
+            }
+            _ => f(&iter.collect::<SmallVec<[_; 8]>>()),
+        }
+    }
+}
+
+impl<'a, T, R> InternIteratorElement<T, R> for &'a T
+where
+    T: Clone + 'a,
+{
+    type Output = R;
+    fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output {
+        // This code isn't hot.
+        f(&iter.cloned().collect::<SmallVec<[_; 8]>>())
+    }
+}
+
+impl<T, R, E> InternIteratorElement<T, R> for Result<T, E> {
+    type Output = Result<R, E>;
+    fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(
+        mut iter: I,
+        f: F,
+    ) -> Self::Output {
+        // This code is hot enough that it's worth specializing for the most
+        // common length lists, to avoid the overhead of `SmallVec` creation.
+        // Lengths 0, 1, and 2 typically account for ~95% of cases. If
+        // `size_hint` is incorrect a panic will occur via an `unwrap` or an
+        // `assert`, unless a failure happens first, in which case the result
+        // will be an error anyway.
+        Ok(match iter.size_hint() {
+            (0, Some(0)) => {
+                assert!(iter.next().is_none());
+                f(&[])
+            }
+            (1, Some(1)) => {
+                let t0 = iter.next().unwrap()?;
+                assert!(iter.next().is_none());
+                f(&[t0])
+            }
+            (2, Some(2)) => {
+                let t0 = iter.next().unwrap()?;
+                let t1 = iter.next().unwrap()?;
+                assert!(iter.next().is_none());
+                f(&[t0, t1])
+            }
+            _ => f(&iter.collect::<Result<SmallVec<[_; 8]>, _>>()?),
+        })
+    }
+}
+
 bitflags! {
     /// Flags that we track on types. These flags are propagated upwards
     /// through the type during type construction, so that we can quickly check
diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs
new file mode 100644
index 00000000000..650c3519b56
--- /dev/null
+++ b/compiler/rustc_type_ir/src/sty.rs
@@ -0,0 +1,1040 @@
+#![allow(rustc::usage_of_ty_tykind)]
+
+use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
+use std::{fmt, hash};
+
+use crate::DebruijnIndex;
+use crate::FloatTy;
+use crate::IntTy;
+use crate::Interner;
+use crate::TyDecoder;
+use crate::TyEncoder;
+use crate::UintTy;
+
+use self::TyKind::*;
+
+use rustc_data_structures::stable_hasher::HashStable;
+use rustc_serialize::{Decodable, Encodable};
+
+/// Defines the kinds of types used by the type system.
+///
+/// Types written by the user start out as `hir::TyKind` and get
+/// converted to this representation using `AstConv::ast_ty_to_ty`.
+///
+/// The `HashStable` implementation for this type is defined in `rustc_query_system::ich`.
+#[rustc_diagnostic_item = "IrTyKind"]
+pub enum TyKind<I: Interner> {
+    /// The primitive boolean type. Written as `bool`.
+    Bool,
+
+    /// The primitive character type; holds a Unicode scalar value
+    /// (a non-surrogate code point). Written as `char`.
+    Char,
+
+    /// A primitive signed integer type. For example, `i32`.
+    Int(IntTy),
+
+    /// A primitive unsigned integer type. For example, `u32`.
+    Uint(UintTy),
+
+    /// A primitive floating-point type. For example, `f64`.
+    Float(FloatTy),
+
+    /// Algebraic data types (ADT). For example: structures, enumerations and unions.
+    ///
+    /// For example, the type `List<i32>` would be represented using the `AdtDef`
+    /// for `struct List<T>` and the substs `[i32]`.
+    ///
+    /// Note that generic parameters in fields only get lazily substituted
+    /// by using something like `adt_def.all_fields().map(|field| field.ty(tcx, substs))`.
+    Adt(I::AdtDef, I::SubstsRef),
+
+    /// An unsized FFI type that is opaque to Rust. Written as `extern type T`.
+    Foreign(I::DefId),
+
+    /// The pointee of a string slice. Written as `str`.
+    Str,
+
+    /// An array with the given length. Written as `[T; N]`.
+    Array(I::Ty, I::Const),
+
+    /// The pointee of an array slice. Written as `[T]`.
+    Slice(I::Ty),
+
+    /// A raw pointer. Written as `*mut T` or `*const T`
+    RawPtr(I::TypeAndMut),
+
+    /// A reference; a pointer with an associated lifetime. Written as
+    /// `&'a mut T` or `&'a T`.
+    Ref(I::Region, I::Ty, I::Mutability),
+
+    /// The anonymous type of a function declaration/definition. Each
+    /// function has a unique type.
+    ///
+    /// For the function `fn foo() -> i32 { 3 }` this type would be
+    /// shown to the user as `fn() -> i32 {foo}`.
+    ///
+    /// For example the type of `bar` here:
+    /// ```rust
+    /// fn foo() -> i32 { 1 }
+    /// let bar = foo; // bar: fn() -> i32 {foo}
+    /// ```
+    FnDef(I::DefId, I::SubstsRef),
+
+    /// A pointer to a function. Written as `fn() -> i32`.
+    ///
+    /// Note that both functions and closures start out as either
+    /// [FnDef] or [Closure] which can be then be coerced to this variant.
+    ///
+    /// For example the type of `bar` here:
+    ///
+    /// ```rust
+    /// fn foo() -> i32 { 1 }
+    /// let bar: fn() -> i32 = foo;
+    /// ```
+    FnPtr(I::PolyFnSig),
+
+    /// A trait object. Written as `dyn for<'b> Trait<'b, Assoc = u32> + Send + 'a`.
+    Dynamic(I::ListBinderExistentialPredicate, I::Region),
+
+    /// The anonymous type of a closure. Used to represent the type of `|a| a`.
+    ///
+    /// Closure substs contain both the - potentially substituted - generic parameters
+    /// of its parent and some synthetic parameters. See the documentation for
+    /// `ClosureSubsts` for more details.
+    Closure(I::DefId, I::SubstsRef),
+
+    /// The anonymous type of a generator. Used to represent the type of
+    /// `|a| yield a`.
+    ///
+    /// For more info about generator substs, visit the documentation for
+    /// `GeneratorSubsts`.
+    Generator(I::DefId, I::SubstsRef, I::Movability),
+
+    /// A type representing the types stored inside a generator.
+    /// This should only appear as part of the `GeneratorSubsts`.
+    ///
+    /// Note that the captured variables for generators are stored separately
+    /// using a tuple in the same way as for closures.
+    ///
+    /// Unlike upvars, the witness can reference lifetimes from
+    /// inside of the generator itself. To deal with them in
+    /// the type of the generator, we convert them to higher ranked
+    /// lifetimes bound by the witness itself.
+    ///
+    /// Looking at the following example, the witness for this generator
+    /// may end up as something like `for<'a> [Vec<i32>, &'a Vec<i32>]`:
+    ///
+    /// ```ignore UNSOLVED (ask @compiler-errors, should this error? can we just swap the yields?)
+    /// #![feature(generators)]
+    /// |a| {
+    ///     let x = &vec![3];
+    ///     yield a;
+    ///     yield x[0];
+    /// }
+    /// # ;
+    /// ```
+    GeneratorWitness(I::BinderListTy),
+
+    /// The never type `!`.
+    Never,
+
+    /// A tuple type. For example, `(i32, bool)`.
+    Tuple(I::ListTy),
+
+    /// The projection of an associated type. For example,
+    /// `<T as Trait<..>>::N`.
+    Projection(I::ProjectionTy),
+
+    /// Opaque (`impl Trait`) type found in a return type.
+    ///
+    /// The `DefId` comes either from
+    /// * the `impl Trait` ast::Ty node,
+    /// * or the `type Foo = impl Trait` declaration
+    ///
+    /// For RPIT the substitutions are for the generics of the function,
+    /// while for TAIT it is used for the generic parameters of the alias.
+    ///
+    /// During codegen, `tcx.type_of(def_id)` can be used to get the underlying type.
+    Opaque(I::DefId, I::SubstsRef),
+
+    /// A type parameter; for example, `T` in `fn f<T>(x: T) {}`.
+    Param(I::ParamTy),
+
+    /// Bound type variable, used to represent the `'a` in `for<'a> fn(&'a ())`.
+    ///
+    /// For canonical queries, we replace inference variables with bound variables,
+    /// so e.g. when checking whether `&'_ (): Trait<_>` holds, we canonicalize that to
+    /// `for<'a, T> &'a (): Trait<T>` and then convert the introduced bound variables
+    /// back to inference variables in a new inference context when inside of the query.
+    ///
+    /// See the `rustc-dev-guide` for more details about
+    /// [higher-ranked trait bounds][1] and [canonical queries][2].
+    ///
+    /// [1]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
+    /// [2]: https://rustc-dev-guide.rust-lang.org/traits/canonical-queries.html
+    Bound(DebruijnIndex, I::BoundTy),
+
+    /// A placeholder type, used during higher ranked subtyping to instantiate
+    /// bound variables.
+    Placeholder(I::PlaceholderType),
+
+    /// A type variable used during type checking.
+    ///
+    /// Similar to placeholders, inference variables also live in a universe to
+    /// correctly deal with higher ranked types. Though unlike placeholders,
+    /// that universe is stored in the `InferCtxt` instead of directly
+    /// inside of the type.
+    Infer(I::InferTy),
+
+    /// A placeholder for a type which could not be computed; this is
+    /// propagated to avoid useless error messages.
+    Error(I::DelaySpanBugEmitted),
+}
+
+impl<I: Interner> TyKind<I> {
+    #[inline]
+    pub fn is_primitive(&self) -> bool {
+        matches!(self, Bool | Char | Int(_) | Uint(_) | Float(_))
+    }
+}
+
+// This is manually implemented for `TyKind` because `std::mem::discriminant`
+// returns an opaque value that is `PartialEq` but not `PartialOrd`
+#[inline]
+const fn discriminant<I: Interner>(value: &TyKind<I>) -> usize {
+    match value {
+        Bool => 0,
+        Char => 1,
+        Int(_) => 2,
+        Uint(_) => 3,
+        Float(_) => 4,
+        Adt(_, _) => 5,
+        Foreign(_) => 6,
+        Str => 7,
+        Array(_, _) => 8,
+        Slice(_) => 9,
+        RawPtr(_) => 10,
+        Ref(_, _, _) => 11,
+        FnDef(_, _) => 12,
+        FnPtr(_) => 13,
+        Dynamic(_, _) => 14,
+        Closure(_, _) => 15,
+        Generator(_, _, _) => 16,
+        GeneratorWitness(_) => 17,
+        Never => 18,
+        Tuple(_) => 19,
+        Projection(_) => 20,
+        Opaque(_, _) => 21,
+        Param(_) => 22,
+        Bound(_, _) => 23,
+        Placeholder(_) => 24,
+        Infer(_) => 25,
+        Error(_) => 26,
+    }
+}
+
+// This is manually implemented because a derive would require `I: Clone`
+impl<I: Interner> Clone for TyKind<I> {
+    fn clone(&self) -> Self {
+        match self {
+            Bool => Bool,
+            Char => Char,
+            Int(i) => Int(i.clone()),
+            Uint(u) => Uint(u.clone()),
+            Float(f) => Float(f.clone()),
+            Adt(d, s) => Adt(d.clone(), s.clone()),
+            Foreign(d) => Foreign(d.clone()),
+            Str => Str,
+            Array(t, c) => Array(t.clone(), c.clone()),
+            Slice(t) => Slice(t.clone()),
+            RawPtr(t) => RawPtr(t.clone()),
+            Ref(r, t, m) => Ref(r.clone(), t.clone(), m.clone()),
+            FnDef(d, s) => FnDef(d.clone(), s.clone()),
+            FnPtr(s) => FnPtr(s.clone()),
+            Dynamic(p, r) => Dynamic(p.clone(), r.clone()),
+            Closure(d, s) => Closure(d.clone(), s.clone()),
+            Generator(d, s, m) => Generator(d.clone(), s.clone(), m.clone()),
+            GeneratorWitness(g) => GeneratorWitness(g.clone()),
+            Never => Never,
+            Tuple(t) => Tuple(t.clone()),
+            Projection(p) => Projection(p.clone()),
+            Opaque(d, s) => Opaque(d.clone(), s.clone()),
+            Param(p) => Param(p.clone()),
+            Bound(d, b) => Bound(d.clone(), b.clone()),
+            Placeholder(p) => Placeholder(p.clone()),
+            Infer(t) => Infer(t.clone()),
+            Error(e) => Error(e.clone()),
+        }
+    }
+}
+
+// This is manually implemented because a derive would require `I: PartialEq`
+impl<I: Interner> PartialEq for TyKind<I> {
+    #[inline]
+    fn eq(&self, other: &TyKind<I>) -> bool {
+        let __self_vi = discriminant(self);
+        let __arg_1_vi = discriminant(other);
+        if __self_vi == __arg_1_vi {
+            match (&*self, &*other) {
+                (&Int(ref __self_0), &Int(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                (&Uint(ref __self_0), &Uint(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                (&Float(ref __self_0), &Float(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                (&Adt(ref __self_0, ref __self_1), &Adt(ref __arg_1_0, ref __arg_1_1)) => {
+                    __self_0 == __arg_1_0 && __self_1 == __arg_1_1
+                }
+                (&Foreign(ref __self_0), &Foreign(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                (&Array(ref __self_0, ref __self_1), &Array(ref __arg_1_0, ref __arg_1_1)) => {
+                    __self_0 == __arg_1_0 && __self_1 == __arg_1_1
+                }
+                (&Slice(ref __self_0), &Slice(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                (&RawPtr(ref __self_0), &RawPtr(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                (
+                    &Ref(ref __self_0, ref __self_1, ref __self_2),
+                    &Ref(ref __arg_1_0, ref __arg_1_1, ref __arg_1_2),
+                ) => __self_0 == __arg_1_0 && __self_1 == __arg_1_1 && __self_2 == __arg_1_2,
+                (&FnDef(ref __self_0, ref __self_1), &FnDef(ref __arg_1_0, ref __arg_1_1)) => {
+                    __self_0 == __arg_1_0 && __self_1 == __arg_1_1
+                }
+                (&FnPtr(ref __self_0), &FnPtr(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                (&Dynamic(ref __self_0, ref __self_1), &Dynamic(ref __arg_1_0, ref __arg_1_1)) => {
+                    __self_0 == __arg_1_0 && __self_1 == __arg_1_1
+                }
+                (&Closure(ref __self_0, ref __self_1), &Closure(ref __arg_1_0, ref __arg_1_1)) => {
+                    __self_0 == __arg_1_0 && __self_1 == __arg_1_1
+                }
+                (
+                    &Generator(ref __self_0, ref __self_1, ref __self_2),
+                    &Generator(ref __arg_1_0, ref __arg_1_1, ref __arg_1_2),
+                ) => __self_0 == __arg_1_0 && __self_1 == __arg_1_1 && __self_2 == __arg_1_2,
+                (&GeneratorWitness(ref __self_0), &GeneratorWitness(ref __arg_1_0)) => {
+                    __self_0 == __arg_1_0
+                }
+                (&Tuple(ref __self_0), &Tuple(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                (&Projection(ref __self_0), &Projection(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                (&Opaque(ref __self_0, ref __self_1), &Opaque(ref __arg_1_0, ref __arg_1_1)) => {
+                    __self_0 == __arg_1_0 && __self_1 == __arg_1_1
+                }
+                (&Param(ref __self_0), &Param(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                (&Bound(ref __self_0, ref __self_1), &Bound(ref __arg_1_0, ref __arg_1_1)) => {
+                    __self_0 == __arg_1_0 && __self_1 == __arg_1_1
+                }
+                (&Placeholder(ref __self_0), &Placeholder(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                (&Infer(ref __self_0), &Infer(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                (&Error(ref __self_0), &Error(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                _ => true,
+            }
+        } else {
+            false
+        }
+    }
+}
+
+// This is manually implemented because a derive would require `I: Eq`
+impl<I: Interner> Eq for TyKind<I> {}
+
+// This is manually implemented because a derive would require `I: PartialOrd`
+impl<I: Interner> PartialOrd for TyKind<I> {
+    #[inline]
+    fn partial_cmp(&self, other: &TyKind<I>) -> Option<Ordering> {
+        Some(Ord::cmp(self, other))
+    }
+}
+
+// This is manually implemented because a derive would require `I: Ord`
+impl<I: Interner> Ord for TyKind<I> {
+    #[inline]
+    fn cmp(&self, other: &TyKind<I>) -> Ordering {
+        let __self_vi = discriminant(self);
+        let __arg_1_vi = discriminant(other);
+        if __self_vi == __arg_1_vi {
+            match (&*self, &*other) {
+                (&Int(ref __self_0), &Int(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
+                (&Uint(ref __self_0), &Uint(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
+                (&Float(ref __self_0), &Float(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
+                (&Adt(ref __self_0, ref __self_1), &Adt(ref __arg_1_0, ref __arg_1_1)) => {
+                    match Ord::cmp(__self_0, __arg_1_0) {
+                        Ordering::Equal => Ord::cmp(__self_1, __arg_1_1),
+                        cmp => cmp,
+                    }
+                }
+                (&Foreign(ref __self_0), &Foreign(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
+                (&Array(ref __self_0, ref __self_1), &Array(ref __arg_1_0, ref __arg_1_1)) => {
+                    match Ord::cmp(__self_0, __arg_1_0) {
+                        Ordering::Equal => Ord::cmp(__self_1, __arg_1_1),
+                        cmp => cmp,
+                    }
+                }
+                (&Slice(ref __self_0), &Slice(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
+                (&RawPtr(ref __self_0), &RawPtr(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
+                (
+                    &Ref(ref __self_0, ref __self_1, ref __self_2),
+                    &Ref(ref __arg_1_0, ref __arg_1_1, ref __arg_1_2),
+                ) => match Ord::cmp(__self_0, __arg_1_0) {
+                    Ordering::Equal => match Ord::cmp(__self_1, __arg_1_1) {
+                        Ordering::Equal => Ord::cmp(__self_2, __arg_1_2),
+                        cmp => cmp,
+                    },
+                    cmp => cmp,
+                },
+                (&FnDef(ref __self_0, ref __self_1), &FnDef(ref __arg_1_0, ref __arg_1_1)) => {
+                    match Ord::cmp(__self_0, __arg_1_0) {
+                        Ordering::Equal => Ord::cmp(__self_1, __arg_1_1),
+                        cmp => cmp,
+                    }
+                }
+                (&FnPtr(ref __self_0), &FnPtr(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
+                (&Dynamic(ref __self_0, ref __self_1), &Dynamic(ref __arg_1_0, ref __arg_1_1)) => {
+                    match Ord::cmp(__self_0, __arg_1_0) {
+                        Ordering::Equal => Ord::cmp(__self_1, __arg_1_1),
+                        cmp => cmp,
+                    }
+                }
+                (&Closure(ref __self_0, ref __self_1), &Closure(ref __arg_1_0, ref __arg_1_1)) => {
+                    match Ord::cmp(__self_0, __arg_1_0) {
+                        Ordering::Equal => Ord::cmp(__self_1, __arg_1_1),
+                        cmp => cmp,
+                    }
+                }
+                (
+                    &Generator(ref __self_0, ref __self_1, ref __self_2),
+                    &Generator(ref __arg_1_0, ref __arg_1_1, ref __arg_1_2),
+                ) => match Ord::cmp(__self_0, __arg_1_0) {
+                    Ordering::Equal => match Ord::cmp(__self_1, __arg_1_1) {
+                        Ordering::Equal => Ord::cmp(__self_2, __arg_1_2),
+                        cmp => cmp,
+                    },
+                    cmp => cmp,
+                },
+                (&GeneratorWitness(ref __self_0), &GeneratorWitness(ref __arg_1_0)) => {
+                    Ord::cmp(__self_0, __arg_1_0)
+                }
+                (&Tuple(ref __self_0), &Tuple(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
+                (&Projection(ref __self_0), &Projection(ref __arg_1_0)) => {
+                    Ord::cmp(__self_0, __arg_1_0)
+                }
+                (&Opaque(ref __self_0, ref __self_1), &Opaque(ref __arg_1_0, ref __arg_1_1)) => {
+                    match Ord::cmp(__self_0, __arg_1_0) {
+                        Ordering::Equal => Ord::cmp(__self_1, __arg_1_1),
+                        cmp => cmp,
+                    }
+                }
+                (&Param(ref __self_0), &Param(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
+                (&Bound(ref __self_0, ref __self_1), &Bound(ref __arg_1_0, ref __arg_1_1)) => {
+                    match Ord::cmp(__self_0, __arg_1_0) {
+                        Ordering::Equal => Ord::cmp(__self_1, __arg_1_1),
+                        cmp => cmp,
+                    }
+                }
+                (&Placeholder(ref __self_0), &Placeholder(ref __arg_1_0)) => {
+                    Ord::cmp(__self_0, __arg_1_0)
+                }
+                (&Infer(ref __self_0), &Infer(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
+                (&Error(ref __self_0), &Error(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
+                _ => Ordering::Equal,
+            }
+        } else {
+            Ord::cmp(&__self_vi, &__arg_1_vi)
+        }
+    }
+}
+
+// This is manually implemented because a derive would require `I: Hash`
+impl<I: Interner> hash::Hash for TyKind<I> {
+    fn hash<__H: hash::Hasher>(&self, state: &mut __H) -> () {
+        match (&*self,) {
+            (&Int(ref __self_0),) => {
+                hash::Hash::hash(&discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&Uint(ref __self_0),) => {
+                hash::Hash::hash(&discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&Float(ref __self_0),) => {
+                hash::Hash::hash(&discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&Adt(ref __self_0, ref __self_1),) => {
+                hash::Hash::hash(&discriminant(self), state);
+                hash::Hash::hash(__self_0, state);
+                hash::Hash::hash(__self_1, state)
+            }
+            (&Foreign(ref __self_0),) => {
+                hash::Hash::hash(&discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&Array(ref __self_0, ref __self_1),) => {
+                hash::Hash::hash(&discriminant(self), state);
+                hash::Hash::hash(__self_0, state);
+                hash::Hash::hash(__self_1, state)
+            }
+            (&Slice(ref __self_0),) => {
+                hash::Hash::hash(&discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&RawPtr(ref __self_0),) => {
+                hash::Hash::hash(&discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&Ref(ref __self_0, ref __self_1, ref __self_2),) => {
+                hash::Hash::hash(&discriminant(self), state);
+                hash::Hash::hash(__self_0, state);
+                hash::Hash::hash(__self_1, state);
+                hash::Hash::hash(__self_2, state)
+            }
+            (&FnDef(ref __self_0, ref __self_1),) => {
+                hash::Hash::hash(&discriminant(self), state);
+                hash::Hash::hash(__self_0, state);
+                hash::Hash::hash(__self_1, state)
+            }
+            (&FnPtr(ref __self_0),) => {
+                hash::Hash::hash(&discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&Dynamic(ref __self_0, ref __self_1),) => {
+                hash::Hash::hash(&discriminant(self), state);
+                hash::Hash::hash(__self_0, state);
+                hash::Hash::hash(__self_1, state)
+            }
+            (&Closure(ref __self_0, ref __self_1),) => {
+                hash::Hash::hash(&discriminant(self), state);
+                hash::Hash::hash(__self_0, state);
+                hash::Hash::hash(__self_1, state)
+            }
+            (&Generator(ref __self_0, ref __self_1, ref __self_2),) => {
+                hash::Hash::hash(&discriminant(self), state);
+                hash::Hash::hash(__self_0, state);
+                hash::Hash::hash(__self_1, state);
+                hash::Hash::hash(__self_2, state)
+            }
+            (&GeneratorWitness(ref __self_0),) => {
+                hash::Hash::hash(&discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&Tuple(ref __self_0),) => {
+                hash::Hash::hash(&discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&Projection(ref __self_0),) => {
+                hash::Hash::hash(&discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&Opaque(ref __self_0, ref __self_1),) => {
+                hash::Hash::hash(&discriminant(self), state);
+                hash::Hash::hash(__self_0, state);
+                hash::Hash::hash(__self_1, state)
+            }
+            (&Param(ref __self_0),) => {
+                hash::Hash::hash(&discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&Bound(ref __self_0, ref __self_1),) => {
+                hash::Hash::hash(&discriminant(self), state);
+                hash::Hash::hash(__self_0, state);
+                hash::Hash::hash(__self_1, state)
+            }
+            (&Placeholder(ref __self_0),) => {
+                hash::Hash::hash(&discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&Infer(ref __self_0),) => {
+                hash::Hash::hash(&discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&Error(ref __self_0),) => {
+                hash::Hash::hash(&discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            _ => hash::Hash::hash(&discriminant(self), state),
+        }
+    }
+}
+
+// This is manually implemented because a derive would require `I: Debug`
+impl<I: Interner> fmt::Debug for TyKind<I> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match (&*self,) {
+            (&Bool,) => fmt::Formatter::write_str(f, "Bool"),
+            (&Char,) => fmt::Formatter::write_str(f, "Char"),
+            (&Int(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Int");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Uint(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Uint");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Float(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Float");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Adt(ref __self_0, ref __self_1),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Adt");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Foreign(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Foreign");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Str,) => fmt::Formatter::write_str(f, "Str"),
+            (&Array(ref __self_0, ref __self_1),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Array");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Slice(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Slice");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&RawPtr(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "RawPtr");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Ref(ref __self_0, ref __self_1, ref __self_2),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Ref");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_2);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&FnDef(ref __self_0, ref __self_1),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "FnDef");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&FnPtr(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "FnPtr");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Dynamic(ref __self_0, ref __self_1),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Dynamic");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Closure(ref __self_0, ref __self_1),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Closure");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Generator(ref __self_0, ref __self_1, ref __self_2),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Generator");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_2);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&GeneratorWitness(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "GeneratorWitness");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Never,) => fmt::Formatter::write_str(f, "Never"),
+            (&Tuple(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Tuple");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Projection(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Projection");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Opaque(ref __self_0, ref __self_1),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Opaque");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Param(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Param");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Bound(ref __self_0, ref __self_1),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Bound");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Placeholder(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Placeholder");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Infer(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Infer");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Error(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Error");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+        }
+    }
+}
+
+// This is manually implemented because a derive would require `I: Encodable`
+impl<I: Interner, E: TyEncoder> Encodable<E> for TyKind<I>
+where
+    I::DelaySpanBugEmitted: Encodable<E>,
+    I::AdtDef: Encodable<E>,
+    I::SubstsRef: Encodable<E>,
+    I::DefId: Encodable<E>,
+    I::Ty: Encodable<E>,
+    I::Const: Encodable<E>,
+    I::Region: Encodable<E>,
+    I::TypeAndMut: Encodable<E>,
+    I::Mutability: Encodable<E>,
+    I::Movability: Encodable<E>,
+    I::PolyFnSig: Encodable<E>,
+    I::ListBinderExistentialPredicate: Encodable<E>,
+    I::BinderListTy: Encodable<E>,
+    I::ListTy: Encodable<E>,
+    I::ProjectionTy: Encodable<E>,
+    I::ParamTy: Encodable<E>,
+    I::BoundTy: Encodable<E>,
+    I::PlaceholderType: Encodable<E>,
+    I::InferTy: Encodable<E>,
+    I::DelaySpanBugEmitted: Encodable<E>,
+    I::PredicateKind: Encodable<E>,
+    I::AllocId: Encodable<E>,
+{
+    fn encode(&self, e: &mut E) -> Result<(), <E as rustc_serialize::Encoder>::Error> {
+        rustc_serialize::Encoder::emit_enum(e, |e| {
+            let disc = discriminant(self);
+            match self {
+                Bool => e.emit_enum_variant("Bool", disc, 0, |_| Ok(())),
+                Char => e.emit_enum_variant("Char", disc, 0, |_| Ok(())),
+                Int(i) => e.emit_enum_variant("Int", disc, 1, |e| {
+                    e.emit_enum_variant_arg(true, |e| i.encode(e))?;
+                    Ok(())
+                }),
+                Uint(u) => e.emit_enum_variant("Uint", disc, 1, |e| {
+                    e.emit_enum_variant_arg(true, |e| u.encode(e))?;
+                    Ok(())
+                }),
+                Float(f) => e.emit_enum_variant("Float", disc, 1, |e| {
+                    e.emit_enum_variant_arg(true, |e| f.encode(e))?;
+                    Ok(())
+                }),
+                Adt(adt, substs) => e.emit_enum_variant("Adt", disc, 2, |e| {
+                    e.emit_enum_variant_arg(true, |e| adt.encode(e))?;
+                    e.emit_enum_variant_arg(false, |e| substs.encode(e))?;
+                    Ok(())
+                }),
+                Foreign(def_id) => e.emit_enum_variant("Foreign", disc, 1, |e| {
+                    e.emit_enum_variant_arg(true, |e| def_id.encode(e))?;
+                    Ok(())
+                }),
+                Str => e.emit_enum_variant("Str", disc, 0, |_| Ok(())),
+                Array(t, c) => e.emit_enum_variant("Array", disc, 2, |e| {
+                    e.emit_enum_variant_arg(true, |e| t.encode(e))?;
+                    e.emit_enum_variant_arg(false, |e| c.encode(e))?;
+                    Ok(())
+                }),
+                Slice(t) => e.emit_enum_variant("Slice", disc, 1, |e| {
+                    e.emit_enum_variant_arg(true, |e| t.encode(e))?;
+                    Ok(())
+                }),
+                RawPtr(tam) => e.emit_enum_variant("RawPtr", disc, 1, |e| {
+                    e.emit_enum_variant_arg(true, |e| tam.encode(e))?;
+                    Ok(())
+                }),
+                Ref(r, t, m) => e.emit_enum_variant("Ref", disc, 3, |e| {
+                    e.emit_enum_variant_arg(true, |e| r.encode(e))?;
+                    e.emit_enum_variant_arg(false, |e| t.encode(e))?;
+                    e.emit_enum_variant_arg(false, |e| m.encode(e))?;
+                    Ok(())
+                }),
+                FnDef(def_id, substs) => e.emit_enum_variant("FnDef", disc, 2, |e| {
+                    e.emit_enum_variant_arg(true, |e| def_id.encode(e))?;
+                    e.emit_enum_variant_arg(false, |e| substs.encode(e))?;
+                    Ok(())
+                }),
+                FnPtr(polyfnsig) => e.emit_enum_variant("FnPtr", disc, 1, |e| {
+                    e.emit_enum_variant_arg(true, |e| polyfnsig.encode(e))?;
+                    Ok(())
+                }),
+                Dynamic(l, r) => e.emit_enum_variant("Dynamic", disc, 2, |e| {
+                    e.emit_enum_variant_arg(true, |e| l.encode(e))?;
+                    e.emit_enum_variant_arg(false, |e| r.encode(e))?;
+                    Ok(())
+                }),
+                Closure(def_id, substs) => e.emit_enum_variant("Closure", disc, 2, |e| {
+                    e.emit_enum_variant_arg(true, |e| def_id.encode(e))?;
+                    e.emit_enum_variant_arg(false, |e| substs.encode(e))?;
+                    Ok(())
+                }),
+                Generator(def_id, substs, m) => e.emit_enum_variant("Generator", disc, 3, |e| {
+                    e.emit_enum_variant_arg(true, |e| def_id.encode(e))?;
+                    e.emit_enum_variant_arg(false, |e| substs.encode(e))?;
+                    e.emit_enum_variant_arg(false, |e| m.encode(e))?;
+                    Ok(())
+                }),
+                GeneratorWitness(b) => e.emit_enum_variant("GeneratorWitness", disc, 1, |e| {
+                    e.emit_enum_variant_arg(true, |e| b.encode(e))?;
+                    Ok(())
+                }),
+                Never => e.emit_enum_variant("Never", disc, 0, |_| Ok(())),
+                Tuple(substs) => e.emit_enum_variant("Tuple", disc, 1, |e| {
+                    e.emit_enum_variant_arg(true, |e| substs.encode(e))?;
+                    Ok(())
+                }),
+                Projection(p) => e.emit_enum_variant("Projection", disc, 1, |e| {
+                    e.emit_enum_variant_arg(true, |e| p.encode(e))?;
+                    Ok(())
+                }),
+                Opaque(def_id, substs) => e.emit_enum_variant("Opaque", disc, 2, |e| {
+                    e.emit_enum_variant_arg(true, |e| def_id.encode(e))?;
+                    e.emit_enum_variant_arg(false, |e| substs.encode(e))?;
+                    Ok(())
+                }),
+                Param(p) => e.emit_enum_variant("Param", disc, 1, |e| {
+                    e.emit_enum_variant_arg(true, |e| p.encode(e))?;
+                    Ok(())
+                }),
+                Bound(d, b) => e.emit_enum_variant("Bound", disc, 2, |e| {
+                    e.emit_enum_variant_arg(true, |e| d.encode(e))?;
+                    e.emit_enum_variant_arg(false, |e| b.encode(e))?;
+                    Ok(())
+                }),
+                Placeholder(p) => e.emit_enum_variant("Placeholder", disc, 1, |e| {
+                    e.emit_enum_variant_arg(true, |e| p.encode(e))?;
+                    Ok(())
+                }),
+                Infer(i) => e.emit_enum_variant("Infer", disc, 1, |e| {
+                    e.emit_enum_variant_arg(true, |e| i.encode(e))?;
+                    Ok(())
+                }),
+                Error(d) => e.emit_enum_variant("Error", disc, 1, |e| {
+                    e.emit_enum_variant_arg(true, |e| d.encode(e))?;
+                    Ok(())
+                }),
+            }
+        })
+    }
+}
+
+// This is manually implemented because a derive would require `I: Decodable`
+impl<I: Interner, D: TyDecoder<I = I>> Decodable<D> for TyKind<I>
+where
+    I::DelaySpanBugEmitted: Decodable<D>,
+    I::AdtDef: Decodable<D>,
+    I::SubstsRef: Decodable<D>,
+    I::DefId: Decodable<D>,
+    I::Ty: Decodable<D>,
+    I::Const: Decodable<D>,
+    I::Region: Decodable<D>,
+    I::TypeAndMut: Decodable<D>,
+    I::Mutability: Decodable<D>,
+    I::Movability: Decodable<D>,
+    I::PolyFnSig: Decodable<D>,
+    I::ListBinderExistentialPredicate: Decodable<D>,
+    I::BinderListTy: Decodable<D>,
+    I::ListTy: Decodable<D>,
+    I::ProjectionTy: Decodable<D>,
+    I::ParamTy: Decodable<D>,
+    I::BoundTy: Decodable<D>,
+    I::PlaceholderType: Decodable<D>,
+    I::InferTy: Decodable<D>,
+    I::DelaySpanBugEmitted: Decodable<D>,
+    I::PredicateKind: Decodable<D>,
+    I::AllocId: Decodable<D>,
+{
+    fn decode(d: &mut D) -> Self {
+        match rustc_serialize::Decoder::read_usize(d) {
+            0 => Bool,
+            1 => Char,
+            2 => Int(rustc_serialize::Decodable::decode(d)),
+            3 => Uint(rustc_serialize::Decodable::decode(d)),
+            4 => Float(rustc_serialize::Decodable::decode(d)),
+            5 => Adt(rustc_serialize::Decodable::decode(d), rustc_serialize::Decodable::decode(d)),
+            6 => Foreign(rustc_serialize::Decodable::decode(d)),
+            7 => Str,
+            8 => {
+                Array(rustc_serialize::Decodable::decode(d), rustc_serialize::Decodable::decode(d))
+            }
+            9 => Slice(rustc_serialize::Decodable::decode(d)),
+            10 => RawPtr(rustc_serialize::Decodable::decode(d)),
+            11 => Ref(
+                rustc_serialize::Decodable::decode(d),
+                rustc_serialize::Decodable::decode(d),
+                rustc_serialize::Decodable::decode(d),
+            ),
+            12 => {
+                FnDef(rustc_serialize::Decodable::decode(d), rustc_serialize::Decodable::decode(d))
+            }
+            13 => FnPtr(rustc_serialize::Decodable::decode(d)),
+            14 => Dynamic(
+                rustc_serialize::Decodable::decode(d),
+                rustc_serialize::Decodable::decode(d),
+            ),
+            15 => Closure(
+                rustc_serialize::Decodable::decode(d),
+                rustc_serialize::Decodable::decode(d),
+            ),
+            16 => Generator(
+                rustc_serialize::Decodable::decode(d),
+                rustc_serialize::Decodable::decode(d),
+                rustc_serialize::Decodable::decode(d),
+            ),
+            17 => GeneratorWitness(rustc_serialize::Decodable::decode(d)),
+            18 => Never,
+            19 => Tuple(rustc_serialize::Decodable::decode(d)),
+            20 => Projection(rustc_serialize::Decodable::decode(d)),
+            21 => {
+                Opaque(rustc_serialize::Decodable::decode(d), rustc_serialize::Decodable::decode(d))
+            }
+            22 => Param(rustc_serialize::Decodable::decode(d)),
+            23 => {
+                Bound(rustc_serialize::Decodable::decode(d), rustc_serialize::Decodable::decode(d))
+            }
+            24 => Placeholder(rustc_serialize::Decodable::decode(d)),
+            25 => Infer(rustc_serialize::Decodable::decode(d)),
+            26 => Error(rustc_serialize::Decodable::decode(d)),
+            _ => panic!(
+                "{}",
+                format!(
+                    "invalid enum variant tag while decoding `{}`, expected 0..{}",
+                    "TyKind", 27,
+                )
+            ),
+        }
+    }
+}
+
+// This is not a derived impl because a derive would require `I: HashStable`
+#[allow(rustc::usage_of_ty_tykind)]
+impl<CTX, I: Interner> HashStable<CTX> for TyKind<I>
+where
+    I::AdtDef: HashStable<CTX>,
+    I::DefId: HashStable<CTX>,
+    I::SubstsRef: HashStable<CTX>,
+    I::Ty: HashStable<CTX>,
+    I::Const: HashStable<CTX>,
+    I::TypeAndMut: HashStable<CTX>,
+    I::PolyFnSig: HashStable<CTX>,
+    I::ListBinderExistentialPredicate: HashStable<CTX>,
+    I::Region: HashStable<CTX>,
+    I::Movability: HashStable<CTX>,
+    I::Mutability: HashStable<CTX>,
+    I::BinderListTy: HashStable<CTX>,
+    I::ListTy: HashStable<CTX>,
+    I::ProjectionTy: HashStable<CTX>,
+    I::BoundTy: HashStable<CTX>,
+    I::ParamTy: HashStable<CTX>,
+    I::PlaceholderType: HashStable<CTX>,
+    I::InferTy: HashStable<CTX>,
+    I::DelaySpanBugEmitted: HashStable<CTX>,
+{
+    #[inline]
+    fn hash_stable(
+        &self,
+        __hcx: &mut CTX,
+        __hasher: &mut rustc_data_structures::stable_hasher::StableHasher,
+    ) {
+        std::mem::discriminant(self).hash_stable(__hcx, __hasher);
+        match self {
+            Bool => {}
+            Char => {}
+            Int(i) => {
+                i.hash_stable(__hcx, __hasher);
+            }
+            Uint(u) => {
+                u.hash_stable(__hcx, __hasher);
+            }
+            Float(f) => {
+                f.hash_stable(__hcx, __hasher);
+            }
+            Adt(adt, substs) => {
+                adt.hash_stable(__hcx, __hasher);
+                substs.hash_stable(__hcx, __hasher);
+            }
+            Foreign(def_id) => {
+                def_id.hash_stable(__hcx, __hasher);
+            }
+            Str => {}
+            Array(t, c) => {
+                t.hash_stable(__hcx, __hasher);
+                c.hash_stable(__hcx, __hasher);
+            }
+            Slice(t) => {
+                t.hash_stable(__hcx, __hasher);
+            }
+            RawPtr(tam) => {
+                tam.hash_stable(__hcx, __hasher);
+            }
+            Ref(r, t, m) => {
+                r.hash_stable(__hcx, __hasher);
+                t.hash_stable(__hcx, __hasher);
+                m.hash_stable(__hcx, __hasher);
+            }
+            FnDef(def_id, substs) => {
+                def_id.hash_stable(__hcx, __hasher);
+                substs.hash_stable(__hcx, __hasher);
+            }
+            FnPtr(polyfnsig) => {
+                polyfnsig.hash_stable(__hcx, __hasher);
+            }
+            Dynamic(l, r) => {
+                l.hash_stable(__hcx, __hasher);
+                r.hash_stable(__hcx, __hasher);
+            }
+            Closure(def_id, substs) => {
+                def_id.hash_stable(__hcx, __hasher);
+                substs.hash_stable(__hcx, __hasher);
+            }
+            Generator(def_id, substs, m) => {
+                def_id.hash_stable(__hcx, __hasher);
+                substs.hash_stable(__hcx, __hasher);
+                m.hash_stable(__hcx, __hasher);
+            }
+            GeneratorWitness(b) => {
+                b.hash_stable(__hcx, __hasher);
+            }
+            Never => {}
+            Tuple(substs) => {
+                substs.hash_stable(__hcx, __hasher);
+            }
+            Projection(p) => {
+                p.hash_stable(__hcx, __hasher);
+            }
+            Opaque(def_id, substs) => {
+                def_id.hash_stable(__hcx, __hasher);
+                substs.hash_stable(__hcx, __hasher);
+            }
+            Param(p) => {
+                p.hash_stable(__hcx, __hasher);
+            }
+            Bound(d, b) => {
+                d.hash_stable(__hcx, __hasher);
+                b.hash_stable(__hcx, __hasher);
+            }
+            Placeholder(p) => {
+                p.hash_stable(__hcx, __hasher);
+            }
+            Infer(i) => {
+                i.hash_stable(__hcx, __hasher);
+            }
+            Error(d) => {
+                d.hash_stable(__hcx, __hasher);
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_typeck/Cargo.toml b/compiler/rustc_typeck/Cargo.toml
index 57930a28a35..c08023ee6a7 100644
--- a/compiler/rustc_typeck/Cargo.toml
+++ b/compiler/rustc_typeck/Cargo.toml
@@ -29,3 +29,4 @@ rustc_trait_selection = { path = "../rustc_trait_selection" }
 rustc_ty_utils = { path = "../rustc_ty_utils" }
 rustc_lint = { path = "../rustc_lint" }
 rustc_serialize = { path = "../rustc_serialize" }
+rustc_type_ir = { path = "../rustc_type_ir" }
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index d0d2841209a..419ccb5a73a 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -12,7 +12,7 @@ use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, AssocItem, Ty, TypeAndMut};
+use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{BytePos, Span};
 
diff --git a/compiler/rustc_typeck/src/check/intrinsicck.rs b/compiler/rustc_typeck/src/check/intrinsicck.rs
index 027868be8bb..9cb57759b86 100644
--- a/compiler/rustc_typeck/src/check/intrinsicck.rs
+++ b/compiler/rustc_typeck/src/check/intrinsicck.rs
@@ -4,7 +4,7 @@ use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_index::vec::Idx;
 use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
-use rustc_middle::ty::{self, FloatTy, InferTy, IntTy, Ty, TyCtxt, TypeFoldable, UintTy};
+use rustc_middle::ty::{self, Article, FloatTy, InferTy, IntTy, Ty, TyCtxt, TypeFoldable, UintTy};
 use rustc_session::lint;
 use rustc_span::{Span, Symbol, DUMMY_SP};
 use rustc_target::abi::{Pointer, VariantIdx};
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index 637f6459525..3ae04706e4b 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -10,7 +10,6 @@ use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
 };
 use rustc_middle::ty::fold::TypeFolder;
-use rustc_middle::ty::TyKind::{Adt, Array, Char, FnDef, Never, Ref, Str, Tuple, Uint};
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{sym, Ident};
@@ -18,6 +17,7 @@ use rustc_span::Span;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt as _;
 use rustc_trait_selection::traits::{FulfillmentError, TraitEngine, TraitEngineExt};
+use rustc_type_ir::sty::TyKind::*;
 
 use std::ops::ControlFlow;
 
diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs
index 3135e9996ab..d08d9938708 100644
--- a/compiler/rustc_typeck/src/coherence/builtin.rs
+++ b/compiler/rustc_typeck/src/coherence/builtin.rs
@@ -177,7 +177,7 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did:
     tcx.infer_ctxt().enter(|infcx| {
         let cause = ObligationCause::misc(span, impl_hir_id);
 
-        use ty::TyKind::*;
+        use rustc_type_ir::sty::TyKind::*;
         match (source.kind(), target.kind()) {
             (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
                 if infcx.at(&cause, param_env).eq(r_a, *r_b).is_ok() && mutbl_a == *mutbl_b => {}
diff --git a/src/test/run-make-fulldeps/obtain-borrowck/driver.rs b/src/test/run-make-fulldeps/obtain-borrowck/driver.rs
index c3b82aa853c..8f78bda033e 100644
--- a/src/test/run-make-fulldeps/obtain-borrowck/driver.rs
+++ b/src/test/run-make-fulldeps/obtain-borrowck/driver.rs
@@ -154,7 +154,7 @@ fn get_bodies<'tcx>(tcx: TyCtxt<'tcx>) -> Vec<(String, BodyWithBorrowckFacts<'tc
                 // SAFETY: For soundness we need to ensure that the bodies have
                 // the same lifetime (`'tcx`), which they had before they were
                 // stored in the thread local.
-                (def_path.to_string_no_crate_verbose(), body)
+                (def_path.to_string_no_crate_verbose(), unsafe { std::mem::transmute(body) })
             })
             .collect()
     })
diff --git a/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.rs b/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.rs
index 973294e985f..2cb1ed6fcb7 100644
--- a/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.rs
+++ b/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.rs
@@ -3,41 +3,43 @@
 #![feature(rustc_private)]
 
 extern crate rustc_middle;
+extern crate rustc_type_ir;
 
 use rustc_middle::ty::{self, Ty, TyKind};
+use rustc_type_ir::{Interner, TyKind as IrTyKind};
 
 #[deny(rustc::usage_of_ty_tykind)]
 fn main() {
     let kind = TyKind::Bool; //~ ERROR usage of `ty::TyKind::<kind>`
 
     match kind {
-        TyKind::Bool => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Char => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Int(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Uint(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Float(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Adt(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Foreign(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Str => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Array(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Slice(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::RawPtr(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Ref(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::FnDef(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::FnPtr(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Dynamic(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Closure(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Generator(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::Bool => (),                 //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::Char => (),                 //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::Int(..) => (),              //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::Uint(..) => (),             //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::Float(..) => (),            //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::Adt(..) => (),              //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::Foreign(..) => (),          //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::Str => (),                  //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::Array(..) => (),            //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::Slice(..) => (),            //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::RawPtr(..) => (),           //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::Ref(..) => (),              //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::FnDef(..) => (),            //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::FnPtr(..) => (),            //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::Dynamic(..) => (),          //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::Closure(..) => (),          //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::Generator(..) => (),        //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::GeneratorWitness(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Never => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Tuple(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Projection(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Opaque(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Param(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Bound(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Placeholder(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Infer(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Error(_) => (), //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::Never => (),                //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::Tuple(..) => (),            //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::Projection(..) => (),       //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::Opaque(..) => (),           //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::Param(..) => (),            //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::Bound(..) => (),            //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::Placeholder(..) => (),      //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::Infer(..) => (),            //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::Error(_) => (),             //~ ERROR usage of `ty::TyKind::<kind>`
     }
 
     if let ty::Int(int_ty) = kind {}
@@ -45,4 +47,10 @@ fn main() {
     if let TyKind::Int(int_ty) = kind {} //~ ERROR usage of `ty::TyKind::<kind>`
 
     fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {} //~ ERROR usage of `ty::TyKind`
+
+    fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
+        //~^ ERROR usage of `ty::TyKind`
+        //~| ERROR usage of `ty::TyKind`
+        IrTyKind::Bool //~ ERROR usage of `ty::TyKind::<kind>`
+    }
 }
diff --git a/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.stderr b/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.stderr
index d6e4c85c190..171f49087d6 100644
--- a/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.stderr
+++ b/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.stderr
@@ -1,190 +1,214 @@
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:11:16
+  --> $DIR/ty_tykind_usage.rs:13:16
    |
 LL |     let kind = TyKind::Bool;
-   |                ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |                ^^^^^^ help: try using `ty::<kind>` directly: `ty`
    |
 note: the lint level is defined here
-  --> $DIR/ty_tykind_usage.rs:9:8
+  --> $DIR/ty_tykind_usage.rs:11:8
    |
 LL | #[deny(rustc::usage_of_ty_tykind)]
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:14:9
+  --> $DIR/ty_tykind_usage.rs:16:9
    |
 LL |         TyKind::Bool => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:15:9
+  --> $DIR/ty_tykind_usage.rs:17:9
    |
 LL |         TyKind::Char => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:16:9
+  --> $DIR/ty_tykind_usage.rs:18:9
    |
 LL |         TyKind::Int(..) => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:17:9
+  --> $DIR/ty_tykind_usage.rs:19:9
    |
 LL |         TyKind::Uint(..) => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:18:9
+  --> $DIR/ty_tykind_usage.rs:20:9
    |
 LL |         TyKind::Float(..) => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:19:9
+  --> $DIR/ty_tykind_usage.rs:21:9
    |
 LL |         TyKind::Adt(..) => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:20:9
+  --> $DIR/ty_tykind_usage.rs:22:9
    |
 LL |         TyKind::Foreign(..) => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:21:9
+  --> $DIR/ty_tykind_usage.rs:23:9
    |
 LL |         TyKind::Str => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:22:9
+  --> $DIR/ty_tykind_usage.rs:24:9
    |
 LL |         TyKind::Array(..) => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:23:9
+  --> $DIR/ty_tykind_usage.rs:25:9
    |
 LL |         TyKind::Slice(..) => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:24:9
+  --> $DIR/ty_tykind_usage.rs:26:9
    |
 LL |         TyKind::RawPtr(..) => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:25:9
+  --> $DIR/ty_tykind_usage.rs:27:9
    |
 LL |         TyKind::Ref(..) => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:26:9
+  --> $DIR/ty_tykind_usage.rs:28:9
    |
 LL |         TyKind::FnDef(..) => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:27:9
+  --> $DIR/ty_tykind_usage.rs:29:9
    |
 LL |         TyKind::FnPtr(..) => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:28:9
+  --> $DIR/ty_tykind_usage.rs:30:9
    |
 LL |         TyKind::Dynamic(..) => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:29:9
+  --> $DIR/ty_tykind_usage.rs:31:9
    |
 LL |         TyKind::Closure(..) => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:30:9
+  --> $DIR/ty_tykind_usage.rs:32:9
    |
 LL |         TyKind::Generator(..) => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:31:9
+  --> $DIR/ty_tykind_usage.rs:33:9
    |
 LL |         TyKind::GeneratorWitness(..) => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:32:9
+  --> $DIR/ty_tykind_usage.rs:34:9
    |
 LL |         TyKind::Never => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:33:9
+  --> $DIR/ty_tykind_usage.rs:35:9
    |
 LL |         TyKind::Tuple(..) => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:34:9
+  --> $DIR/ty_tykind_usage.rs:36:9
    |
 LL |         TyKind::Projection(..) => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:35:9
+  --> $DIR/ty_tykind_usage.rs:37:9
    |
 LL |         TyKind::Opaque(..) => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:36:9
+  --> $DIR/ty_tykind_usage.rs:38:9
    |
 LL |         TyKind::Param(..) => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:37:9
+  --> $DIR/ty_tykind_usage.rs:39:9
    |
 LL |         TyKind::Bound(..) => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:38:9
+  --> $DIR/ty_tykind_usage.rs:40:9
    |
 LL |         TyKind::Placeholder(..) => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:39:9
+  --> $DIR/ty_tykind_usage.rs:41:9
    |
 LL |         TyKind::Infer(..) => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:40:9
+  --> $DIR/ty_tykind_usage.rs:42:9
    |
 LL |         TyKind::Error(_) => (),
-   |         ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:45:12
+  --> $DIR/ty_tykind_usage.rs:47:12
    |
 LL |     if let TyKind::Int(int_ty) = kind {}
-   |            ^^^^^^ help: try using ty::<kind> directly: `ty`
+   |            ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind`
-  --> $DIR/ty_tykind_usage.rs:47:24
+  --> $DIR/ty_tykind_usage.rs:49:24
    |
 LL |     fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {}
    |                        ^^^^^^^^^^
    |
    = help: try using `Ty` instead
 
-error: aborting due to 30 previous errors
+error: usage of `ty::TyKind`
+  --> $DIR/ty_tykind_usage.rs:51:37
+   |
+LL |     fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
+   |                                     ^^^^^^^^^^^
+   |
+   = help: try using `Ty` instead
+
+error: usage of `ty::TyKind`
+  --> $DIR/ty_tykind_usage.rs:51:53
+   |
+LL |     fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
+   |                                                     ^^^^^^^^^^^
+   |
+   = help: try using `Ty` instead
+
+error: usage of `ty::TyKind::<kind>`
+  --> $DIR/ty_tykind_usage.rs:54:9
+   |
+LL |         IrTyKind::Bool
+   |         --------^^^^^^
+   |         |
+   |         help: try using `ty::<kind>` directly: `ty`
+
+error: aborting due to 33 previous errors