about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/util.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs33
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/collect/lifetimes.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/constrained_generic_params.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/hir_wf_check.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/variance/mod.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/mem_categorization.rs1
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs18
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs12
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs12
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs36
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs5
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/suggest.rs31
-rw-r--r--compiler/rustc_infer/src/infer/freshen.rs12
-rw-r--r--compiler/rustc_infer/src/infer/fudge.rs6
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs14
-rw-r--r--compiler/rustc_infer/src/infer/nll_relate/mod.rs4
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs6
-rw-r--r--compiler/rustc_infer/src/infer/resolve.rs27
-rw-r--r--compiler/rustc_infer/src/traits/structural_impls.rs6
-rw-r--r--compiler/rustc_lint/src/types.rs2
-rw-r--r--compiler/rustc_macros/src/type_foldable.rs4
-rw-r--r--compiler/rustc_macros/src/type_visitable.rs4
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs2
-rw-r--r--compiler/rustc_middle/src/lib.rs3
-rw-r--r--compiler/rustc_middle/src/macros.rs148
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs14
-rw-r--r--compiler/rustc_middle/src/mir/type_foldable.rs8
-rw-r--r--compiler/rustc_middle/src/mir/type_visitable.rs2
-rw-r--r--compiler/rustc_middle/src/traits/solve.rs29
-rw-r--r--compiler/rustc_middle/src/ty/abstract_const.rs7
-rw-r--r--compiler/rustc_middle/src/ty/context.rs2
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs13
-rw-r--r--compiler/rustc_middle/src/ty/erase_regions.rs7
-rw-r--r--compiler/rustc_middle/src/ty/error.rs2
-rw-r--r--compiler/rustc_middle/src/ty/fold.rs223
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs6
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs7
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs12
-rw-r--r--compiler/rustc_middle/src/ty/normalize_erasing_regions.rs13
-rw-r--r--compiler/rustc_middle/src/ty/opaque_types.rs16
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs6
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs323
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs20
-rw-r--r--compiler/rustc_middle/src/ty/subst.rs34
-rw-r--r--compiler/rustc_middle/src/ty/util.rs10
-rw-r--r--compiler/rustc_middle/src/ty/visit.rs118
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs4
-rw-r--r--compiler/rustc_monomorphize/src/polymorphize.rs4
-rw-r--r--compiler/rustc_privacy/src/lib.rs4
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs26
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs16
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_match.rs6
-rw-r--r--compiler/rustc_traits/src/chalk/db.rs4
-rw-r--r--compiler/rustc_traits/src/chalk/lowering.rs21
-rw-r--r--compiler/rustc_traits/src/chalk/mod.rs2
-rw-r--r--compiler/rustc_type_ir/src/fold.rs239
-rw-r--r--compiler/rustc_type_ir/src/lib.rs14
-rw-r--r--compiler/rustc_type_ir/src/macros.rs176
-rw-r--r--compiler/rustc_type_ir/src/structural_impls.rs238
-rw-r--r--compiler/rustc_type_ir/src/visit.rs115
-rw-r--r--library/std/src/sys/windows/fs.rs7
-rw-r--r--src/bootstrap/format.rs40
m---------src/doc/book0
m---------src/doc/embedded-book0
m---------src/doc/nomicon0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
m---------src/doc/rustc-dev-guide0
-rw-r--r--src/doc/style-guide/src/cargo.md3
-rw-r--r--src/librustdoc/clean/auto_trait.rs4
-rw-r--r--src/librustdoc/clean/mod.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs4
-rw-r--r--tests/mir-opt/copy-prop/mutate_through_pointer.rs10
-rw-r--r--tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/sibling_ptr.rs9
-rw-r--r--tests/mir-opt/sroa.escaping.ScalarReplacementOfAggregates.diff48
-rw-r--r--tests/mir-opt/sroa.rs7
-rw-r--r--tests/ui/async-await/dont-suggest-missing-await.stderr9
-rw-r--r--tests/ui/async-await/generator-desc.stderr4
-rw-r--r--tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr2
-rw-r--r--tests/ui/async-await/issue-61076.rs2
-rw-r--r--tests/ui/async-await/issue-61076.stderr2
-rw-r--r--tests/ui/async-await/issue-98634.stderr12
-rw-r--r--tests/ui/async-await/issues/issue-102206.stderr4
-rw-r--r--tests/ui/async-await/suggest-missing-await-closure.stderr9
-rw-r--r--tests/ui/async-await/suggest-missing-await.stderr28
-rw-r--r--tests/ui/coherence/issue-85026.stderr8
-rw-r--r--tests/ui/const-generics/wrong-normalization.stderr4
-rw-r--r--tests/ui/error-codes/E0116.stderr2
-rw-r--r--tests/ui/error-codes/E0118.stderr4
-rw-r--r--tests/ui/error-codes/E0390.stderr8
-rw-r--r--tests/ui/impl-trait/issue-102605.stderr9
-rw-r--r--tests/ui/impl-trait/issue-99914.stderr4
-rw-r--r--tests/ui/impl-trait/normalize-tait-in-const.stderr2
-rw-r--r--tests/ui/impl-trait/where-allowed.stderr4
-rw-r--r--tests/ui/incoherent-inherent-impls/needs-has-incoherent-impls.stderr78
-rw-r--r--tests/ui/incoherent-inherent-impls/no-attr-empty-impl.stderr12
-rw-r--r--tests/ui/kinds-of-primitive-impl.stderr16
-rw-r--r--tests/ui/privacy/private-in-public-ill-formed.stderr8
-rw-r--r--tests/ui/suggestions/if-then-neeing-semi.rs11
-rw-r--r--tests/ui/suggestions/if-then-neeing-semi.stderr24
-rw-r--r--tests/ui/suggestions/issue-81839.stderr5
-rw-r--r--tests/ui/suggestions/match-prev-arm-needing-semi.rs11
-rw-r--r--tests/ui/suggestions/match-prev-arm-needing-semi.stderr24
-rw-r--r--tests/ui/suggestions/opaque-type-error.stderr8
-rw-r--r--tests/ui/traits/trait-or-new-type-instead.stderr7
-rw-r--r--tests/ui/type-alias-impl-trait/issue-98604.stderr4
-rw-r--r--tests/ui/typeck/issue-90027-async-fn-return-suggestion.stderr9
133 files changed, 1482 insertions, 1257 deletions
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 2ae13990a45..70124dba809 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -17,7 +17,7 @@ use rustc_middle::mir::{
 };
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::traits::ObligationCauseCode;
-use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitable};
+use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable};
 use rustc_span::Span;
 
 use crate::{
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index d3868730557..c7fe382bac4 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -86,7 +86,7 @@ mod prelude {
     pub(crate) use rustc_middle::ty::layout::{self, LayoutOf, TyAndLayout};
     pub(crate) use rustc_middle::ty::{
         self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut,
-        TypeFoldable, TypeVisitable, UintTy,
+        TypeFoldable, UintTy,
     };
     pub(crate) use rustc_target::abi::{Abi, Scalar, Size, VariantIdx};
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index bb265b8289e..de1734332d4 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -3,7 +3,7 @@ use crate::traits::*;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
-use rustc_middle::ty::{self, Instance, Ty, TypeFoldable, TypeVisitable};
+use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
 use rustc_target::abi::call::{FnAbi, PassMode};
 
 use std::iter;
diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs
index cabc65e2c07..581cb6421f7 100644
--- a/compiler/rustc_const_eval/src/interpret/util.rs
+++ b/compiler/rustc_const_eval/src/interpret/util.rs
@@ -1,5 +1,5 @@
 use rustc_middle::mir::interpret::InterpResult;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
+use rustc_middle::ty::{self, ir::TypeVisitor, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
 use std::ops::ControlFlow;
 
 /// Checks whether a type contains generic parameters which require substitution.
@@ -21,7 +21,7 @@ where
         tcx: TyCtxt<'tcx>,
     }
 
-    impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> {
+    impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UsedParamsNeedSubstVisitor<'tcx> {
         type BreakTy = FoundParam;
 
         fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 5e3601efbbe..15a66ccc0f4 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -261,7 +261,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
         selftys: Vec<(Span, Option<String>)>,
     }
 
-    impl<'tcx> ty::visit::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
+    impl<'tcx> ty::visit::ir::TypeVisitor<TyCtxt<'tcx>> for ProhibitOpaqueVisitor<'tcx> {
         type BreakTy = Ty<'tcx>;
 
         fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
@@ -1447,7 +1447,7 @@ fn opaque_type_cycle_error(
                     opaques: Vec<DefId>,
                     closures: Vec<DefId>,
                 }
-                impl<'tcx> ty::visit::TypeVisitor<'tcx> for OpaqueTypeCollector {
+                impl<'tcx> ty::visit::ir::TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector {
                     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                         match *t.kind() {
                             ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index c86af6a379b..a926deb2393 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -16,7 +16,7 @@ use rustc_infer::traits::util;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::util::ExplicitSelf;
 use rustc_middle::ty::{
-    self, DefIdTree, InternalSubsts, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
+    self, ir::TypeFolder, DefIdTree, InternalSubsts, Ty, TypeFoldable, TypeSuperFoldable,
 };
 use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
 use rustc_span::Span;
@@ -464,8 +464,8 @@ struct RemapLateBound<'a, 'tcx> {
     mapping: &'a FxHashMap<ty::BoundRegionKind, ty::BoundRegionKind>,
 }
 
-impl<'tcx> TypeFolder<'tcx> for RemapLateBound<'_, 'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateBound<'_, 'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
@@ -829,14 +829,14 @@ impl<'a, 'tcx> ImplTraitInTraitCollector<'a, 'tcx> {
     }
 }
 
-impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> {
-    fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.ocx.infcx.tcx
     }
 
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
         if let ty::Alias(ty::Projection, proj) = ty.kind()
-            && self.tcx().def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder
+            && self.interner().def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder
         {
             if let Some((ty, _)) = self.types.get(&proj.def_id) {
                 return *ty;
@@ -852,7 +852,7 @@ impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> {
             });
             self.types.insert(proj.def_id, (infer_ty, proj.substs));
             // Recurse into bounds
-            for (pred, pred_span) in self.tcx().bound_explicit_item_bounds(proj.def_id).subst_iter_copied(self.tcx(), proj.substs) {
+            for (pred, pred_span) in self.interner().bound_explicit_item_bounds(proj.def_id).subst_iter_copied(self.interner(), proj.substs) {
                 let pred = pred.fold_with(self);
                 let pred = self.ocx.normalize(
                     &ObligationCause::misc(self.span, self.body_id),
@@ -861,7 +861,7 @@ impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> {
                 );
 
                 self.ocx.register_obligation(traits::Obligation::new(
-                    self.tcx(),
+                    self.interner(),
                     ObligationCause::new(
                         self.span,
                         self.body_id,
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 5f95622883b..16e7dcd0060 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -16,8 +16,8 @@ use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
 use rustc_middle::ty::{
-    self, AdtKind, DefIdTree, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
-    TypeVisitable, TypeVisitor,
+    self, ir::TypeVisitor, AdtKind, DefIdTree, GenericParamDefKind, Ty, TyCtxt, TypeFoldable,
+    TypeSuperVisitable,
 };
 use rustc_middle::ty::{GenericArgKind, InternalSubsts};
 use rustc_session::parse::feature_err;
@@ -772,7 +772,7 @@ impl<'tcx> GATSubstCollector<'tcx> {
     }
 }
 
-impl<'tcx> TypeVisitor<'tcx> for GATSubstCollector<'tcx> {
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GATSubstCollector<'tcx> {
     type BreakTy = !;
 
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
@@ -1435,7 +1435,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
             struct CountParams {
                 params: FxHashSet<u32>,
             }
-            impl<'tcx> ty::visit::TypeVisitor<'tcx> for CountParams {
+            impl<'tcx> ty::visit::ir::TypeVisitor<TyCtxt<'tcx>> for CountParams {
                 type BreakTy = ();
 
                 fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index c1b0237b2d1..940a450101c 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -57,7 +57,7 @@ const ADD_ATTR: &str =
     "alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items";
 
 impl<'tcx> InherentCollect<'tcx> {
-    fn check_def_id(&mut self, item: &hir::Item<'_>, self_ty: Ty<'tcx>, def_id: DefId) {
+    fn check_def_id(&mut self, item: &hir::Item<'_>, self_ty: Ty<'tcx>, def_id: DefId, span: Span) {
         let impl_def_id = item.owner_id;
         if let Some(def_id) = def_id.as_local() {
             // Add the implementation to the mapping from implementation to base
@@ -76,12 +76,12 @@ impl<'tcx> InherentCollect<'tcx> {
             if !self.tcx.has_attr(def_id, sym::rustc_has_incoherent_inherent_impls) {
                 struct_span_err!(
                     self.tcx.sess,
-                    item.span,
+                    span,
                     E0390,
                     "cannot define inherent `impl` for a type outside of the crate where the type is defined",
                 )
                 .help(INTO_DEFINING_CRATE)
-                .span_help(item.span, ADD_ATTR_TO_TY)
+                .span_help(span, ADD_ATTR_TO_TY)
                 .emit();
                 return;
             }
@@ -93,12 +93,12 @@ impl<'tcx> InherentCollect<'tcx> {
                 {
                     struct_span_err!(
                         self.tcx.sess,
-                        item.span,
+                        span,
                         E0390,
                         "cannot define inherent `impl` for a type outside of the crate where the type is defined",
                     )
                     .help(INTO_DEFINING_CRATE)
-                    .span_help(impl_item.span, ADD_ATTR)
+                    .span_help(self.tcx.hir().span(impl_item.id.hir_id()), ADD_ATTR)
                     .emit();
                     return;
                 }
@@ -112,12 +112,12 @@ impl<'tcx> InherentCollect<'tcx> {
         } else {
             struct_span_err!(
                 self.tcx.sess,
-                item.span,
+                span,
                 E0116,
                 "cannot define inherent `impl` for a type outside of the crate \
                               where the type is defined"
             )
-            .span_label(item.span, "impl for type defined outside of crate.")
+            .span_label(span, "impl for type defined outside of crate.")
             .note("define and implement a trait or new type instead")
             .emit();
         }
@@ -182,29 +182,30 @@ impl<'tcx> InherentCollect<'tcx> {
         }
 
         let item = self.tcx.hir().item(id);
-        let hir::ItemKind::Impl(hir::Impl { of_trait: None, self_ty: ty, items, .. }) = item.kind else {
+        let impl_span = self.tcx.hir().span(id.hir_id());
+        let hir::ItemKind::Impl(hir::Impl { of_trait: None, items, .. }) = item.kind else {
             return;
         };
 
         let self_ty = self.tcx.type_of(item.owner_id);
         match *self_ty.kind() {
             ty::Adt(def, _) => {
-                self.check_def_id(item, self_ty, def.did());
+                self.check_def_id(item, self_ty, def.did(), impl_span);
             }
             ty::Foreign(did) => {
-                self.check_def_id(item, self_ty, did);
+                self.check_def_id(item, self_ty, did, impl_span);
             }
             ty::Dynamic(data, ..) if data.principal_def_id().is_some() => {
-                self.check_def_id(item, self_ty, data.principal_def_id().unwrap());
+                self.check_def_id(item, self_ty, data.principal_def_id().unwrap(), impl_span);
             }
             ty::Dynamic(..) => {
                 struct_span_err!(
                     self.tcx.sess,
-                    ty.span,
+                    impl_span,
                     E0785,
                     "cannot define inherent `impl` for a dyn auto trait"
                 )
-                .span_label(ty.span, "impl requires at least one non-auto trait")
+                .span_label(impl_span, "impl requires at least one non-auto trait")
                 .note("define and implement a new trait or type instead")
                 .emit();
             }
@@ -221,17 +222,17 @@ impl<'tcx> InherentCollect<'tcx> {
             | ty::Never
             | ty::FnPtr(_)
             | ty::Tuple(..) => {
-                self.check_primitive_impl(item.owner_id.def_id, self_ty, items, ty.span)
+                self.check_primitive_impl(item.owner_id.def_id, self_ty, items, impl_span)
             }
             ty::Alias(..) | ty::Param(_) => {
                 let mut err = struct_span_err!(
                     self.tcx.sess,
-                    ty.span,
+                    impl_span,
                     E0118,
                     "no nominal type found for inherent implementation"
                 );
 
-                err.span_label(ty.span, "impl requires a nominal type")
+                err.span_label(impl_span, "impl requires a nominal type")
                     .note("either implement a trait on it or create a newtype to wrap it instead");
 
                 err.emit();
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 7d381d8902a..d0db8cabfdd 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -8,7 +8,7 @@ use rustc_hir as hir;
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::util::IgnoreRegions;
 use rustc_middle::ty::{
-    self, AliasKind, ImplPolarity, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
+    self, ir::TypeVisitor, AliasKind, ImplPolarity, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
 };
 use rustc_session::lint;
 use rustc_span::def_id::{DefId, LocalDefId};
@@ -552,7 +552,7 @@ fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty:
         seen: FxHashSet<DefId>,
     }
 
-    impl<'tcx> TypeVisitor<'tcx> for DisableAutoTraitVisitor<'tcx> {
+    impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for DisableAutoTraitVisitor<'tcx> {
         type BreakTy = ();
         fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
             let tcx = self.tcx;
diff --git a/compiler/rustc_hir_analysis/src/collect/lifetimes.rs b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
index 3c67722b637..3f8d620fe69 100644
--- a/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
+++ b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
@@ -17,7 +17,7 @@ use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeNa
 use rustc_middle::bug;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_lifetime::*;
-use rustc_middle::ty::{self, DefIdTree, TyCtxt, TypeSuperVisitable, TypeVisitor};
+use rustc_middle::ty::{self, ir::TypeVisitor, DefIdTree, TyCtxt, TypeSuperVisitable};
 use rustc_span::def_id::DefId;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
@@ -1752,7 +1752,7 @@ fn is_late_bound_map(
 
     use std::ops::ControlFlow;
     use ty::Ty;
-    impl<'tcx> TypeVisitor<'tcx> for ConstrainedCollectorPostAstConv {
+    impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ConstrainedCollectorPostAstConv {
         fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<!> {
             match t.kind() {
                 ty::Param(param_ty) => {
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index c5522c94874..54fcccb0c11 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -9,7 +9,7 @@ use rustc_middle::ty::print::with_forced_trimmed_paths;
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{
-    self, DefIdTree, IsSuggestable, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable,
+    self, ir::TypeFolder, DefIdTree, IsSuggestable, Ty, TyCtxt, TypeSuperFoldable, TypeVisitable,
 };
 use rustc_span::symbol::Ident;
 use rustc_span::{Span, DUMMY_SP};
@@ -850,8 +850,8 @@ fn infer_placeholder_type<'a>(
         tcx: TyCtxt<'tcx>,
     }
 
-    impl<'tcx> TypeFolder<'tcx> for MakeNameable<'tcx> {
-        fn tcx(&self) -> TyCtxt<'tcx> {
+    impl<'tcx> TypeFolder<TyCtxt<'tcx>> for MakeNameable<'tcx> {
+        fn interner(&self) -> TyCtxt<'tcx> {
             self.tcx
         }
 
diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
index 56cc1d8fadc..072676c400d 100644
--- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
+++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
@@ -1,5 +1,5 @@
 use rustc_data_structures::fx::FxHashSet;
-use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
+use rustc_middle::ty::visit::{ir::TypeVisitor, TypeSuperVisitable, TypeVisitable};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::source_map::Span;
 use std::ops::ControlFlow;
@@ -56,7 +56,7 @@ struct ParameterCollector {
     include_nonconstraining: bool,
 }
 
-impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParameterCollector {
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         match *t.kind() {
             ty::Alias(ty::Projection, ..) if !self.include_nonconstraining => {
diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
index 9cf82b39ec9..8fc4610ae85 100644
--- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
@@ -5,7 +5,7 @@ use rustc_hir::{ForeignItem, ForeignItemKind};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::{ObligationCause, WellFormedLoc};
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, Region, TyCtxt, TypeFoldable, TypeFolder};
+use rustc_middle::ty::{self, ir::TypeFolder, Region, TyCtxt, TypeFoldable};
 use rustc_span::def_id::LocalDefId;
 use rustc_trait_selection::traits;
 
@@ -189,8 +189,8 @@ struct EraseAllBoundRegions<'tcx> {
 // us an inaccurate span for an error message, but cannot
 // lead to unsoundness (we call `delay_span_bug` at the start
 // of `diagnostic_hir_wf_check`).
-impl<'tcx> TypeFolder<'tcx> for EraseAllBoundRegions<'tcx> {
-    fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EraseAllBoundRegions<'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
     fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs
index 079070be279..fb63bf22474 100644
--- a/compiler/rustc_hir_analysis/src/variance/mod.rs
+++ b/compiler/rustc_hir_analysis/src/variance/mod.rs
@@ -7,8 +7,10 @@ use rustc_arena::DroplessArena;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::ty::query::Providers;
+#[cfg(not(bootstrap))]
+use rustc_middle::ty::TypeVisitable;
 use rustc_middle::ty::{self, CrateVariancesMap, SubstsRef, Ty, TyCtxt};
-use rustc_middle::ty::{DefIdTree, TypeSuperVisitable, TypeVisitable};
+use rustc_middle::ty::{DefIdTree, TypeSuperVisitable};
 use std::ops::ControlFlow;
 
 /// Defines the `TermsContext` basically houses an arena where we can
@@ -99,7 +101,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
         }
     }
 
-    impl<'tcx> ty::TypeVisitor<'tcx> for OpaqueTypeLifetimeCollector<'tcx> {
+    impl<'tcx> ty::ir::TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeLifetimeCollector<'tcx> {
         #[instrument(level = "trace", skip(self), ret)]
         fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
             if let ty::RegionKind::ReEarlyBound(ebr) = r.kind() {
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 211fe477a2d..b1268c5f792 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -12,7 +12,7 @@ use rustc_infer::infer::{InferOk, InferResult};
 use rustc_macros::{TypeFoldable, TypeVisitable};
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::visit::TypeVisitable;
-use rustc_middle::ty::{self, Ty, TypeSuperVisitable, TypeVisitor};
+use rustc_middle::ty::{self, ir::TypeVisitor, Ty, TyCtxt, TypeSuperVisitable};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::Span;
 use rustc_span::sym;
@@ -232,7 +232,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 struct MentionsTy<'tcx> {
                     expected_ty: Ty<'tcx>,
                 }
-                impl<'tcx> TypeVisitor<'tcx> for MentionsTy<'tcx> {
+                impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MentionsTy<'tcx> {
                     type BreakTy = ();
 
                     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
index b220a87bc65..f434fb92289 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
@@ -3,7 +3,9 @@ use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::DefId;
 use rustc_infer::traits::ObligationCauseCode;
-use rustc_middle::ty::{self, DefIdTree, Ty, TypeSuperVisitable, TypeVisitable, TypeVisitor};
+use rustc_middle::ty::{
+    self, ir::TypeVisitor, DefIdTree, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
+};
 use rustc_span::{self, Span};
 use rustc_trait_selection::traits;
 
@@ -247,7 +249,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         t: T,
     ) -> Option<ty::GenericArg<'tcx>> {
         struct FindAmbiguousParameter<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, DefId);
-        impl<'tcx> TypeVisitor<'tcx> for FindAmbiguousParameter<'_, 'tcx> {
+        impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for FindAmbiguousParameter<'_, 'tcx> {
             type BreakTy = ty::GenericArg<'tcx>;
             fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> {
                 if let Some(origin) = self.0.type_var_origin(ty)
diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
index 92240b66eb1..60e0ce3494d 100644
--- a/compiler/rustc_hir_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs
@@ -51,7 +51,6 @@
 use rustc_middle::hir::place::*;
 use rustc_middle::ty::adjustment;
 use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
 use rustc_data_structures::fx::FxIndexMap;
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 16b0d48002e..b5e6727bfba 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -20,7 +20,7 @@ use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
 use rustc_middle::ty::AssocItem;
 use rustc_middle::ty::GenericParamDefKind;
 use rustc_middle::ty::ToPredicate;
-use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFoldable, TypeVisitable};
+use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFoldable};
 use rustc_middle::ty::{InternalSubsts, SubstsRef};
 use rustc_session::lint;
 use rustc_span::def_id::DefId;
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index ba72aefe39c..c8256e7ec08 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -13,7 +13,7 @@ use rustc_middle::ty::adjustment::{
 };
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{
-    self, DefIdTree, IsSuggestable, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable,
+    self, ir::TypeFolder, DefIdTree, IsSuggestable, Ty, TyCtxt, TypeSuperFoldable, TypeVisitable,
 };
 use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::source_map::Spanned;
@@ -963,8 +963,8 @@ fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, rhs: Ty<'tcx>, op: hir::BinOp) -> bool
 
 struct TypeParamEraser<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, Span);
 
-impl<'tcx> TypeFolder<'tcx> for TypeParamEraser<'_, 'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for TypeParamEraser<'_, 'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.0.tcx
     }
 
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 0aa34f9dd70..b6c9a88c82d 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -13,8 +13,8 @@ use rustc_infer::infer::InferCtxt;
 use rustc_middle::hir::place::Place as HirPlace;
 use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
-use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
-use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable};
+use rustc_middle::ty::fold::{ir::TypeFolder, TypeFoldable, TypeSuperFoldable};
+use rustc_middle::ty::visit::TypeSuperVisitable;
 use rustc_middle::ty::TypeckResults;
 use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt};
 use rustc_span::symbol::sym;
@@ -561,7 +561,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
             struct RecursionChecker {
                 def_id: LocalDefId,
             }
-            impl<'tcx> ty::TypeVisitor<'tcx> for RecursionChecker {
+            impl<'tcx> ty::ir::TypeVisitor<TyCtxt<'tcx>> for RecursionChecker {
                 type BreakTy = ();
                 fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                     if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *t.kind() {
@@ -763,8 +763,8 @@ struct EraseEarlyRegions<'tcx> {
     tcx: TyCtxt<'tcx>,
 }
 
-impl<'tcx> TypeFolder<'tcx> for EraseEarlyRegions<'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EraseEarlyRegions<'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
@@ -779,8 +779,8 @@ impl<'tcx> TypeFolder<'tcx> for EraseEarlyRegions<'tcx> {
     }
 }
 
-impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
-    fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
+impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
@@ -797,7 +797,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
                 debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t);
                 let e = self.report_error(t);
                 self.replaced_with_error = Some(e);
-                self.tcx().ty_error_with_guaranteed(e)
+                self.interner().ty_error_with_guaranteed(e)
             }
         }
     }
@@ -814,7 +814,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
                 debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct);
                 let e = self.report_error(ct);
                 self.replaced_with_error = Some(e);
-                self.tcx().const_error_with_guaranteed(ct.ty(), e)
+                self.interner().const_error_with_guaranteed(ct.ty(), e)
             }
         }
     }
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index c11dcc8587b..6bfdeda3a24 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -10,7 +10,7 @@ use crate::infer::canonical::{
 };
 use crate::infer::InferCtxt;
 use rustc_middle::ty::flags::FlagComputation;
-use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::fold::{ir::TypeFolder, TypeFoldable, TypeSuperFoldable};
 use rustc_middle::ty::subst::GenericArg;
 use rustc_middle::ty::{self, BoundVar, InferConst, List, Ty, TyCtxt, TypeFlags};
 use std::sync::atomic::Ordering;
@@ -326,8 +326,8 @@ struct Canonicalizer<'cx, 'tcx> {
     binder_index: ty::DebruijnIndex,
 }
 
-impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
@@ -738,7 +738,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
         let var = self.canonical_var(info, r.into());
         let br = ty::BoundRegion { var, kind: ty::BrAnon(var.as_u32(), None) };
         let region = ty::ReLateBound(self.binder_index, br);
-        self.tcx().mk_region(region)
+        self.interner().mk_region(region)
     }
 
     /// Given a type variable `ty_var` of the given kind, first check
@@ -752,7 +752,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
             self.fold_ty(bound_to)
         } else {
             let var = self.canonical_var(info, ty_var.into());
-            self.tcx().mk_bound(self.binder_index, var.into())
+            self.interner().mk_bound(self.binder_index, var.into())
         }
     }
 
@@ -771,7 +771,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
             self.fold_const(bound_to)
         } else {
             let var = self.canonical_var(info, const_var.into());
-            self.tcx().mk_const(
+            self.interner().mk_const(
                 ty::ConstKind::Bound(self.binder_index, var),
                 self.fold_ty(const_var.ty()),
             )
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index 4da2a674144..c2bf075444f 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -38,8 +38,8 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{
-    self, AliasKind, FallibleTypeFolder, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable,
-    TypeSuperFoldable, TypeVisitable,
+    self, ir::FallibleTypeFolder, AliasKind, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable,
+    TypeSuperFoldable,
 };
 use rustc_middle::ty::{IntType, UintType};
 use rustc_span::{Span, DUMMY_SP};
@@ -844,10 +844,10 @@ struct ConstInferUnifier<'cx, 'tcx> {
     target_vid: ty::ConstVid<'tcx>,
 }
 
-impl<'tcx> FallibleTypeFolder<'tcx> for ConstInferUnifier<'_, 'tcx> {
+impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for ConstInferUnifier<'_, 'tcx> {
     type Error = TypeError<'tcx>;
 
-    fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
 
@@ -875,7 +875,7 @@ impl<'tcx> FallibleTypeFolder<'tcx> for ConstInferUnifier<'_, 'tcx> {
                             .borrow_mut()
                             .type_variables()
                             .new_var(self.for_universe, origin);
-                        Ok(self.tcx().mk_ty_var(new_var_id))
+                        Ok(self.interner().mk_ty_var(new_var_id))
                     }
                 }
             }
@@ -953,7 +953,7 @@ impl<'tcx> FallibleTypeFolder<'tcx> for ConstInferUnifier<'_, 'tcx> {
                                         },
                                     },
                                 );
-                            Ok(self.tcx().mk_const(new_var_id, c.ty()))
+                            Ok(self.interner().mk_const(new_var_id, c.ty()))
                         }
                     }
                 }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 88a0d6def5e..c56149c1149 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -1491,7 +1491,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             }
         }
 
-        impl<'tcx> ty::visit::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> {
+        impl<'tcx> ty::visit::ir::TypeVisitor<TyCtxt<'tcx>> for OpaqueTypesVisitor<'tcx> {
             fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 if let Some((kind, def_id)) = TyCategory::from_ty(self.tcx, t) {
                     let span = self.tcx.def_span(def_id);
@@ -1783,14 +1783,24 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                             }
                         }))
                     {
-                        diag.note_expected_found_extra(
-                            &expected_label,
-                            expected,
-                            &found_label,
-                            found,
-                            &sort_string(values.expected, exp_p),
-                            &sort_string(values.found, found_p),
-                        );
+                        if let Some(ExpectedFound { found: found_ty, .. }) = exp_found {
+                            // `Future` is a special opaque type that the compiler
+                            // will try to hide in some case such as `async fn`, so
+                            // to make an error more use friendly we will
+                            // avoid to suggest a mismatch type with a
+                            // type that the user usually are not usign
+                            // directly such as `impl Future<Output = u8>`.
+                            if !self.tcx.ty_is_opaque_future(found_ty) {
+                                diag.note_expected_found_extra(
+                                    &expected_label,
+                                    expected,
+                                    &found_label,
+                                    found,
+                                    &sort_string(values.expected, exp_p),
+                                    &sort_string(values.found, found_p),
+                                );
+                            }
+                        }
                     }
                 }
                 _ => {
@@ -2854,6 +2864,7 @@ impl IntoDiagnosticArg for ObligationCauseAsDiagArg<'_> {
 pub enum TyCategory {
     Closure,
     Opaque,
+    OpaqueFuture,
     Generator(hir::GeneratorKind),
     Foreign,
 }
@@ -2863,6 +2874,7 @@ impl TyCategory {
         match self {
             Self::Closure => "closure",
             Self::Opaque => "opaque type",
+            Self::OpaqueFuture => "future",
             Self::Generator(gk) => gk.descr(),
             Self::Foreign => "foreign type",
         }
@@ -2871,7 +2883,11 @@ impl TyCategory {
     pub fn from_ty(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<(Self, DefId)> {
         match *ty.kind() {
             ty::Closure(def_id, _) => Some((Self::Closure, def_id)),
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => Some((Self::Opaque, def_id)),
+            ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
+                let kind =
+                    if tcx.ty_is_opaque_future(ty) { Self::OpaqueFuture } else { Self::Opaque };
+                Some((kind, def_id))
+            }
             ty::Generator(def_id, ..) => {
                 Some((Self::Generator(tcx.generator_kind(def_id).unwrap()), def_id))
             }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index 6a463583dfb..641477e907d 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -17,7 +17,8 @@ use rustc_hir::{
     TyKind,
 };
 use rustc_middle::ty::{
-    self, AssocItemContainer, StaticLifetimeVisitor, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
+    self, ir::TypeVisitor, AssocItemContainer, StaticLifetimeVisitor, Ty, TyCtxt,
+    TypeSuperVisitable,
 };
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
@@ -539,7 +540,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
 /// Collect all the trait objects in a type that could have received an implicit `'static` lifetime.
 pub struct TraitObjectVisitor(pub FxIndexSet<DefId>);
 
-impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor {
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for TraitObjectVisitor {
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         match t.kind() {
             ty::Dynamic(preds, re, _) if re.is_static() => {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index 40c0c806e1f..d295881d5d7 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -75,7 +75,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             }
         }
 
-        impl<'tcx> ty::visit::TypeVisitor<'tcx> for HighlightBuilder<'tcx> {
+        impl<'tcx> ty::visit::ir::TypeVisitor<TyCtxt<'tcx>> for HighlightBuilder<'tcx> {
             fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
                 if !r.has_name() && self.counter <= 3 {
                     self.highlight.highlighting_region(r, self.counter);
diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
index 73859aca424..7d9a53d1c02 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
@@ -238,31 +238,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 }
             },
             (_, Some(ty)) if self.same_type_modulo_infer(exp_found.expected, ty) => {
-                diag.span_suggestion_verbose(
-                    exp_span.shrink_to_hi(),
-                    "consider `await`ing on the `Future`",
-                    ".await",
-                    Applicability::MaybeIncorrect,
-                );
+                self.suggest_await_on_future(diag, exp_span);
+                diag.span_note(exp_span, "calling an async function returns a future");
             }
             (Some(ty), _) if self.same_type_modulo_infer(ty, exp_found.found) => match cause.code()
             {
                 ObligationCauseCode::Pattern { span: Some(then_span), .. } => {
-                    diag.span_suggestion_verbose(
-                        then_span.shrink_to_hi(),
-                        "consider `await`ing on the `Future`",
-                        ".await",
-                        Applicability::MaybeIncorrect,
-                    );
+                    self.suggest_await_on_future(diag, then_span.shrink_to_hi());
                 }
                 ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => {
                     let then_span = self.find_block_span_from_hir_id(*then_id);
-                    diag.span_suggestion_verbose(
-                        then_span.shrink_to_hi(),
-                        "consider `await`ing on the `Future`",
-                        ".await",
-                        Applicability::MaybeIncorrect,
-                    );
+                    self.suggest_await_on_future(diag, then_span.shrink_to_hi());
                 }
                 ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
                     ref prior_arms,
@@ -283,6 +269,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         }
     }
 
+    pub fn suggest_await_on_future(&self, diag: &mut Diagnostic, sp: Span) {
+        diag.span_suggestion_verbose(
+            sp.shrink_to_hi(),
+            "consider `await`ing on the `Future`",
+            ".await",
+            Applicability::MaybeIncorrect,
+        );
+    }
+
     pub(super) fn suggest_accessing_field_where_appropriate(
         &self,
         cause: &ObligationCause<'tcx>,
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index 073a2b0753d..41bffdc684d 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -33,8 +33,8 @@
 use super::InferCtxt;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::infer::unify_key::ToType;
-use rustc_middle::ty::fold::TypeFolder;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitable};
+use rustc_middle::ty::fold::ir::TypeFolder;
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable};
 use std::collections::hash_map::Entry;
 
 pub struct TypeFreshener<'a, 'tcx> {
@@ -105,8 +105,8 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
 
@@ -124,13 +124,13 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
             | ty::ReError(_)
             | ty::ReErased => {
                 // replace all free regions with 'erased
-                self.tcx().lifetimes.re_erased
+                self.interner().lifetimes.re_erased
             }
             ty::ReStatic => {
                 if self.keep_static {
                     r
                 } else {
-                    self.tcx().lifetimes.re_erased
+                    self.interner().lifetimes.re_erased
                 }
             }
         }
diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs
index 6dd6c4e1f5e..cc2f19a5704 100644
--- a/compiler/rustc_infer/src/infer/fudge.rs
+++ b/compiler/rustc_infer/src/infer/fudge.rs
@@ -1,4 +1,4 @@
-use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::fold::{ir::TypeFolder, TypeFoldable, TypeSuperFoldable};
 use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid};
 
 use super::type_variable::TypeVariableOrigin;
@@ -175,8 +175,8 @@ pub struct InferenceFudger<'a, 'tcx> {
     const_vars: (Range<ConstVid<'tcx>>, Vec<ConstVariableOrigin>),
 }
 
-impl<'a, 'tcx> TypeFolder<'tcx> for InferenceFudger<'a, 'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
 
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index ae196a7133c..b5a10ea6590 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -26,7 +26,7 @@ use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::traits::select;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::fold::BoundVarReplacerDelegate;
-use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::fold::{ir::TypeFolder, TypeFoldable, TypeSuperFoldable};
 use rustc_middle::ty::relate::RelateResult;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef};
 use rustc_middle::ty::visit::TypeVisitable;
@@ -1852,8 +1852,8 @@ struct InferenceLiteralEraser<'tcx> {
     tcx: TyCtxt<'tcx>,
 }
 
-impl<'tcx> TypeFolder<'tcx> for InferenceLiteralEraser<'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceLiteralEraser<'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
@@ -1870,8 +1870,8 @@ struct ShallowResolver<'a, 'tcx> {
     infcx: &'a InferCtxt<'tcx>,
 }
 
-impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ShallowResolver<'a, 'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
 
@@ -2064,8 +2064,8 @@ fn replace_param_and_infer_substs_with_placeholder<'tcx>(
         idx: u32,
     }
 
-    impl<'tcx> TypeFolder<'tcx> for ReplaceParamAndInferWithPlaceholder<'tcx> {
-        fn tcx(&self) -> TyCtxt<'tcx> {
+    impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceParamAndInferWithPlaceholder<'tcx> {
+        fn interner(&self) -> TyCtxt<'tcx> {
             self.tcx
         }
 
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index 1dd5062acaf..644774c93c2 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -29,7 +29,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
-use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
+use rustc_middle::ty::visit::{ir::TypeVisitor, TypeSuperVisitable, TypeVisitable};
 use rustc_middle::ty::{self, InferConst, Ty, TyCtxt};
 use rustc_span::Span;
 use std::fmt::Debug;
@@ -792,7 +792,7 @@ struct ScopeInstantiator<'me, 'tcx> {
     bound_region_scope: &'me mut BoundRegionScope<'tcx>,
 }
 
-impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> {
+impl<'me, 'tcx> TypeVisitor<TyCtxt<'tcx>> for ScopeInstantiator<'me, 'tcx> {
     fn visit_binder<T: TypeVisitable<'tcx>>(
         &mut self,
         t: &ty::Binder<'tcx, T>,
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index b68b0baaa40..5635e8adf34 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -12,8 +12,8 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::GenericArgKind;
 use rustc_middle::ty::{
-    self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
-    TypeVisitable, TypeVisitor,
+    self, ir::TypeVisitor, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable,
+    TypeSuperVisitable, TypeVisitable,
 };
 use rustc_span::Span;
 
@@ -431,7 +431,7 @@ pub struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP: FnMut(ty::Region<'tcx>)> {
     pub op: OP,
 }
 
-impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP>
+impl<'tcx, OP> TypeVisitor<TyCtxt<'tcx>> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP>
 where
     OP: FnMut(ty::Region<'tcx>),
 {
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index a39a40cf9ab..008bf1e9c5d 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -1,9 +1,12 @@
 use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use super::{FixupError, FixupResult, InferCtxt, Span};
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
-use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable};
-use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitor};
-use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable, TypeVisitable};
+use rustc_middle::ty::fold::{
+    ir::{FallibleTypeFolder, TypeFolder},
+    TypeSuperFoldable,
+};
+use rustc_middle::ty::visit::{ir::TypeVisitor, TypeSuperVisitable};
+use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable};
 
 use std::ops::ControlFlow;
 
@@ -28,9 +31,9 @@ impl<'a, 'tcx> OpportunisticVarResolver<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
-        TypeFolder::tcx(&self.shallow_resolver)
+impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for OpportunisticVarResolver<'a, 'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
+        TypeFolder::interner(&self.shallow_resolver)
     }
 
     #[inline]
@@ -70,8 +73,8 @@ impl<'a, 'tcx> OpportunisticRegionResolver<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for OpportunisticRegionResolver<'a, 'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
 
@@ -92,7 +95,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> {
                     .borrow_mut()
                     .unwrap_region_constraints()
                     .opportunistic_resolve_var(rid);
-                TypeFolder::tcx(self).reuse_or_mk_region(r, ty::ReVar(resolved))
+                TypeFolder::interner(self).reuse_or_mk_region(r, ty::ReVar(resolved))
             }
             _ => r,
         }
@@ -124,7 +127,7 @@ impl<'a, 'tcx> UnresolvedTypeOrConstFinder<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeOrConstFinder<'a, 'tcx> {
+impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for UnresolvedTypeOrConstFinder<'a, 'tcx> {
     type BreakTy = (ty::Term<'tcx>, Option<Span>);
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         let t = self.infcx.shallow_resolve(t);
@@ -208,10 +211,10 @@ struct FullTypeResolver<'a, 'tcx> {
     infcx: &'a InferCtxt<'tcx>,
 }
 
-impl<'a, 'tcx> FallibleTypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
+impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> {
     type Error = FixupError<'tcx>;
 
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
 
diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs
index 1c6ab6a082b..95df6cd62b9 100644
--- a/compiler/rustc_infer/src/traits/structural_impls.rs
+++ b/compiler/rustc_infer/src/traits/structural_impls.rs
@@ -1,8 +1,8 @@
 use crate::traits;
 use crate::traits::project::Normalized;
-use rustc_middle::ty;
 use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable};
 use rustc_middle::ty::visit::{TypeVisitable, TypeVisitor};
+use rustc_middle::ty::{self, ir, TyCtxt};
 
 use std::fmt;
 use std::ops::ControlFlow;
@@ -61,7 +61,7 @@ impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> {
 ///////////////////////////////////////////////////////////////////////////
 // TypeFoldable implementations.
 
-impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx, O> {
+impl<'tcx, O: TypeFoldable<'tcx>> ir::TypeFoldable<TyCtxt<'tcx>> for traits::Obligation<'tcx, O> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         Ok(traits::Obligation {
             cause: self.cause,
@@ -72,7 +72,7 @@ impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx
     }
 }
 
-impl<'tcx, O: TypeVisitable<'tcx>> TypeVisitable<'tcx> for traits::Obligation<'tcx, O> {
+impl<'tcx, O: TypeVisitable<'tcx>> ir::TypeVisitable<TyCtxt<'tcx>> for traits::Obligation<'tcx, O> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.predicate.visit_with(visitor)?;
         self.param_env.visit_with(visitor)
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index b0a5d3674ad..88c6ea7efb2 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1144,7 +1144,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
 
     fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
         struct ProhibitOpaqueTypes;
-        impl<'tcx> ty::visit::TypeVisitor<'tcx> for ProhibitOpaqueTypes {
+        impl<'tcx> ty::visit::ir::TypeVisitor<TyCtxt<'tcx>> for ProhibitOpaqueTypes {
             type BreakTy = Ty<'tcx>;
 
             fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
diff --git a/compiler/rustc_macros/src/type_foldable.rs b/compiler/rustc_macros/src/type_foldable.rs
index 23e619221aa..95bb27ef4f4 100644
--- a/compiler/rustc_macros/src/type_foldable.rs
+++ b/compiler/rustc_macros/src/type_foldable.rs
@@ -17,13 +17,13 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::
         vi.construct(|_, index| {
             let bind = &bindings[index];
             quote! {
-                ::rustc_middle::ty::fold::TypeFoldable::try_fold_with(#bind, __folder)?
+                ::rustc_middle::ty::fold::ir::TypeFoldable::try_fold_with(#bind, __folder)?
             }
         })
     });
 
     s.bound_impl(
-        quote!(::rustc_middle::ty::fold::TypeFoldable<'tcx>),
+        quote!(::rustc_middle::ty::fold::ir::TypeFoldable<::rustc_middle::ty::TyCtxt<'tcx>>),
         quote! {
             fn try_fold_with<__F: ::rustc_middle::ty::fold::FallibleTypeFolder<'tcx>>(
                 self,
diff --git a/compiler/rustc_macros/src/type_visitable.rs b/compiler/rustc_macros/src/type_visitable.rs
index 1f95661ce9d..67057e1a97c 100644
--- a/compiler/rustc_macros/src/type_visitable.rs
+++ b/compiler/rustc_macros/src/type_visitable.rs
@@ -13,13 +13,13 @@ pub fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2:
     s.add_bounds(synstructure::AddBounds::Generics);
     let body_visit = s.each(|bind| {
         quote! {
-            ::rustc_middle::ty::visit::TypeVisitable::visit_with(#bind, __visitor)?;
+            ::rustc_middle::ty::visit::ir::TypeVisitable::visit_with(#bind, __visitor)?;
         }
     });
     s.bind_with(|_| synstructure::BindStyle::Move);
 
     s.bound_impl(
-        quote!(::rustc_middle::ty::visit::TypeVisitable<'tcx>),
+        quote!(::rustc_middle::ty::visit::ir::TypeVisitable<::rustc_middle::ty::TyCtxt<'tcx>>),
         quote! {
             fn visit_with<__V: ::rustc_middle::ty::visit::TypeVisitor<'tcx>>(
                 &self,
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index e6e4545d9c3..ada516aa032 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -42,7 +42,7 @@ pub struct Canonical<'tcx, V> {
 
 pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo<'tcx>>;
 
-impl<'tcx> ty::TypeFoldable<'tcx> for CanonicalVarInfos<'tcx> {
+impl<'tcx> ty::ir::TypeFoldable<TyCtxt<'tcx>> for CanonicalVarInfos<'tcx> {
     fn try_fold_with<F: ty::FallibleTypeFolder<'tcx>>(
         self,
         folder: &mut F,
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 56df1a66f9d..e6cd38c0f15 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -48,18 +48,17 @@
 #![feature(associated_type_bounds)]
 #![feature(rustc_attrs)]
 #![feature(control_flow_enum)]
-#![feature(associated_type_defaults)]
 #![feature(trusted_step)]
 #![feature(try_blocks)]
 #![feature(try_reserve_kind)]
 #![feature(nonzero_ops)]
-#![feature(unwrap_infallible)]
 #![feature(decl_macro)]
 #![feature(drain_filter)]
 #![feature(intra_doc_pointers)]
 #![feature(yeet_expr)]
 #![feature(result_option_inspect)]
 #![feature(const_option)]
+#![feature(trait_alias)]
 #![recursion_limit = "512"]
 #![allow(rustc::potential_query_instability)]
 
diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs
index 250f3d0797e..57d66ac6a03 100644
--- a/compiler/rustc_middle/src/macros.rs
+++ b/compiler/rustc_middle/src/macros.rs
@@ -69,7 +69,7 @@ macro_rules! CloneLiftImpls {
 macro_rules! TrivialTypeTraversalImpls {
     (for <$tcx:lifetime> { $($ty:ty,)+ }) => {
         $(
-            impl<$tcx> $crate::ty::fold::TypeFoldable<$tcx> for $ty {
+            impl<$tcx> $crate::ty::fold::ir::TypeFoldable<$crate::ty::TyCtxt<$tcx>> for $ty {
                 fn try_fold_with<F: $crate::ty::fold::FallibleTypeFolder<$tcx>>(
                     self,
                     _: &mut F,
@@ -86,7 +86,7 @@ macro_rules! TrivialTypeTraversalImpls {
                 }
             }
 
-            impl<$tcx> $crate::ty::visit::TypeVisitable<$tcx> for $ty {
+            impl<$tcx> $crate::ty::visit::ir::TypeVisitable<$crate::ty::TyCtxt<$tcx>> for $ty {
                 #[inline]
                 fn visit_with<F: $crate::ty::visit::TypeVisitor<$tcx>>(
                     &self,
@@ -101,7 +101,7 @@ macro_rules! TrivialTypeTraversalImpls {
 
     ($($ty:ty,)+) => {
         TrivialTypeTraversalImpls! {
-            for <'tcx> {
+            for<'tcx> {
                 $($ty,)+
             }
         }
@@ -115,145 +115,3 @@ macro_rules! TrivialTypeTraversalAndLiftImpls {
         CloneLiftImpls! { $($t)* }
     }
 }
-
-#[macro_export]
-macro_rules! EnumTypeTraversalImpl {
-    (impl<$($p:tt),*> TypeFoldable<$tcx:tt> for $s:path {
-        $($variants:tt)*
-    } $(where $($wc:tt)*)*) => {
-        impl<$($p),*> $crate::ty::fold::TypeFoldable<$tcx> for $s
-            $(where $($wc)*)*
-        {
-            fn try_fold_with<V: $crate::ty::fold::FallibleTypeFolder<$tcx>>(
-                self,
-                folder: &mut V,
-            ) -> ::std::result::Result<Self, V::Error> {
-                EnumTypeTraversalImpl!(@FoldVariants(self, folder) input($($variants)*) output())
-            }
-        }
-    };
-
-    (impl<$($p:tt),*> TypeVisitable<$tcx:tt> for $s:path {
-        $($variants:tt)*
-    } $(where $($wc:tt)*)*) => {
-        impl<$($p),*> $crate::ty::visit::TypeVisitable<$tcx> for $s
-            $(where $($wc)*)*
-        {
-            fn visit_with<V: $crate::ty::visit::TypeVisitor<$tcx>>(
-                &self,
-                visitor: &mut V,
-            ) -> ::std::ops::ControlFlow<V::BreakTy> {
-                EnumTypeTraversalImpl!(@VisitVariants(self, visitor) input($($variants)*) output())
-            }
-        }
-    };
-
-    (@FoldVariants($this:expr, $folder:expr) input() output($($output:tt)*)) => {
-        Ok(match $this {
-            $($output)*
-        })
-    };
-
-    (@FoldVariants($this:expr, $folder:expr)
-     input( ($variant:path) ( $($variant_arg:ident),* ) , $($input:tt)*)
-     output( $($output:tt)*) ) => {
-        EnumTypeTraversalImpl!(
-            @FoldVariants($this, $folder)
-                input($($input)*)
-                output(
-                    $variant ( $($variant_arg),* ) => {
-                        $variant (
-                            $($crate::ty::fold::TypeFoldable::try_fold_with($variant_arg, $folder)?),*
-                        )
-                    }
-                    $($output)*
-                )
-        )
-    };
-
-    (@FoldVariants($this:expr, $folder:expr)
-     input( ($variant:path) { $($variant_arg:ident),* $(,)? } , $($input:tt)*)
-     output( $($output:tt)*) ) => {
-        EnumTypeTraversalImpl!(
-            @FoldVariants($this, $folder)
-                input($($input)*)
-                output(
-                    $variant { $($variant_arg),* } => {
-                        $variant {
-                            $($variant_arg: $crate::ty::fold::TypeFoldable::fold_with(
-                                $variant_arg, $folder
-                            )?),* }
-                    }
-                    $($output)*
-                )
-        )
-    };
-
-    (@FoldVariants($this:expr, $folder:expr)
-     input( ($variant:path), $($input:tt)*)
-     output( $($output:tt)*) ) => {
-        EnumTypeTraversalImpl!(
-            @FoldVariants($this, $folder)
-                input($($input)*)
-                output(
-                    $variant => { $variant }
-                    $($output)*
-                )
-        )
-    };
-
-    (@VisitVariants($this:expr, $visitor:expr) input() output($($output:tt)*)) => {
-        match $this {
-            $($output)*
-        }
-    };
-
-    (@VisitVariants($this:expr, $visitor:expr)
-     input( ($variant:path) ( $($variant_arg:ident),* ) , $($input:tt)*)
-     output( $($output:tt)*) ) => {
-        EnumTypeTraversalImpl!(
-            @VisitVariants($this, $visitor)
-                input($($input)*)
-                output(
-                    $variant ( $($variant_arg),* ) => {
-                        $($crate::ty::visit::TypeVisitable::visit_with(
-                            $variant_arg, $visitor
-                        )?;)*
-                        ::std::ops::ControlFlow::Continue(())
-                    }
-                    $($output)*
-                )
-        )
-    };
-
-    (@VisitVariants($this:expr, $visitor:expr)
-     input( ($variant:path) { $($variant_arg:ident),* $(,)? } , $($input:tt)*)
-     output( $($output:tt)*) ) => {
-        EnumTypeTraversalImpl!(
-            @VisitVariants($this, $visitor)
-                input($($input)*)
-                output(
-                    $variant { $($variant_arg),* } => {
-                        $($crate::ty::visit::TypeVisitable::visit_with(
-                            $variant_arg, $visitor
-                        )?;)*
-                        ::std::ops::ControlFlow::Continue(())
-                    }
-                    $($output)*
-                )
-        )
-    };
-
-    (@VisitVariants($this:expr, $visitor:expr)
-     input( ($variant:path), $($input:tt)*)
-     output( $($output:tt)*) ) => {
-        EnumTypeTraversalImpl!(
-            @VisitVariants($this, $visitor)
-                input($($input)*)
-                output(
-                    $variant => { ::std::ops::ControlFlow::Continue(()) }
-                    $($output)*
-                )
-        )
-    };
-}
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 10ac7e0d39a..6f42b69633c 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -7,10 +7,10 @@ use crate::mir::interpret::{
 };
 use crate::mir::visit::MirVisitable;
 use crate::ty::codec::{TyDecoder, TyEncoder};
-use crate::ty::fold::{FallibleTypeFolder, TypeFoldable};
+use crate::ty::fold::{ir::TypeFoldable, FallibleTypeFolder};
 use crate::ty::print::{FmtPrinter, Printer};
 use crate::ty::visit::{TypeVisitable, TypeVisitor};
-use crate::ty::{self, DefIdTree, List, Ty, TyCtxt};
+use crate::ty::{self, ir, DefIdTree, List, Ty, TyCtxt};
 use crate::ty::{AdtDef, InstanceDef, ScalarInt, UserTypeAnnotationIndex};
 use crate::ty::{GenericArg, InternalSubsts, SubstsRef};
 
@@ -705,7 +705,11 @@ pub enum BindingForm<'tcx> {
     RefForGuard,
 }
 
-TrivialTypeTraversalAndLiftImpls! { BindingForm<'tcx>, }
+TrivialTypeTraversalAndLiftImpls! {
+    for<'tcx> {
+        BindingForm<'tcx>,
+    }
+}
 
 mod binding_form_impl {
     use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -2742,7 +2746,7 @@ impl UserTypeProjection {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection {
+impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for UserTypeProjection {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         Ok(UserTypeProjection {
             base: self.base.try_fold_with(folder)?,
@@ -2751,7 +2755,7 @@ impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection {
     }
 }
 
-impl<'tcx> TypeVisitable<'tcx> for UserTypeProjection {
+impl<'tcx> ir::TypeVisitable<TyCtxt<'tcx>> for UserTypeProjection {
     fn visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> ControlFlow<Vs::BreakTy> {
         self.base.visit_with(visitor)
         // Note: there's nothing in `self.proj` to visit.
diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs
index 0705b4cff53..006085c0ef5 100644
--- a/compiler/rustc_middle/src/mir/type_foldable.rs
+++ b/compiler/rustc_middle/src/mir/type_foldable.rs
@@ -30,25 +30,25 @@ TrivialTypeTraversalImpls! {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for &'tcx [InlineAsmTemplatePiece] {
+impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx [InlineAsmTemplatePiece] {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> {
         Ok(self)
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for &'tcx [Span] {
+impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx [Span] {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> {
         Ok(self)
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> {
+impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<PlaceElem<'tcx>> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         ty::util::fold_list(self, folder, |tcx, v| tcx.intern_place_elems(v))
     }
 }
 
-impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> {
+impl<'tcx, R: Idx, C: Idx> TypeFoldable<TyCtxt<'tcx>> for BitMatrix<R, C> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
         Ok(self)
     }
diff --git a/compiler/rustc_middle/src/mir/type_visitable.rs b/compiler/rustc_middle/src/mir/type_visitable.rs
index d44c6809bd8..e7c5d44b22e 100644
--- a/compiler/rustc_middle/src/mir/type_visitable.rs
+++ b/compiler/rustc_middle/src/mir/type_visitable.rs
@@ -2,7 +2,7 @@
 
 use super::*;
 
-impl<'tcx, R: Idx, C: Idx> TypeVisitable<'tcx> for BitMatrix<R, C> {
+impl<'tcx, R: Idx, C: Idx> ir::TypeVisitable<TyCtxt<'tcx>> for BitMatrix<R, C> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::Continue(())
     }
diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs
index 63f9c32f0a7..bddf84880d2 100644
--- a/compiler/rustc_middle/src/traits/solve.rs
+++ b/compiler/rustc_middle/src/traits/solve.rs
@@ -2,7 +2,10 @@ use std::ops::ControlFlow;
 
 use rustc_data_structures::intern::Interned;
 
-use crate::ty::{FallibleTypeFolder, Ty, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor};
+use crate::ty::{
+    ir::{self, TypeFoldable, TypeVisitable},
+    FallibleTypeFolder, Ty, TyCtxt, TypeFolder, TypeVisitor,
+};
 
 #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
 pub struct ExternalConstraints<'tcx>(pub(crate) Interned<'tcx, ExternalConstraintsData<'tcx>>);
@@ -23,27 +26,29 @@ pub struct ExternalConstraintsData<'tcx> {
     pub opaque_types: Vec<(Ty<'tcx>, Ty<'tcx>)>,
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ExternalConstraints<'tcx> {
+impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ExternalConstraints<'tcx> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        Ok(FallibleTypeFolder::tcx(folder).intern_external_constraints(ExternalConstraintsData {
-            regions: (),
-            opaque_types: self
-                .opaque_types
-                .iter()
-                .map(|opaque| opaque.try_fold_with(folder))
-                .collect::<Result<_, F::Error>>()?,
-        }))
+        Ok(ir::FallibleTypeFolder::interner(folder).intern_external_constraints(
+            ExternalConstraintsData {
+                regions: (),
+                opaque_types: self
+                    .opaque_types
+                    .iter()
+                    .map(|opaque| opaque.try_fold_with(folder))
+                    .collect::<Result<_, F::Error>>()?,
+            },
+        ))
     }
 
     fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
-        TypeFolder::tcx(folder).intern_external_constraints(ExternalConstraintsData {
+        ir::TypeFolder::interner(folder).intern_external_constraints(ExternalConstraintsData {
             regions: (),
             opaque_types: self.opaque_types.iter().map(|opaque| opaque.fold_with(folder)).collect(),
         })
     }
 }
 
-impl<'tcx> TypeVisitable<'tcx> for ExternalConstraints<'tcx> {
+impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ExternalConstraints<'tcx> {
     fn visit_with<V: TypeVisitor<'tcx>>(
         &self,
         visitor: &mut V,
diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs
index 5de758ad9ba..b7f0a0be75e 100644
--- a/compiler/rustc_middle/src/ty/abstract_const.rs
+++ b/compiler/rustc_middle/src/ty/abstract_const.rs
@@ -1,7 +1,6 @@
 //! A subset of a mir body used for const evaluatability checking.
 use crate::ty::{
-    self, Const, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
-    TypeVisitable,
+    self, ir::TypeFolder, Const, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable,
 };
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def_id::DefId;
@@ -53,8 +52,8 @@ impl<'tcx> TyCtxt<'tcx> {
             tcx: TyCtxt<'tcx>,
         }
 
-        impl<'tcx> TypeFolder<'tcx> for Expander<'tcx> {
-            fn tcx(&self) -> TyCtxt<'tcx> {
+        impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Expander<'tcx> {
+            fn interner(&self) -> TyCtxt<'tcx> {
                 self.tcx
             }
             fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 5962384241e..02088fffeb6 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -100,9 +100,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     type AdtDef = ty::AdtDef<'tcx>;
     type SubstsRef = ty::SubstsRef<'tcx>;
     type DefId = DefId;
+    type Binder<T> = Binder<'tcx, T>;
     type Ty = Ty<'tcx>;
     type Const = ty::Const<'tcx>;
     type Region = Region<'tcx>;
+    type Predicate = Predicate<'tcx>;
     type TypeAndMut = TypeAndMut<'tcx>;
     type Mutability = hir::Mutability;
     type Movability = hir::Movability;
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 0a30ae9d0aa..fc529f5d1d0 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -3,9 +3,10 @@
 use std::ops::ControlFlow;
 
 use crate::ty::{
-    visit::TypeVisitable, AliasTy, Const, ConstKind, DefIdTree, FallibleTypeFolder, InferConst,
-    InferTy, Opaque, PolyTraitPredicate, Projection, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable,
-    TypeSuperVisitable, TypeVisitor,
+    ir::{FallibleTypeFolder, TypeVisitor},
+    visit::TypeVisitable,
+    AliasTy, Const, ConstKind, DefIdTree, InferConst, InferTy, Opaque, PolyTraitPredicate,
+    Projection, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable,
 };
 
 use rustc_data_structures::fx::FxHashMap;
@@ -460,7 +461,7 @@ pub struct IsSuggestableVisitor<'tcx> {
     infer_suggestable: bool,
 }
 
-impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> {
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IsSuggestableVisitor<'tcx> {
     type BreakTy = ();
 
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
@@ -535,10 +536,10 @@ pub struct MakeSuggestableFolder<'tcx> {
     infer_suggestable: bool,
 }
 
-impl<'tcx> FallibleTypeFolder<'tcx> for MakeSuggestableFolder<'tcx> {
+impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> {
     type Error = ();
 
-    fn tcx(&self) -> TyCtxt<'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs
index 9e4f90caab0..d3b031bf875 100644
--- a/compiler/rustc_middle/src/ty/erase_regions.rs
+++ b/compiler/rustc_middle/src/ty/erase_regions.rs
@@ -1,5 +1,4 @@
-use crate::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
-use crate::ty::visit::TypeVisitable;
+use crate::ty::fold::{ir::TypeFolder, TypeFoldable, TypeSuperFoldable};
 use crate::ty::{self, Ty, TyCtxt, TypeFlags};
 
 pub(super) fn provide(providers: &mut ty::query::Providers) {
@@ -35,8 +34,8 @@ struct RegionEraserVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
 }
 
-impl<'tcx> TypeFolder<'tcx> for RegionEraserVisitor<'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RegionEraserVisitor<'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index bd78705cdb5..9c171a69d06 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -271,7 +271,7 @@ impl<'tcx> Ty<'tcx> {
             ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(),
             ty::Alias(ty::Projection, _) => "associated type".into(),
             ty::Param(p) => format!("type parameter `{p}`").into(),
-            ty::Alias(ty::Opaque, ..) => "opaque type".into(),
+            ty::Alias(ty::Opaque, ..) => if tcx.ty_is_opaque_future(self) { "future".into() } else { "opaque type".into() },
             ty::Error(_) => "type error".into(),
             _ => {
                 let width = tcx.sess.diagnostic_width();
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index c0d319edf76..352daa8fc29 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -1,209 +1,18 @@
-//! A folding traversal mechanism for complex data structures that contain type
-//! information.
-//!
-//! This is a modifying traversal. It consumes the data structure, producing a
-//! (possibly) modified version of it. Both fallible and infallible versions are
-//! available. The name is potentially confusing, because this traversal is more
-//! like `Iterator::map` than `Iterator::fold`.
-//!
-//! This traversal has limited flexibility. Only a small number of "types of
-//! interest" within the complex data structures can receive custom
-//! modification. These are the ones containing the most important type-related
-//! information, such as `Ty`, `Predicate`, `Region`, and `Const`.
-//!
-//! There are three groups of traits involved in each traversal.
-//! - `TypeFoldable`. This is implemented once for many types, including:
-//!   - Types of interest, for which the methods delegate to the folder.
-//!   - All other types, including generic containers like `Vec` and `Option`.
-//!     It defines a "skeleton" of how they should be folded.
-//! - `TypeSuperFoldable`. This is implemented only for each type of interest,
-//!   and defines the folding "skeleton" for these types.
-//! - `TypeFolder`/`FallibleTypeFolder. One of these is implemented for each
-//!   folder. This defines how types of interest are folded.
-//!
-//! This means each fold is a mixture of (a) generic folding operations, and (b)
-//! custom fold operations that are specific to the folder.
-//! - The `TypeFoldable` impls handle most of the traversal, and call into
-//!   `TypeFolder`/`FallibleTypeFolder` when they encounter a type of interest.
-//! - A `TypeFolder`/`FallibleTypeFolder` may call into another `TypeFoldable`
-//!   impl, because some of the types of interest are recursive and can contain
-//!   other types of interest.
-//! - A `TypeFolder`/`FallibleTypeFolder` may also call into a `TypeSuperFoldable`
-//!   impl, because each folder might provide custom handling only for some types
-//!   of interest, or only for some variants of each type of interest, and then
-//!   use default traversal for the remaining cases.
-//!
-//! For example, if you have `struct S(Ty, U)` where `S: TypeFoldable` and `U:
-//! TypeFoldable`, and an instance `s = S(ty, u)`, it would be folded like so:
-//! ```text
-//! s.fold_with(folder) calls
-//! - ty.fold_with(folder) calls
-//!   - folder.fold_ty(ty) may call
-//!     - ty.super_fold_with(folder)
-//! - u.fold_with(folder)
-//! ```
 use crate::ty::{self, Binder, BoundTy, Ty, TyCtxt, TypeVisitable};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir::def_id::DefId;
 
 use std::collections::BTreeMap;
 
-/// This trait is implemented for every type that can be folded,
-/// providing the skeleton of the traversal.
-///
-/// To implement this conveniently, use the derive macro located in
-/// `rustc_macros`.
-pub trait TypeFoldable<'tcx>: TypeVisitable<'tcx> {
-    /// The entry point for folding. To fold a value `t` with a folder `f`
-    /// call: `t.try_fold_with(f)`.
-    ///
-    /// For most types, this just traverses the value, calling `try_fold_with`
-    /// on each field/element.
-    ///
-    /// For types of interest (such as `Ty`), the implementation of method
-    /// calls a folder method specifically for that type (such as
-    /// `F::try_fold_ty`). This is where control transfers from `TypeFoldable`
-    /// to `TypeFolder`.
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error>;
-
-    /// A convenient alternative to `try_fold_with` for use with infallible
-    /// folders. Do not override this method, to ensure coherence with
-    /// `try_fold_with`.
-    fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
-        self.try_fold_with(folder).into_ok()
-    }
-}
-
-// This trait is implemented for types of interest.
-pub trait TypeSuperFoldable<'tcx>: TypeFoldable<'tcx> {
-    /// Provides a default fold for a type of interest. This should only be
-    /// called within `TypeFolder` methods, when a non-custom traversal is
-    /// desired for the value of the type of interest passed to that method.
-    /// For example, in `MyFolder::try_fold_ty(ty)`, it is valid to call
-    /// `ty.try_super_fold_with(self)`, but any other folding should be done
-    /// with `xyz.try_fold_with(self)`.
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error>;
-
-    /// A convenient alternative to `try_super_fold_with` for use with
-    /// infallible folders. Do not override this method, to ensure coherence
-    /// with `try_super_fold_with`.
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
-        self.try_super_fold_with(folder).into_ok()
-    }
-}
-
-/// This trait is implemented for every infallible folding traversal. There is
-/// a fold method defined for every type of interest. Each such method has a
-/// default that does an "identity" fold. Implementations of these methods
-/// often fall back to a `super_fold_with` method if the primary argument
-/// doesn't satisfy a particular condition.
-///
-/// A blanket implementation of [`FallibleTypeFolder`] will defer to
-/// the infallible methods of this trait to ensure that the two APIs
-/// are coherent.
-pub trait TypeFolder<'tcx>: FallibleTypeFolder<'tcx, Error = !> {
-    fn tcx(&self) -> TyCtxt<'tcx>;
-
-    fn fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, T>
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        t.super_fold_with(self)
-    }
-
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        t.super_fold_with(self)
-    }
-
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        r.super_fold_with(self)
-    }
-
-    fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        c.super_fold_with(self)
-    }
-
-    fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
-        p.super_fold_with(self)
-    }
-}
-
-/// This trait is implemented for every folding traversal. There is a fold
-/// method defined for every type of interest. Each such method has a default
-/// that does an "identity" fold.
-///
-/// A blanket implementation of this trait (that defers to the relevant
-/// method of [`TypeFolder`]) is provided for all infallible folders in
-/// order to ensure the two APIs are coherent.
-pub trait FallibleTypeFolder<'tcx>: Sized {
-    type Error;
-
-    fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
+pub trait TypeFoldable<'tcx> = ir::TypeFoldable<TyCtxt<'tcx>> + TypeVisitable<'tcx>;
+pub trait TypeSuperFoldable<'tcx> = ir::TypeSuperFoldable<TyCtxt<'tcx>>;
+pub trait TypeFolder<'tcx> = ir::TypeFolder<TyCtxt<'tcx>>;
+pub trait FallibleTypeFolder<'tcx> = ir::FallibleTypeFolder<TyCtxt<'tcx>>;
 
-    fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error>
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        t.try_super_fold_with(self)
-    }
-
-    fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
-        t.try_super_fold_with(self)
-    }
-
-    fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
-        r.try_super_fold_with(self)
-    }
-
-    fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
-        c.try_super_fold_with(self)
-    }
-
-    fn try_fold_predicate(
-        &mut self,
-        p: ty::Predicate<'tcx>,
-    ) -> Result<ty::Predicate<'tcx>, Self::Error> {
-        p.try_super_fold_with(self)
-    }
-}
-
-// This blanket implementation of the fallible trait for infallible folders
-// delegates to infallible methods to ensure coherence.
-impl<'tcx, F> FallibleTypeFolder<'tcx> for F
-where
-    F: TypeFolder<'tcx>,
-{
-    type Error = !;
-
-    fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
-        TypeFolder::tcx(self)
-    }
-
-    fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, !>
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        Ok(self.fold_binder(t))
-    }
-
-    fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, !> {
-        Ok(self.fold_ty(t))
-    }
-
-    fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, !> {
-        Ok(self.fold_region(r))
-    }
-
-    fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, !> {
-        Ok(self.fold_const(c))
-    }
-
-    fn try_fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> Result<ty::Predicate<'tcx>, !> {
-        Ok(self.fold_predicate(p))
-    }
+pub mod ir {
+    pub use rustc_type_ir::fold::{
+        FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable,
+    };
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -221,13 +30,13 @@ where
     pub ct_op: H,
 }
 
-impl<'tcx, F, G, H> TypeFolder<'tcx> for BottomUpFolder<'tcx, F, G, H>
+impl<'tcx, F, G, H> ir::TypeFolder<TyCtxt<'tcx>> for BottomUpFolder<'tcx, F, G, H>
 where
     F: FnMut(Ty<'tcx>) -> Ty<'tcx>,
     G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>,
     H: FnMut(ty::Const<'tcx>) -> ty::Const<'tcx>,
 {
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
@@ -311,8 +120,8 @@ impl<'a, 'tcx> RegionFolder<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+impl<'a, 'tcx> ir::TypeFolder<TyCtxt<'tcx>> for RegionFolder<'a, 'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
@@ -385,11 +194,11 @@ impl<'tcx, D: BoundVarReplacerDelegate<'tcx>> BoundVarReplacer<'tcx, D> {
     }
 }
 
-impl<'tcx, D> TypeFolder<'tcx> for BoundVarReplacer<'tcx, D>
+impl<'tcx, D> ir::TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'tcx, D>
 where
     D: BoundVarReplacerDelegate<'tcx>,
 {
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
@@ -651,8 +460,8 @@ impl<'tcx> Shifter<'tcx> {
     }
 }
 
-impl<'tcx> TypeFolder<'tcx> for Shifter<'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+impl<'tcx> ir::TypeFolder<TyCtxt<'tcx>> for Shifter<'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 8b4fccc58bd..55f2395e531 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -1,6 +1,6 @@
 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use crate::ty::print::{FmtPrinter, Printer};
-use crate::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitable};
+use crate::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable};
 use crate::ty::{EarlyBinder, InternalSubsts, SubstsRef};
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::Namespace;
@@ -674,8 +674,8 @@ fn polymorphize<'tcx>(
         tcx: TyCtxt<'tcx>,
     }
 
-    impl<'tcx> ty::TypeFolder<'tcx> for PolymorphizationFolder<'tcx> {
-        fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
+    impl<'tcx> ty::ir::TypeFolder<TyCtxt<'tcx>> for PolymorphizationFolder<'tcx> {
+        fn interner(&self) -> TyCtxt<'tcx> {
             self.tcx
         }
 
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 4c285582138..1d76f435e26 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -1120,6 +1120,13 @@ impl From<call::AdjustForForeignAbiError> for FnAbiError<'_> {
 
 impl<'tcx> fmt::Display for FnAbiError<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        #[cfg(bootstrap)]
+        match self {
+            Self::Layout(err) => fmt::Display::fmt(err, f),
+            Self::AdjustForForeignAbi(err) => fmt::Display::fmt(err, f),
+        }
+
+        #[cfg(not(bootstrap))]
         match self {
             Self::Layout(err) => err.fmt(f),
             Self::AdjustForForeignAbi(err) => err.fmt(f),
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index fa2d3b89cf4..4ed0484438f 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -146,6 +146,10 @@ mod structural_impls;
 mod sty;
 mod typeck_results;
 
+pub mod ir {
+    pub use super::{fold::ir::*, visit::ir::*};
+}
+
 // Data types
 
 pub type RegisteredTools = FxHashSet<Ident>;
@@ -913,13 +917,13 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Term<'tcx> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for Term<'tcx> {
+impl<'tcx> ir::TypeFoldable<TyCtxt<'tcx>> for Term<'tcx> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         Ok(self.unpack().try_fold_with(folder)?.pack())
     }
 }
 
-impl<'tcx> TypeVisitable<'tcx> for Term<'tcx> {
+impl<'tcx> ir::TypeVisitable<TyCtxt<'tcx>> for Term<'tcx> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.unpack().visit_with(visitor)
     }
@@ -1615,7 +1619,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ParamEnv<'tcx> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> {
+impl<'tcx> ir::TypeFoldable<TyCtxt<'tcx>> for ParamEnv<'tcx> {
     fn try_fold_with<F: ty::fold::FallibleTypeFolder<'tcx>>(
         self,
         folder: &mut F,
@@ -1628,7 +1632,7 @@ impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> {
     }
 }
 
-impl<'tcx> TypeVisitable<'tcx> for ParamEnv<'tcx> {
+impl<'tcx> ir::TypeVisitable<TyCtxt<'tcx>> for ParamEnv<'tcx> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.caller_bounds().visit_with(visitor)?;
         self.reveal().visit_with(visitor)
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index ee13920d52e..825e5fbe232 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -9,7 +9,10 @@
 
 use crate::mir;
 use crate::traits::query::NoSolution;
-use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder};
+use crate::ty::fold::{
+    ir::{FallibleTypeFolder, TypeFolder},
+    TypeFoldable,
+};
 use crate::ty::{self, EarlyBinder, SubstsRef, Ty, TyCtxt};
 
 #[derive(Debug, Copy, Clone, HashStable, TyEncodable, TyDecodable)]
@@ -202,8 +205,8 @@ impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> {
     }
 }
 
-impl<'tcx> TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for NormalizeAfterErasingRegionsFolder<'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
@@ -238,10 +241,10 @@ impl<'tcx> TryNormalizeAfterErasingRegionsFolder<'tcx> {
     }
 }
 
-impl<'tcx> FallibleTypeFolder<'tcx> for TryNormalizeAfterErasingRegionsFolder<'tcx> {
+impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for TryNormalizeAfterErasingRegionsFolder<'tcx> {
     type Error = NormalizationError<'tcx>;
 
-    fn tcx(&self) -> TyCtxt<'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs
index a5ebdbc8792..66c878c8b63 100644
--- a/compiler/rustc_middle/src/ty/opaque_types.rs
+++ b/compiler/rustc_middle/src/ty/opaque_types.rs
@@ -1,7 +1,9 @@
 use crate::error::ConstNotUsedTraitAlias;
-use crate::ty::fold::{TypeFolder, TypeSuperFoldable};
+use crate::ty::fold::{ir::TypeFolder, TypeSuperFoldable};
 use crate::ty::subst::{GenericArg, GenericArgKind};
-use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
+#[cfg(not(bootstrap))]
+use crate::ty::TypeFoldable;
+use crate::ty::{self, Ty, TyCtxt};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_span::def_id::DefId;
 use rustc_span::Span;
@@ -91,8 +93,8 @@ impl<'tcx> ReverseMapper<'tcx> {
     }
 }
 
-impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
@@ -141,7 +143,7 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
                     )
                     .emit();
 
-                self.tcx().re_error(e)
+                self.interner().re_error(e)
             }
         }
     }
@@ -186,7 +188,7 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
                                 .emit();
                         }
 
-                        self.tcx().ty_error()
+                        self.interner().ty_error()
                     }
                 }
             }
@@ -214,7 +216,7 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
                             });
                         }
 
-                        self.tcx().const_error(ct.ty())
+                        self.interner().const_error(ct.ty())
                     }
                 }
             }
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index c4a95ddacbf..f50a5d89d3d 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -2221,8 +2221,8 @@ struct RegionFolder<'a, 'tcx> {
             ),
 }
 
-impl<'a, 'tcx> ty::TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+impl<'a, 'tcx> ty::ir::TypeFolder<TyCtxt<'tcx>> for RegionFolder<'a, 'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
@@ -2493,7 +2493,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
             }
         }
 
-        impl<'tcx> ty::visit::TypeVisitor<'tcx> for RegionNameCollector<'tcx> {
+        impl<'tcx> ty::visit::ir::TypeVisitor<TyCtxt<'tcx>> for RegionNameCollector<'tcx> {
             type BreakTy = ();
 
             fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 1ef66b01ea0..97ee2b1fc5d 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -1,20 +1,19 @@
-//! This module contains implements of the `Lift` and `TypeFoldable`
-//! traits for various types in the Rust compiler. Most are written by
-//! hand, though we've recently added some macros and proc-macros to help with the tedium.
+//! This module contains implementations of the `Lift`, `TypeFoldable` and
+//! `TypeVisitable` traits for various types in the Rust compiler. Most are
+//! written by hand, though we've recently added some macros and proc-macros
+//! to help with the tedium.
 
 use crate::mir::interpret;
 use crate::mir::{Field, ProjectionKind};
-use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
+use crate::ty::fold::{ir::TypeSuperFoldable, FallibleTypeFolder, TypeFoldable};
 use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
-use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
-use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
-use rustc_data_structures::functor::IdFunctor;
+use crate::ty::visit::{ir::TypeSuperVisitable, TypeVisitable, TypeVisitor};
+use crate::ty::{self, ir, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
 use rustc_hir::def::Namespace;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_target::abi::TyAndLayout;
 
 use std::fmt;
-use std::mem::ManuallyDrop;
 use std::ops::ControlFlow;
 use std::rc::Rc;
 use std::sync::Arc;
@@ -195,17 +194,27 @@ impl<'tcx> fmt::Debug for AliasTy<'tcx> {
 // Atomic structs
 //
 // For things that don't carry any arena-allocated data (and are
-// copy...), just add them to this list.
+// copy...), just add them to one of these lists as appropriat.
 
-TrivialTypeTraversalAndLiftImpls! {
+// For things for which the type library provides traversal implementations
+// for all Interners, we only need to provide a Lift implementation:
+CloneLiftImpls! {
     (),
     bool,
     usize,
-    ::rustc_target::abi::VariantIdx,
     u16,
     u32,
     u64,
     String,
+    rustc_type_ir::DebruijnIndex,
+}
+
+// For things about which the type library does not know, or does not
+// provide any traversal implementations, we need to provide both a Lift
+// implementation and traversal implementations (the latter only for
+// TyCtxt<'_> interners).
+TrivialTypeTraversalAndLiftImpls! {
+    ::rustc_target::abi::VariantIdx,
     crate::middle::region::Scope,
     crate::ty::FloatTy,
     ::rustc_ast::InlineAsmOptions,
@@ -257,7 +266,6 @@ TrivialTypeTraversalAndLiftImpls! {
     Field,
     interpret::Scalar,
     rustc_target::abi::Size,
-    rustc_type_ir::DebruijnIndex,
     ty::BoundVar,
     ty::Placeholder<ty::BoundVar>,
 }
@@ -360,235 +368,34 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> {
 }
 
 ///////////////////////////////////////////////////////////////////////////
-// TypeFoldable implementations.
+// Traversal implementations.
 
 /// AdtDefs are basically the same as a DefId.
-impl<'tcx> TypeFoldable<'tcx> for ty::AdtDef<'tcx> {
+impl<'tcx> ir::TypeFoldable<TyCtxt<'tcx>> for ty::AdtDef<'tcx> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> {
         Ok(self)
     }
 }
 
-impl<'tcx> TypeVisitable<'tcx> for ty::AdtDef<'tcx> {
+impl<'tcx> ir::TypeVisitable<TyCtxt<'tcx>> for ty::AdtDef<'tcx> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::Continue(())
     }
 }
 
-impl<'tcx, T: TypeFoldable<'tcx>, U: TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) {
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<(T, U), F::Error> {
-        Ok((self.0.try_fold_with(folder)?, self.1.try_fold_with(folder)?))
-    }
-}
-
-impl<'tcx, T: TypeVisitable<'tcx>, U: TypeVisitable<'tcx>> TypeVisitable<'tcx> for (T, U) {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        self.0.visit_with(visitor)?;
-        self.1.visit_with(visitor)
-    }
-}
-
-impl<'tcx, A: TypeFoldable<'tcx>, B: TypeFoldable<'tcx>, C: TypeFoldable<'tcx>> TypeFoldable<'tcx>
-    for (A, B, C)
-{
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<(A, B, C), F::Error> {
-        Ok((
-            self.0.try_fold_with(folder)?,
-            self.1.try_fold_with(folder)?,
-            self.2.try_fold_with(folder)?,
-        ))
-    }
-}
-
-impl<'tcx, A: TypeVisitable<'tcx>, B: TypeVisitable<'tcx>, C: TypeVisitable<'tcx>>
-    TypeVisitable<'tcx> for (A, B, C)
-{
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        self.0.visit_with(visitor)?;
-        self.1.visit_with(visitor)?;
-        self.2.visit_with(visitor)
-    }
-}
-
-EnumTypeTraversalImpl! {
-    impl<'tcx, T> TypeFoldable<'tcx> for Option<T> {
-        (Some)(a),
-        (None),
-    } where T: TypeFoldable<'tcx>
-}
-EnumTypeTraversalImpl! {
-    impl<'tcx, T> TypeVisitable<'tcx> for Option<T> {
-        (Some)(a),
-        (None),
-    } where T: TypeVisitable<'tcx>
-}
-
-EnumTypeTraversalImpl! {
-    impl<'tcx, T, E> TypeFoldable<'tcx> for Result<T, E> {
-        (Ok)(a),
-        (Err)(a),
-    } where T: TypeFoldable<'tcx>, E: TypeFoldable<'tcx>,
-}
-EnumTypeTraversalImpl! {
-    impl<'tcx, T, E> TypeVisitable<'tcx> for Result<T, E> {
-        (Ok)(a),
-        (Err)(a),
-    } where T: TypeVisitable<'tcx>, E: TypeVisitable<'tcx>,
-}
-
-impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> {
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(
-        mut self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
-        // We merely want to replace the contained `T`, if at all possible,
-        // so that we don't needlessly allocate a new `Rc` or indeed clone
-        // the contained type.
-        unsafe {
-            // First step is to ensure that we have a unique reference to
-            // the contained type, which `Rc::make_mut` will accomplish (by
-            // allocating a new `Rc` and cloning the `T` only if required).
-            // This is done *before* casting to `Rc<ManuallyDrop<T>>` so that
-            // panicking during `make_mut` does not leak the `T`.
-            Rc::make_mut(&mut self);
-
-            // Casting to `Rc<ManuallyDrop<T>>` is safe because `ManuallyDrop`
-            // is `repr(transparent)`.
-            let ptr = Rc::into_raw(self).cast::<ManuallyDrop<T>>();
-            let mut unique = Rc::from_raw(ptr);
-
-            // Call to `Rc::make_mut` above guarantees that `unique` is the
-            // sole reference to the contained value, so we can avoid doing
-            // a checked `get_mut` here.
-            let slot = Rc::get_mut_unchecked(&mut unique);
-
-            // Semantically move the contained type out from `unique`, fold
-            // it, then move the folded value back into `unique`. Should
-            // folding fail, `ManuallyDrop` ensures that the "moved-out"
-            // value is not re-dropped.
-            let owned = ManuallyDrop::take(slot);
-            let folded = owned.try_fold_with(folder)?;
-            *slot = ManuallyDrop::new(folded);
-
-            // Cast back to `Rc<T>`.
-            Ok(Rc::from_raw(Rc::into_raw(unique).cast()))
-        }
-    }
-}
-
-impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for Rc<T> {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        (**self).visit_with(visitor)
-    }
-}
-
-impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Arc<T> {
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(
-        mut self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
-        // We merely want to replace the contained `T`, if at all possible,
-        // so that we don't needlessly allocate a new `Arc` or indeed clone
-        // the contained type.
-        unsafe {
-            // First step is to ensure that we have a unique reference to
-            // the contained type, which `Arc::make_mut` will accomplish (by
-            // allocating a new `Arc` and cloning the `T` only if required).
-            // This is done *before* casting to `Arc<ManuallyDrop<T>>` so that
-            // panicking during `make_mut` does not leak the `T`.
-            Arc::make_mut(&mut self);
-
-            // Casting to `Arc<ManuallyDrop<T>>` is safe because `ManuallyDrop`
-            // is `repr(transparent)`.
-            let ptr = Arc::into_raw(self).cast::<ManuallyDrop<T>>();
-            let mut unique = Arc::from_raw(ptr);
-
-            // Call to `Arc::make_mut` above guarantees that `unique` is the
-            // sole reference to the contained value, so we can avoid doing
-            // a checked `get_mut` here.
-            let slot = Arc::get_mut_unchecked(&mut unique);
-
-            // Semantically move the contained type out from `unique`, fold
-            // it, then move the folded value back into `unique`. Should
-            // folding fail, `ManuallyDrop` ensures that the "moved-out"
-            // value is not re-dropped.
-            let owned = ManuallyDrop::take(slot);
-            let folded = owned.try_fold_with(folder)?;
-            *slot = ManuallyDrop::new(folded);
-
-            // Cast back to `Arc<T>`.
-            Ok(Arc::from_raw(Arc::into_raw(unique).cast()))
-        }
-    }
-}
-
-impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for Arc<T> {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        (**self).visit_with(visitor)
-    }
-}
-
-impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<T> {
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        self.try_map_id(|value| value.try_fold_with(folder))
-    }
-}
-
-impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for Box<T> {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        (**self).visit_with(visitor)
-    }
-}
-
-impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> {
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        self.try_map_id(|t| t.try_fold_with(folder))
-    }
-}
-
-impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for Vec<T> {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        self.iter().try_for_each(|t| t.visit_with(visitor))
-    }
-}
-
-impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for &[T] {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        self.iter().try_for_each(|t| t.visit_with(visitor))
-    }
-}
-
-impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> {
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        self.try_map_id(|t| t.try_fold_with(folder))
-    }
-}
-
-impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for Box<[T]> {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        self.iter().try_for_each(|t| t.visit_with(visitor))
-    }
-}
-
-impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<'tcx, T> {
+impl<'tcx, T: TypeFoldable<'tcx>> ir::TypeFoldable<TyCtxt<'tcx>> for ty::Binder<'tcx, T> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         folder.try_fold_binder(self)
     }
 }
 
-impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for ty::Binder<'tcx, T> {
+impl<'tcx, T: TypeVisitable<'tcx>> ir::TypeVisitable<TyCtxt<'tcx>> for ty::Binder<'tcx, T> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         visitor.visit_binder(self)
     }
 }
 
-impl<'tcx, T: TypeFoldable<'tcx>> TypeSuperFoldable<'tcx> for ty::Binder<'tcx, T> {
+impl<'tcx, T: TypeFoldable<'tcx>> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Binder<'tcx, T> {
     fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
         self,
         folder: &mut F,
@@ -597,43 +404,43 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeSuperFoldable<'tcx> for ty::Binder<'tcx, T
     }
 }
 
-impl<'tcx, T: TypeVisitable<'tcx>> TypeSuperVisitable<'tcx> for ty::Binder<'tcx, T> {
+impl<'tcx, T: TypeVisitable<'tcx>> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Binder<'tcx, T> {
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.as_ref().skip_binder().visit_with(visitor)
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> {
+impl<'tcx> ir::TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         ty::util::fold_list(self, folder, |tcx, v| tcx.intern_poly_existential_predicates(v))
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Const<'tcx>> {
+impl<'tcx> ir::TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::Const<'tcx>> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         ty::util::fold_list(self, folder, |tcx, v| tcx.mk_const_list(v.iter()))
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ProjectionKind> {
+impl<'tcx> ir::TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ProjectionKind> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         ty::util::fold_list(self, folder, |tcx, v| tcx.intern_projs(v))
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
+impl<'tcx> ir::TypeFoldable<TyCtxt<'tcx>> for Ty<'tcx> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         folder.try_fold_ty(self)
     }
 }
 
-impl<'tcx> TypeVisitable<'tcx> for Ty<'tcx> {
+impl<'tcx> ir::TypeVisitable<TyCtxt<'tcx>> for Ty<'tcx> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         visitor.visit_ty(*self)
     }
 }
 
-impl<'tcx> TypeSuperFoldable<'tcx> for Ty<'tcx> {
+impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for Ty<'tcx> {
     fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
         self,
         folder: &mut F,
@@ -679,11 +486,11 @@ impl<'tcx> TypeSuperFoldable<'tcx> for Ty<'tcx> {
             | ty::Foreign(..) => return Ok(self),
         };
 
-        Ok(if *self.kind() == kind { self } else { folder.tcx().mk_ty(kind) })
+        Ok(if *self.kind() == kind { self } else { folder.interner().mk_ty(kind) })
     }
 }
 
-impl<'tcx> TypeSuperVisitable<'tcx> for Ty<'tcx> {
+impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for Ty<'tcx> {
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         match self.kind() {
             ty::RawPtr(ref tm) => tm.visit_with(visitor),
@@ -727,19 +534,19 @@ impl<'tcx> TypeSuperVisitable<'tcx> for Ty<'tcx> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> {
+impl<'tcx> ir::TypeFoldable<TyCtxt<'tcx>> for ty::Region<'tcx> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         folder.try_fold_region(self)
     }
 }
 
-impl<'tcx> TypeVisitable<'tcx> for ty::Region<'tcx> {
+impl<'tcx> ir::TypeVisitable<TyCtxt<'tcx>> for ty::Region<'tcx> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         visitor.visit_region(*self)
     }
 }
 
-impl<'tcx> TypeSuperFoldable<'tcx> for ty::Region<'tcx> {
+impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Region<'tcx> {
     fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
         self,
         _folder: &mut F,
@@ -748,81 +555,59 @@ impl<'tcx> TypeSuperFoldable<'tcx> for ty::Region<'tcx> {
     }
 }
 
-impl<'tcx> TypeSuperVisitable<'tcx> for ty::Region<'tcx> {
+impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Region<'tcx> {
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::Continue(())
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
+impl<'tcx> ir::TypeFoldable<TyCtxt<'tcx>> for ty::Predicate<'tcx> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         folder.try_fold_predicate(self)
     }
 }
 
-impl<'tcx> TypeVisitable<'tcx> for ty::Predicate<'tcx> {
+impl<'tcx> ir::TypeVisitable<TyCtxt<'tcx>> for ty::Predicate<'tcx> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         visitor.visit_predicate(*self)
     }
-
-    #[inline]
-    fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
-        self.outer_exclusive_binder() > binder
-    }
-
-    #[inline]
-    fn has_type_flags(&self, flags: ty::TypeFlags) -> bool {
-        self.flags().intersects(flags)
-    }
 }
 
-impl<'tcx> TypeSuperFoldable<'tcx> for ty::Predicate<'tcx> {
+impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Predicate<'tcx> {
     fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
         self,
         folder: &mut F,
     ) -> Result<Self, F::Error> {
         let new = self.kind().try_fold_with(folder)?;
-        Ok(folder.tcx().reuse_or_mk_predicate(self, new))
+        Ok(folder.interner().reuse_or_mk_predicate(self, new))
     }
 }
 
-impl<'tcx> TypeSuperVisitable<'tcx> for ty::Predicate<'tcx> {
+impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Predicate<'tcx> {
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.kind().visit_with(visitor)
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
+impl<'tcx> ir::TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::Predicate<'tcx>> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         ty::util::fold_list(self, folder, |tcx, v| tcx.intern_predicates(v))
     }
 }
 
-impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T> {
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        self.try_map_id(|x| x.try_fold_with(folder))
-    }
-}
-
-impl<'tcx, T: TypeVisitable<'tcx>, I: Idx> TypeVisitable<'tcx> for IndexVec<I, T> {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        self.iter().try_for_each(|t| t.visit_with(visitor))
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::Const<'tcx> {
+impl<'tcx> ir::TypeFoldable<TyCtxt<'tcx>> for ty::Const<'tcx> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         folder.try_fold_const(self)
     }
 }
 
-impl<'tcx> TypeVisitable<'tcx> for ty::Const<'tcx> {
+impl<'tcx> ir::TypeVisitable<TyCtxt<'tcx>> for ty::Const<'tcx> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         visitor.visit_const(*self)
     }
 }
 
-impl<'tcx> TypeSuperFoldable<'tcx> for ty::Const<'tcx> {
+impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Const<'tcx> {
     fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
         self,
         folder: &mut F,
@@ -830,39 +615,39 @@ impl<'tcx> TypeSuperFoldable<'tcx> for ty::Const<'tcx> {
         let ty = self.ty().try_fold_with(folder)?;
         let kind = self.kind().try_fold_with(folder)?;
         if ty != self.ty() || kind != self.kind() {
-            Ok(folder.tcx().mk_const(kind, ty))
+            Ok(folder.interner().mk_const(kind, ty))
         } else {
             Ok(self)
         }
     }
 }
 
-impl<'tcx> TypeSuperVisitable<'tcx> for ty::Const<'tcx> {
+impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Const<'tcx> {
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.ty().visit_with(visitor)?;
         self.kind().visit_with(visitor)
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> {
+impl<'tcx> ir::TypeFoldable<TyCtxt<'tcx>> for InferConst<'tcx> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> {
         Ok(self)
     }
 }
 
-impl<'tcx> TypeVisitable<'tcx> for InferConst<'tcx> {
+impl<'tcx> ir::TypeVisitable<TyCtxt<'tcx>> for InferConst<'tcx> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::Continue(())
     }
 }
 
-impl<'tcx> TypeSuperVisitable<'tcx> for ty::UnevaluatedConst<'tcx> {
+impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::UnevaluatedConst<'tcx> {
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.substs.visit_with(visitor)
     }
 }
 
-impl<'tcx> TypeVisitable<'tcx> for TyAndLayout<'tcx, Ty<'tcx>> {
+impl<'tcx> ir::TypeVisitable<TyCtxt<'tcx>> for TyAndLayout<'tcx, Ty<'tcx>> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         visitor.visit_ty(self.ty)
     }
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 89cde91e755..abde81236e2 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -7,8 +7,10 @@ use crate::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
 use crate::ty::visit::ValidateBoundVars;
 use crate::ty::InferTy::*;
 use crate::ty::{
-    self, AdtDef, DefIdTree, Discr, FallibleTypeFolder, Term, Ty, TyCtxt, TypeFlags, TypeFoldable,
-    TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor,
+    self,
+    ir::{FallibleTypeFolder, TypeVisitor},
+    AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeSuperFoldable,
+    TypeSuperVisitable, TypeVisitable,
 };
 use crate::ty::{List, ParamEnv};
 use hir::def::DefKind;
@@ -1147,10 +1149,10 @@ struct SkipBindersAt<'tcx> {
     index: ty::DebruijnIndex,
 }
 
-impl<'tcx> FallibleTypeFolder<'tcx> for SkipBindersAt<'tcx> {
+impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for SkipBindersAt<'tcx> {
     type Error = ();
 
-    fn tcx(&self) -> TyCtxt<'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
@@ -1171,7 +1173,7 @@ impl<'tcx> FallibleTypeFolder<'tcx> for SkipBindersAt<'tcx> {
             if index == self.index {
                 Err(())
             } else {
-                Ok(self.tcx().mk_bound(index.shifted_out(1), bv))
+                Ok(self.interner().mk_bound(index.shifted_out(1), bv))
             }
         } else {
             ty.try_super_fold_with(self)
@@ -1185,7 +1187,7 @@ impl<'tcx> FallibleTypeFolder<'tcx> for SkipBindersAt<'tcx> {
             if index == self.index {
                 Err(())
             } else {
-                Ok(self.tcx().mk_region(ty::ReLateBound(index.shifted_out(1), bv)))
+                Ok(self.interner().mk_region(ty::ReLateBound(index.shifted_out(1), bv)))
             }
         } else {
             r.try_super_fold_with(self)
@@ -1199,7 +1201,7 @@ impl<'tcx> FallibleTypeFolder<'tcx> for SkipBindersAt<'tcx> {
             if index == self.index {
                 Err(())
             } else {
-                Ok(self.tcx().mk_const(
+                Ok(self.interner().mk_const(
                     ty::ConstKind::Bound(index.shifted_out(1), bv),
                     ct.ty().try_fold_with(self)?,
                 ))
@@ -2038,7 +2040,7 @@ impl<'tcx> Ty<'tcx> {
     pub fn contains(self, other: Ty<'tcx>) -> bool {
         struct ContainsTyVisitor<'tcx>(Ty<'tcx>);
 
-        impl<'tcx> TypeVisitor<'tcx> for ContainsTyVisitor<'tcx> {
+        impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ContainsTyVisitor<'tcx> {
             type BreakTy = ();
 
             fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
@@ -2056,7 +2058,7 @@ impl<'tcx> Ty<'tcx> {
     pub fn contains_closure(self) -> bool {
         struct ContainsClosureVisitor;
 
-        impl<'tcx> TypeVisitor<'tcx> for ContainsClosureVisitor {
+        impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ContainsClosureVisitor {
             type BreakTy = ();
 
             fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index cf1bb5f8ac8..a6ab7440c8e 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -1,10 +1,10 @@
 // Type substitutions.
 
 use crate::ty::codec::{TyDecoder, TyEncoder};
-use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
+use crate::ty::fold::{ir::TypeFolder, FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
 use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts};
 use crate::ty::visit::{TypeVisitable, TypeVisitor};
-use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
+use crate::ty::{self, ir, Lift, List, ParamConst, Ty, TyCtxt};
 
 use rustc_data_structures::intern::Interned;
 use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg};
@@ -227,7 +227,7 @@ impl<'a, 'tcx> Lift<'tcx> for GenericArg<'a> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for GenericArg<'tcx> {
+impl<'tcx> ir::TypeFoldable<TyCtxt<'tcx>> for GenericArg<'tcx> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         match self.unpack() {
             GenericArgKind::Lifetime(lt) => lt.try_fold_with(folder).map(Into::into),
@@ -237,7 +237,7 @@ impl<'tcx> TypeFoldable<'tcx> for GenericArg<'tcx> {
     }
 }
 
-impl<'tcx> TypeVisitable<'tcx> for GenericArg<'tcx> {
+impl<'tcx> ir::TypeVisitable<TyCtxt<'tcx>> for GenericArg<'tcx> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         match self.unpack() {
             GenericArgKind::Lifetime(lt) => lt.visit_with(visitor),
@@ -475,7 +475,7 @@ impl<'tcx> InternalSubsts<'tcx> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> {
+impl<'tcx> ir::TypeFoldable<TyCtxt<'tcx>> for SubstsRef<'tcx> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         // This code is hot enough that it's worth specializing for the most
         // common length lists, to avoid the overhead of `SmallVec` creation.
@@ -486,7 +486,11 @@ impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> {
         match self.len() {
             1 => {
                 let param0 = self[0].try_fold_with(folder)?;
-                if param0 == self[0] { Ok(self) } else { Ok(folder.tcx().intern_substs(&[param0])) }
+                if param0 == self[0] {
+                    Ok(self)
+                } else {
+                    Ok(folder.interner().intern_substs(&[param0]))
+                }
             }
             2 => {
                 let param0 = self[0].try_fold_with(folder)?;
@@ -494,7 +498,7 @@ impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> {
                 if param0 == self[0] && param1 == self[1] {
                     Ok(self)
                 } else {
-                    Ok(folder.tcx().intern_substs(&[param0, param1]))
+                    Ok(folder.interner().intern_substs(&[param0, param1]))
                 }
             }
             0 => Ok(self),
@@ -503,7 +507,7 @@ impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
+impl<'tcx> ir::TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<Ty<'tcx>> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         // This code is fairly hot, though not as hot as `SubstsRef`.
         //
@@ -527,7 +531,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
                 if param0 == self[0] && param1 == self[1] {
                     Ok(self)
                 } else {
-                    Ok(folder.tcx().intern_type_list(&[param0, param1]))
+                    Ok(folder.interner().intern_type_list(&[param0, param1]))
                 }
             }
             _ => ty::util::fold_list(self, folder, |tcx, v| tcx.intern_type_list(v)),
@@ -535,7 +539,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
     }
 }
 
-impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for &'tcx ty::List<T> {
+impl<'tcx, T: TypeVisitable<'tcx>> ir::TypeVisitable<TyCtxt<'tcx>> for &'tcx ty::List<T> {
     #[inline]
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|t| t.visit_with(visitor))
@@ -553,8 +557,8 @@ impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for &'tcx ty::List<T> {
 pub struct EarlyBinder<T>(pub T);
 
 /// For early binders, you should first call `subst` before using any visitors.
-impl<'tcx, T> !TypeFoldable<'tcx> for ty::EarlyBinder<T> {}
-impl<'tcx, T> !TypeVisitable<'tcx> for ty::EarlyBinder<T> {}
+impl<'tcx, T> !ir::TypeFoldable<TyCtxt<'tcx>> for ty::EarlyBinder<T> {}
+impl<'tcx, T> !ir::TypeVisitable<TyCtxt<'tcx>> for ty::EarlyBinder<T> {}
 
 impl<T> EarlyBinder<T> {
     pub fn as_ref(&self) -> EarlyBinder<&T> {
@@ -776,9 +780,9 @@ struct SubstFolder<'a, 'tcx> {
     binders_passed: u32,
 }
 
-impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
+impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for SubstFolder<'a, 'tcx> {
     #[inline]
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
@@ -987,7 +991,7 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> {
             return val;
         }
 
-        let result = ty::fold::shift_vars(TypeFolder::tcx(self), val, self.binders_passed);
+        let result = ty::fold::shift_vars(TypeFolder::interner(self), val, self.binders_passed);
         debug!("shift_vars: shifted result = {:?}", result);
 
         result
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 796164b0d6a..e907ce46c86 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -4,8 +4,8 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use crate::mir;
 use crate::ty::layout::IntegerExt;
 use crate::ty::{
-    self, DefIdTree, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
-    TypeVisitable,
+    self, ir::TypeFolder, DefIdTree, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable,
+    TypeSuperFoldable,
 };
 use crate::ty::{GenericArgKind, SubstsRef};
 use rustc_apfloat::Float as _;
@@ -842,8 +842,8 @@ impl<'tcx> OpaqueTypeExpander<'tcx> {
     }
 }
 
-impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for OpaqueTypeExpander<'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
@@ -1343,7 +1343,7 @@ where
             for t in iter {
                 new_list.push(t.try_fold_with(folder)?)
             }
-            Ok(intern(folder.tcx(), &new_list))
+            Ok(intern(folder.interner(), &new_list))
         }
         Some((_, Err(err))) => {
             return Err(err);
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
index d7b7a094737..8a93b59900e 100644
--- a/compiler/rustc_middle/src/ty/visit.rs
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -1,69 +1,19 @@
-//! A visiting traversal mechanism for complex data structures that contain type
-//! information.
-//!
-//! This is a read-only traversal of the data structure.
-//!
-//! This traversal has limited flexibility. Only a small number of "types of
-//! interest" within the complex data structures can receive custom
-//! visitation. These are the ones containing the most important type-related
-//! information, such as `Ty`, `Predicate`, `Region`, and `Const`.
-//!
-//! There are three groups of traits involved in each traversal.
-//! - `TypeVisitable`. This is implemented once for many types, including:
-//!   - Types of interest, for which the methods delegate to the visitor.
-//!   - All other types, including generic containers like `Vec` and `Option`.
-//!     It defines a "skeleton" of how they should be visited.
-//! - `TypeSuperVisitable`. This is implemented only for each type of interest,
-//!   and defines the visiting "skeleton" for these types.
-//! - `TypeVisitor`. This is implemented for each visitor. This defines how
-//!   types of interest are visited.
-//!
-//! This means each visit is a mixture of (a) generic visiting operations, and (b)
-//! custom visit operations that are specific to the visitor.
-//! - The `TypeVisitable` impls handle most of the traversal, and call into
-//!   `TypeVisitor` when they encounter a type of interest.
-//! - A `TypeVisitor` may call into another `TypeVisitable` impl, because some of
-//!   the types of interest are recursive and can contain other types of interest.
-//! - A `TypeVisitor` may also call into a `TypeSuperVisitable` impl, because each
-//!   visitor might provide custom handling only for some types of interest, or
-//!   only for some variants of each type of interest, and then use default
-//!   traversal for the remaining cases.
-//!
-//! For example, if you have `struct S(Ty, U)` where `S: TypeVisitable` and `U:
-//! TypeVisitable`, and an instance `s = S(ty, u)`, it would be visited like so:
-//! ```text
-//! s.visit_with(visitor) calls
-//! - ty.visit_with(visitor) calls
-//!   - visitor.visit_ty(ty) may call
-//!     - ty.super_visit_with(visitor)
-//! - u.visit_with(visitor)
-//! ```
 use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags};
 use rustc_errors::ErrorGuaranteed;
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sso::SsoHashSet;
-use std::fmt;
 use std::ops::ControlFlow;
 
-/// This trait is implemented for every type that can be visited,
-/// providing the skeleton of the traversal.
-///
-/// To implement this conveniently, use the derive macro located in
-/// `rustc_macros`.
-pub trait TypeVisitable<'tcx>: fmt::Debug + Clone {
-    /// The entry point for visiting. To visit a value `t` with a visitor `v`
-    /// call: `t.visit_with(v)`.
-    ///
-    /// For most types, this just traverses the value, calling `visit_with` on
-    /// each field/element.
-    ///
-    /// For types of interest (such as `Ty`), the implementation of this method
-    /// that calls a visitor method specifically for that type (such as
-    /// `V::visit_ty`). This is where control transfers from `TypeFoldable` to
-    /// `TypeVisitor`.
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
+pub trait TypeVisitable<'tcx> = ir::TypeVisitable<TyCtxt<'tcx>> + TypeVisitableExt<'tcx>;
+pub trait TypeSuperVisitable<'tcx> = ir::TypeSuperVisitable<TyCtxt<'tcx>>;
+pub trait TypeVisitor<'tcx> = ir::TypeVisitor<TyCtxt<'tcx>>;
+
+pub mod ir {
+    pub use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
+}
 
+pub trait TypeVisitableExt<'tcx>: ir::TypeVisitable<TyCtxt<'tcx>> {
     /// Returns `true` if `self` has any late-bound regions that are either
     /// bound by `binder` or bound by some binder outside of `binder`.
     /// If `binder` is `ty::INNERMOST`, this indicates whether
@@ -185,45 +135,7 @@ pub trait TypeVisitable<'tcx>: fmt::Debug + Clone {
     }
 }
 
-pub trait TypeSuperVisitable<'tcx>: TypeVisitable<'tcx> {
-    /// Provides a default visit for a type of interest. This should only be
-    /// called within `TypeVisitor` methods, when a non-custom traversal is
-    /// desired for the value of the type of interest passed to that method.
-    /// For example, in `MyVisitor::visit_ty(ty)`, it is valid to call
-    /// `ty.super_visit_with(self)`, but any other visiting should be done
-    /// with `xyz.visit_with(self)`.
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
-}
-
-/// This trait is implemented for every visiting traversal. There is a visit
-/// method defined for every type of interest. Each such method has a default
-/// that recurses into the type's fields in a non-custom fashion.
-pub trait TypeVisitor<'tcx>: Sized {
-    type BreakTy = !;
-
-    fn visit_binder<T: TypeVisitable<'tcx>>(
-        &mut self,
-        t: &Binder<'tcx, T>,
-    ) -> ControlFlow<Self::BreakTy> {
-        t.super_visit_with(self)
-    }
-
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-        t.super_visit_with(self)
-    }
-
-    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
-        r.super_visit_with(self)
-    }
-
-    fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-        c.super_visit_with(self)
-    }
-
-    fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
-        p.super_visit_with(self)
-    }
-}
+impl<'tcx, T: ir::TypeVisitable<TyCtxt<'tcx>>> TypeVisitableExt<'tcx> for T {}
 
 ///////////////////////////////////////////////////////////////////////////
 // Region folder
@@ -278,7 +190,7 @@ impl<'tcx> TyCtxt<'tcx> {
             callback: F,
         }
 
-        impl<'tcx, F> TypeVisitor<'tcx> for RegionVisitor<F>
+        impl<'tcx, F> ir::TypeVisitor<TyCtxt<'tcx>> for RegionVisitor<F>
         where
             F: FnMut(ty::Region<'tcx>) -> bool,
         {
@@ -380,7 +292,7 @@ impl<'tcx> ValidateBoundVars<'tcx> {
     }
 }
 
-impl<'tcx> TypeVisitor<'tcx> for ValidateBoundVars<'tcx> {
+impl<'tcx> ir::TypeVisitor<TyCtxt<'tcx>> for ValidateBoundVars<'tcx> {
     type BreakTy = ();
 
     fn visit_binder<T: TypeVisitable<'tcx>>(
@@ -492,7 +404,7 @@ struct HasEscapingVarsVisitor {
     outer_index: ty::DebruijnIndex,
 }
 
-impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor {
+impl<'tcx> ir::TypeVisitor<TyCtxt<'tcx>> for HasEscapingVarsVisitor {
     type BreakTy = FoundEscapingVars;
 
     fn visit_binder<T: TypeVisitable<'tcx>>(
@@ -569,7 +481,7 @@ impl std::fmt::Debug for HasTypeFlagsVisitor {
     }
 }
 
-impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
+impl<'tcx> ir::TypeVisitor<TyCtxt<'tcx>> for HasTypeFlagsVisitor {
     type BreakTy = FoundFlags;
 
     #[inline]
@@ -639,7 +551,7 @@ impl LateBoundRegionsCollector {
     }
 }
 
-impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector {
+impl<'tcx> ir::TypeVisitor<TyCtxt<'tcx>> for LateBoundRegionsCollector {
     fn visit_binder<T: TypeVisitable<'tcx>>(
         &mut self,
         t: &Binder<'tcx, T>,
@@ -701,7 +613,7 @@ impl MaxUniverse {
     }
 }
 
-impl<'tcx> TypeVisitor<'tcx> for MaxUniverse {
+impl<'tcx> ir::TypeVisitor<TyCtxt<'tcx>> for MaxUniverse {
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         if let ty::Placeholder(placeholder) = t.kind() {
             self.max_universe = ty::UniverseIndex::from_u32(
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 31a3ffbb1d8..83b8988ceca 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -189,9 +189,7 @@ use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::query::TyCtxtAt;
 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
-use rustc_middle::ty::{
-    self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitable, VtblEntry,
-};
+use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable, VtblEntry};
 use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags, mir::visit::TyContext};
 use rustc_session::config::EntryFnType;
 use rustc_session::lint::builtin::LARGE_ASSIGNMENTS;
diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs
index cf13d4584a1..aba842817ef 100644
--- a/compiler/rustc_monomorphize/src/polymorphize.rs
+++ b/compiler/rustc_monomorphize/src/polymorphize.rs
@@ -15,7 +15,7 @@ use rustc_middle::ty::{
     self,
     query::Providers,
     subst::SubstsRef,
-    visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
+    visit::{ir::TypeVisitor, TypeSuperVisitable, TypeVisitable},
     Const, Ty, TyCtxt, UnusedGenericParams,
 };
 use rustc_span::symbol::sym;
@@ -296,7 +296,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
+impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for MarkUsedGenericParams<'a, 'tcx> {
     #[instrument(level = "debug", skip(self))]
     fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         if !c.has_non_region_param() {
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 43552861532..9cff62e8514 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -28,7 +28,7 @@ use rustc_middle::span_bug;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::{self, Const, DefIdTree, GenericParamDefKind};
-use rustc_middle::ty::{TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
+use rustc_middle::ty::{ir::TypeVisitor, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
 use rustc_session::lint;
 use rustc_span::hygiene::Transparency;
 use rustc_span::symbol::{kw, sym, Ident};
@@ -174,7 +174,7 @@ where
     }
 }
 
-impl<'tcx, V> TypeVisitor<'tcx> for DefIdVisitorSkeleton<'_, 'tcx, V>
+impl<'tcx, V> TypeVisitor<TyCtxt<'tcx>> for DefIdVisitorSkeleton<'_, 'tcx, V>
 where
     V: DefIdVisitor<'tcx> + ?Sized,
 {
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index 50c1787ef8c..c0bfe152a1e 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -6,7 +6,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_middle::arena::ArenaAllocatable;
 use rustc_middle::infer::canonical::{Canonical, CanonicalQueryResponse, QueryResponse};
 use rustc_middle::traits::query::Fallible;
-use rustc_middle::ty::{self, Ty, TypeFoldable, TypeVisitable};
+use rustc_middle::ty::{self, Ty, TypeFoldable};
 use rustc_middle::ty::{GenericArg, ToPredicate};
 use rustc_span::{Span, DUMMY_SP};
 
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index 4fea49893a6..b52200e066f 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -14,7 +14,7 @@ use rustc_infer::traits::specialization_graph::LeafDef;
 use rustc_infer::traits::Reveal;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_middle::ty::{ProjectionPredicate, TypeSuperVisitable, TypeVisitor};
+use rustc_middle::ty::{ir::TypeVisitor, ProjectionPredicate, TypeSuperVisitable};
 use rustc_middle::ty::{ToPredicate, TypeVisitable};
 use rustc_span::{sym, DUMMY_SP};
 use std::iter;
@@ -98,7 +98,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         struct ContainsTerm<'tcx> {
             term: ty::Term<'tcx>,
         }
-        impl<'tcx> TypeVisitor<'tcx> for ContainsTerm<'tcx> {
+        impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ContainsTerm<'tcx> {
             type BreakTy = ();
             fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 if t.needs_infer() {
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 6a840704e86..3adb15cb441 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -8,7 +8,8 @@ use crate::infer::region_constraints::{Constraint, RegionConstraintData};
 use crate::infer::InferCtxt;
 use crate::traits::project::ProjectAndUnifyResult;
 use rustc_middle::mir::interpret::ErrorHandled;
-use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::fold::{ir::TypeFolder, TypeSuperFoldable};
+#[cfg(not(bootstrap))]
 use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{ImplPolarity, Region, RegionVid};
 
@@ -858,8 +859,8 @@ pub struct RegionReplacer<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
 }
 
-impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for RegionReplacer<'a, 'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 61f508a7a07..a95694e5144 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -22,7 +22,7 @@ use rustc_infer::traits::util;
 use rustc_middle::traits::specialization_graph::OverlapMode;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::visit::TypeVisitable;
-use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitor};
+use rustc_middle::ty::{self, ir::TypeVisitor, ImplSubject, Ty, TyCtxt};
 use rustc_span::symbol::sym;
 use rustc_span::DUMMY_SP;
 use std::fmt::Debug;
@@ -627,7 +627,7 @@ enum OrphanCheckEarlyExit<'tcx> {
     LocalTy(Ty<'tcx>),
 }
 
-impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> {
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OrphanChecker<'tcx> {
     type BreakTy = OrphanCheckEarlyExit<'tcx>;
     fn visit_region(&mut self, _r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         ControlFlow::Continue(())
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 786473457ae..dd9b5b534d7 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -14,7 +14,7 @@ use rustc_middle::mir::interpret::ErrorHandled;
 
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
-use rustc_middle::ty::{self, TyCtxt, TypeVisitable, TypeVisitor};
+use rustc_middle::ty::{self, ir::TypeVisitor, TyCtxt, TypeVisitable};
 
 use rustc_span::Span;
 use std::ops::ControlFlow;
@@ -171,7 +171,7 @@ fn satisfied_from_param_env<'tcx>(
         single_match: Option<Result<ty::Const<'tcx>, ()>>,
     }
 
-    impl<'a, 'tcx> TypeVisitor<'tcx> for Visitor<'a, 'tcx> {
+    impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for Visitor<'a, 'tcx> {
         type BreakTy = ();
         fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
             debug!("is_const_evaluatable: candidate={:?}", c);
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 4867855c2ae..c2565b7a3aa 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -34,11 +34,10 @@ use rustc_infer::infer::{InferOk, TypeTrace};
 use rustc_middle::traits::select::OverflowError;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::fold::{ir::TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::print::{with_forced_trimmed_paths, FmtPrinter, Print};
 use rustc_middle::ty::{
     self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
-    TypeVisitable,
 };
 use rustc_session::config::TraitSolver;
 use rustc_session::Limit;
@@ -2675,8 +2674,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             var_map: FxHashMap<Ty<'tcx>, Ty<'tcx>>,
         }
 
-        impl<'a, 'tcx> TypeFolder<'tcx> for ParamToVarFolder<'a, 'tcx> {
-            fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+        impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ParamToVarFolder<'a, 'tcx> {
+            fn interner(&self) -> TyCtxt<'tcx> {
                 self.infcx.tcx
             }
 
@@ -2964,7 +2963,7 @@ impl ArgKind {
 
 struct HasNumericInferVisitor;
 
-impl<'tcx> ty::TypeVisitor<'tcx> for HasNumericInferVisitor {
+impl<'tcx> ty::ir::TypeVisitor<TyCtxt<'tcx>> for HasNumericInferVisitor {
     type BreakTy = ();
 
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index cca178299df..0a1dfa7925b 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -30,10 +30,10 @@ use rustc_middle::hir::map;
 use rustc_middle::ty::error::TypeError::{self, Sorts};
 use rustc_middle::ty::relate::TypeRelation;
 use rustc_middle::ty::{
-    self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
-    GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, InternalSubsts,
-    IsSuggestable, ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder,
-    TypeSuperFoldable, TypeVisitable, TypeckResults,
+    self, ir::TypeFolder, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind,
+    DefIdTree, GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, InternalSubsts,
+    IsSuggestable, ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeSuperFoldable,
+    TypeckResults,
 };
 use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::{sym, Ident, Symbol};
@@ -4081,7 +4081,7 @@ struct ReplaceImplTraitFolder<'tcx> {
     replace_ty: Ty<'tcx>,
 }
 
-impl<'tcx> TypeFolder<'tcx> for ReplaceImplTraitFolder<'tcx> {
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceImplTraitFolder<'tcx> {
     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         if let ty::Param(ty::ParamTy { index, .. }) = t.kind() {
             if self.param.index == *index {
@@ -4091,7 +4091,7 @@ impl<'tcx> TypeFolder<'tcx> for ReplaceImplTraitFolder<'tcx> {
         t.super_fold_with(self)
     }
 
-    fn tcx(&self) -> TyCtxt<'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 83458017e00..067e63de911 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -481,7 +481,7 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI
         generics: &'tcx ty::Generics,
         trait_item_def_id: DefId,
     }
-    impl<'tcx> ty::TypeVisitor<'tcx> for ReferencesOnlyParentGenerics<'tcx> {
+    impl<'tcx> ty::ir::TypeVisitor<TyCtxt<'tcx>> for ReferencesOnlyParentGenerics<'tcx> {
         type BreakTy = ();
         fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
             // If this is a parameter from the trait item's own generics, then bail
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 977446894e7..c12ba103c34 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -19,7 +19,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
 use rustc_middle::ty::{
-    self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
+    self, ir::TypeVisitor, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
 };
 use rustc_middle::ty::{Predicate, ToPredicate};
 use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
@@ -836,7 +836,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
         supertraits: Option<Vec<DefId>>,
     }
 
-    impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> {
+    impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalSelfTypeVisitor<'tcx> {
         type BreakTy = ();
 
         fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index c2bce774bb5..a380d4697ea 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -30,7 +30,7 @@ use rustc_infer::infer::at::At;
 use rustc_infer::infer::resolve::OpportunisticRegionResolver;
 use rustc_infer::traits::ImplSourceBuiltinData;
 use rustc_middle::traits::select::OverflowError;
-use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::fold::{ir::TypeFolder, TypeFoldable, TypeSuperFoldable};
 use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable};
 use rustc_middle::ty::DefIdTree;
 use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt};
@@ -448,8 +448,8 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
     }
 }
 
-impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
-    fn tcx<'c>(&'c self) -> TyCtxt<'tcx> {
+impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.selcx.tcx()
     }
 
@@ -503,7 +503,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
                     Reveal::UserFacing => ty.super_fold_with(self),
 
                     Reveal::All => {
-                        let recursion_limit = self.tcx().recursion_limit();
+                        let recursion_limit = self.interner().recursion_limit();
                         if !recursion_limit.value_within_limit(self.depth) {
                             self.selcx.infcx.err_ctxt().report_overflow_error(
                                 &ty,
@@ -514,8 +514,8 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
                         }
 
                         let substs = substs.fold_with(self);
-                        let generic_ty = self.tcx().bound_type_of(def_id);
-                        let concrete_ty = generic_ty.subst(self.tcx(), substs);
+                        let generic_ty = self.interner().bound_type_of(def_id);
+                        let concrete_ty = generic_ty.subst(self.interner(), substs);
                         self.depth += 1;
                         let folded_ty = self.fold_ty(concrete_ty);
                         self.depth -= 1;
@@ -740,8 +740,8 @@ impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> {
     }
 }
 
-impl<'tcx> TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
 
@@ -846,8 +846,8 @@ impl<'me, 'tcx> PlaceholderReplacer<'me, 'tcx> {
     }
 }
 
-impl<'tcx> TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
 
@@ -888,7 +888,7 @@ impl<'tcx> TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> {
                         let db = ty::DebruijnIndex::from_usize(
                             self.universe_indices.len() - index + self.current_index.as_usize() - 1,
                         );
-                        self.tcx().mk_region(ty::ReLateBound(db, *replace_var))
+                        self.interner().mk_region(ty::ReLateBound(db, *replace_var))
                     }
                     None => r1,
                 }
@@ -915,7 +915,7 @@ impl<'tcx> TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> {
                         let db = ty::DebruijnIndex::from_usize(
                             self.universe_indices.len() - index + self.current_index.as_usize() - 1,
                         );
-                        self.tcx().mk_bound(db, *replace_var)
+                        self.interner().mk_bound(db, *replace_var)
                     }
                     None => ty,
                 }
@@ -939,7 +939,7 @@ impl<'tcx> TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> {
                     let db = ty::DebruijnIndex::from_usize(
                         self.universe_indices.len() - index + self.current_index.as_usize() - 1,
                     );
-                    self.tcx().mk_const(ty::ConstKind::Bound(db, *replace_var), ct.ty())
+                    self.interner().mk_const(ty::ConstKind::Bound(db, *replace_var), ct.ty())
                 }
                 None => ct,
             }
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 1b2533a5cf6..e7282a450f6 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -11,9 +11,9 @@ use crate::traits::{ObligationCause, PredicateObligation, Reveal};
 use rustc_data_structures::sso::SsoHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_infer::traits::Normalized;
-use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
+use rustc_middle::ty::fold::{ir::FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
 use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor};
+use rustc_middle::ty::{self, ir::TypeVisitor, Ty, TyCtxt};
 use rustc_span::DUMMY_SP;
 
 use std::ops::ControlFlow;
@@ -115,7 +115,7 @@ struct MaxEscapingBoundVarVisitor {
     escaping: usize,
 }
 
-impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor {
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MaxEscapingBoundVarVisitor {
     fn visit_binder<T: TypeVisitable<'tcx>>(
         &mut self,
         t: &ty::Binder<'tcx, T>,
@@ -170,10 +170,10 @@ struct QueryNormalizer<'cx, 'tcx> {
     universes: Vec<Option<ty::UniverseIndex>>,
 }
 
-impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
+impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx> {
     type Error = NoSolution;
 
-    fn tcx<'c>(&'c self) -> TyCtxt<'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
 
@@ -214,7 +214,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
 
                     Reveal::All => {
                         let substs = substs.try_fold_with(self)?;
-                        let recursion_limit = self.tcx().recursion_limit();
+                        let recursion_limit = self.interner().recursion_limit();
                         if !recursion_limit.value_within_limit(self.anon_depth) {
                             // A closure or generator may have itself as in its upvars.
                             // This should be checked handled by the recursion check for opaque
@@ -228,8 +228,8 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
                             return ty.try_super_fold_with(self);
                         }
 
-                        let generic_ty = self.tcx().bound_type_of(def_id);
-                        let concrete_ty = generic_ty.subst(self.tcx(), substs);
+                        let generic_ty = self.interner().bound_type_of(def_id);
+                        let concrete_ty = generic_ty.subst(self.interner(), substs);
                         self.anon_depth += 1;
                         if concrete_ty == ty {
                             bug!(
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 45c4811321a..302adb79766 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -48,7 +48,7 @@ use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::relate::TypeRelation;
 use rustc_middle::ty::SubstsRef;
 use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
-use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitable};
+use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable};
 use rustc_session::config::TraitSolver;
 use rustc_span::symbol::sym;
 
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
index 69b965f3a38..8402499b296 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -1,6 +1,8 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
+#[cfg(not(bootstrap))]
+use rustc_middle::ty::TypeVisitable;
+use rustc_middle::ty::{self, ir::TypeVisitor, Ty, TyCtxt, TypeSuperVisitable};
 use rustc_span::Span;
 use std::ops::ControlFlow;
 
@@ -78,7 +80,7 @@ impl<'tcx> Search<'tcx> {
     }
 }
 
-impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> {
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Search<'tcx> {
     type BreakTy = Ty<'tcx>;
 
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs
index 7101f404269..20725c656de 100644
--- a/compiler/rustc_traits/src/chalk/db.rs
+++ b/compiler/rustc_traits/src/chalk/db.rs
@@ -769,8 +769,8 @@ struct ReplaceOpaqueTyFolder<'tcx> {
     binder_index: ty::DebruijnIndex,
 }
 
-impl<'tcx> ty::TypeFolder<'tcx> for ReplaceOpaqueTyFolder<'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+impl<'tcx> ty::ir::TypeFolder<TyCtxt<'tcx>> for ReplaceOpaqueTyFolder<'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index 4f71dcde818..2978fc4ed8c 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -35,8 +35,9 @@ use rustc_ast::ast;
 use rustc_middle::traits::{ChalkEnvironmentAndGoal, ChalkRustInterner as RustInterner};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
 use rustc_middle::ty::{
-    self, Binder, Region, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
-    TypeSuperVisitable, TypeVisitable, TypeVisitor,
+    self,
+    ir::{TypeFolder, TypeVisitor},
+    Binder, Region, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable,
 };
 use rustc_span::def_id::DefId;
 
@@ -925,7 +926,7 @@ impl<'tcx> BoundVarsCollector<'tcx> {
     }
 }
 
-impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for BoundVarsCollector<'tcx> {
     fn visit_binder<T: TypeVisitable<'tcx>>(
         &mut self,
         t: &Binder<'tcx, T>,
@@ -1006,8 +1007,8 @@ impl<'a, 'tcx> NamedBoundVarSubstitutor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> TypeFolder<'tcx> for NamedBoundVarSubstitutor<'a, 'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for NamedBoundVarSubstitutor<'a, 'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
@@ -1062,8 +1063,8 @@ impl<'tcx> ParamsSubstitutor<'tcx> {
     }
 }
 
-impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ParamsSubstitutor<'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
@@ -1138,8 +1139,8 @@ impl<'tcx> ReverseParamsSubstitutor<'tcx> {
     }
 }
 
-impl<'tcx> TypeFolder<'tcx> for ReverseParamsSubstitutor<'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseParamsSubstitutor<'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
@@ -1174,7 +1175,7 @@ impl PlaceholdersCollector {
     }
 }
 
-impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector {
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for PlaceholdersCollector {
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         match t.kind() {
             ty::Placeholder(p) if p.universe == self.universe_index => {
diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs
index 5855a8e28dd..f33f9edd627 100644
--- a/compiler/rustc_traits/src/chalk/mod.rs
+++ b/compiler/rustc_traits/src/chalk/mod.rs
@@ -9,7 +9,7 @@ pub(crate) mod lowering;
 use rustc_middle::infer::canonical::{CanonicalTyVarKind, CanonicalVarKind};
 use rustc_middle::traits::ChalkRustInterner;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, TyCtxt, TypeFoldable, TypeVisitable};
+use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
 
 use rustc_infer::infer::canonical::{
     Canonical, CanonicalVarValues, Certainty, QueryRegionConstraints, QueryResponse,
diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs
new file mode 100644
index 00000000000..ee4ef57c38f
--- /dev/null
+++ b/compiler/rustc_type_ir/src/fold.rs
@@ -0,0 +1,239 @@
+//! A folding traversal mechanism for complex data structures that contain type
+//! information.
+//!
+//! This is a modifying traversal. It consumes the data structure, producing a
+//! (possibly) modified version of it. Both fallible and infallible versions are
+//! available. The name is potentially confusing, because this traversal is more
+//! like `Iterator::map` than `Iterator::fold`.
+//!
+//! This traversal has limited flexibility. Only a small number of "types of
+//! interest" within the complex data structures can receive custom
+//! modification. These are the ones containing the most important type-related
+//! information, such as `Ty`, `Predicate`, `Region`, and `Const`.
+//!
+//! There are three groups of traits involved in each traversal.
+//! - `TypeFoldable`. This is implemented once for many types, including:
+//!   - Types of interest, for which the methods delegate to the folder.
+//!   - All other types, including generic containers like `Vec` and `Option`.
+//!     It defines a "skeleton" of how they should be folded.
+//! - `TypeSuperFoldable`. This is implemented only for each type of interest,
+//!   and defines the folding "skeleton" for these types.
+//! - `TypeFolder`/`FallibleTypeFolder. One of these is implemented for each
+//!   folder. This defines how types of interest are folded.
+//!
+//! This means each fold is a mixture of (a) generic folding operations, and (b)
+//! custom fold operations that are specific to the folder.
+//! - The `TypeFoldable` impls handle most of the traversal, and call into
+//!   `TypeFolder`/`FallibleTypeFolder` when they encounter a type of interest.
+//! - A `TypeFolder`/`FallibleTypeFolder` may call into another `TypeFoldable`
+//!   impl, because some of the types of interest are recursive and can contain
+//!   other types of interest.
+//! - A `TypeFolder`/`FallibleTypeFolder` may also call into a `TypeSuperFoldable`
+//!   impl, because each folder might provide custom handling only for some types
+//!   of interest, or only for some variants of each type of interest, and then
+//!   use default traversal for the remaining cases.
+//!
+//! For example, if you have `struct S(Ty, U)` where `S: TypeFoldable` and `U:
+//! TypeFoldable`, and an instance `s = S(ty, u)`, it would be folded like so:
+//! ```text
+//! s.fold_with(folder) calls
+//! - ty.fold_with(folder) calls
+//!   - folder.fold_ty(ty) may call
+//!     - ty.super_fold_with(folder)
+//! - u.fold_with(folder)
+//! ```
+use crate::{visit::TypeVisitable, Interner};
+
+/// This trait is implemented for every type that can be folded,
+/// providing the skeleton of the traversal.
+///
+/// To implement this conveniently, use the derive macro located in
+/// `rustc_macros`.
+pub trait TypeFoldable<I: Interner>: TypeVisitable<I> {
+    /// The entry point for folding. To fold a value `t` with a folder `f`
+    /// call: `t.try_fold_with(f)`.
+    ///
+    /// For most types, this just traverses the value, calling `try_fold_with`
+    /// on each field/element.
+    ///
+    /// For types of interest (such as `Ty`), the implementation of method
+    /// calls a folder method specifically for that type (such as
+    /// `F::try_fold_ty`). This is where control transfers from `TypeFoldable`
+    /// to `TypeFolder`.
+    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error>;
+
+    /// A convenient alternative to `try_fold_with` for use with infallible
+    /// folders. Do not override this method, to ensure coherence with
+    /// `try_fold_with`.
+    fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
+        self.try_fold_with(folder).into_ok()
+    }
+}
+
+// This trait is implemented for types of interest.
+pub trait TypeSuperFoldable<I: Interner>: TypeFoldable<I> {
+    /// Provides a default fold for a type of interest. This should only be
+    /// called within `TypeFolder` methods, when a non-custom traversal is
+    /// desired for the value of the type of interest passed to that method.
+    /// For example, in `MyFolder::try_fold_ty(ty)`, it is valid to call
+    /// `ty.try_super_fold_with(self)`, but any other folding should be done
+    /// with `xyz.try_fold_with(self)`.
+    fn try_super_fold_with<F: FallibleTypeFolder<I>>(
+        self,
+        folder: &mut F,
+    ) -> Result<Self, F::Error>;
+
+    /// A convenient alternative to `try_super_fold_with` for use with
+    /// infallible folders. Do not override this method, to ensure coherence
+    /// with `try_super_fold_with`.
+    fn super_fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
+        self.try_super_fold_with(folder).into_ok()
+    }
+}
+
+/// This trait is implemented for every infallible folding traversal. There is
+/// a fold method defined for every type of interest. Each such method has a
+/// default that does an "identity" fold. Implementations of these methods
+/// often fall back to a `super_fold_with` method if the primary argument
+/// doesn't satisfy a particular condition.
+///
+/// A blanket implementation of [`FallibleTypeFolder`] will defer to
+/// the infallible methods of this trait to ensure that the two APIs
+/// are coherent.
+pub trait TypeFolder<I: Interner>: FallibleTypeFolder<I, Error = !> {
+    fn interner(&self) -> I;
+
+    fn fold_binder<T>(&mut self, t: I::Binder<T>) -> I::Binder<T>
+    where
+        T: TypeFoldable<I>,
+        I::Binder<T>: TypeSuperFoldable<I>,
+    {
+        t.super_fold_with(self)
+    }
+
+    fn fold_ty(&mut self, t: I::Ty) -> I::Ty
+    where
+        I::Ty: TypeSuperFoldable<I>,
+    {
+        t.super_fold_with(self)
+    }
+
+    fn fold_region(&mut self, r: I::Region) -> I::Region
+    where
+        I::Region: TypeSuperFoldable<I>,
+    {
+        r.super_fold_with(self)
+    }
+
+    fn fold_const(&mut self, c: I::Const) -> I::Const
+    where
+        I::Const: TypeSuperFoldable<I>,
+    {
+        c.super_fold_with(self)
+    }
+
+    fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate
+    where
+        I::Predicate: TypeSuperFoldable<I>,
+    {
+        p.super_fold_with(self)
+    }
+}
+
+/// This trait is implemented for every folding traversal. There is a fold
+/// method defined for every type of interest. Each such method has a default
+/// that does an "identity" fold.
+///
+/// A blanket implementation of this trait (that defers to the relevant
+/// method of [`TypeFolder`]) is provided for all infallible folders in
+/// order to ensure the two APIs are coherent.
+pub trait FallibleTypeFolder<I: Interner>: Sized {
+    type Error;
+
+    fn interner(&self) -> I;
+
+    fn try_fold_binder<T>(&mut self, t: I::Binder<T>) -> Result<I::Binder<T>, Self::Error>
+    where
+        T: TypeFoldable<I>,
+        I::Binder<T>: TypeSuperFoldable<I>,
+    {
+        t.try_super_fold_with(self)
+    }
+
+    fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, Self::Error>
+    where
+        I::Ty: TypeSuperFoldable<I>,
+    {
+        t.try_super_fold_with(self)
+    }
+
+    fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, Self::Error>
+    where
+        I::Region: TypeSuperFoldable<I>,
+    {
+        r.try_super_fold_with(self)
+    }
+
+    fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, Self::Error>
+    where
+        I::Const: TypeSuperFoldable<I>,
+    {
+        c.try_super_fold_with(self)
+    }
+
+    fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Self::Error>
+    where
+        I::Predicate: TypeSuperFoldable<I>,
+    {
+        p.try_super_fold_with(self)
+    }
+}
+
+// This blanket implementation of the fallible trait for infallible folders
+// delegates to infallible methods to ensure coherence.
+impl<I: Interner, F> FallibleTypeFolder<I> for F
+where
+    F: TypeFolder<I>,
+{
+    type Error = !;
+
+    fn interner(&self) -> I {
+        TypeFolder::interner(self)
+    }
+
+    fn try_fold_binder<T>(&mut self, t: I::Binder<T>) -> Result<I::Binder<T>, !>
+    where
+        T: TypeFoldable<I>,
+        I::Binder<T>: TypeSuperFoldable<I>,
+    {
+        Ok(self.fold_binder(t))
+    }
+
+    fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, !>
+    where
+        I::Ty: TypeSuperFoldable<I>,
+    {
+        Ok(self.fold_ty(t))
+    }
+
+    fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, !>
+    where
+        I::Region: TypeSuperFoldable<I>,
+    {
+        Ok(self.fold_region(r))
+    }
+
+    fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, !>
+    where
+        I::Const: TypeSuperFoldable<I>,
+    {
+        Ok(self.fold_const(c))
+    }
+
+    fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, !>
+    where
+        I::Predicate: TypeSuperFoldable<I>,
+    {
+        Ok(self.fold_predicate(p))
+    }
+}
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 4aa958878d4..29d261fda8d 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -1,6 +1,10 @@
+#![feature(associated_type_defaults)]
 #![feature(fmt_helpers_for_derive)]
+#![feature(get_mut_unchecked)]
 #![feature(min_specialization)]
+#![feature(never_type)]
 #![feature(rustc_attrs)]
+#![feature(unwrap_infallible)]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
 
@@ -18,8 +22,14 @@ use std::hash::Hash;
 use std::mem::discriminant;
 
 pub mod codec;
+pub mod fold;
 pub mod sty;
 pub mod ty_info;
+pub mod visit;
+
+#[macro_use]
+mod macros;
+mod structural_impls;
 
 pub use codec::*;
 pub use sty::*;
@@ -28,13 +38,15 @@ pub use ty_info::*;
 /// Needed so we can use #[derive(HashStable_Generic)]
 pub trait HashStableContext {}
 
-pub trait Interner {
+pub trait Interner: Sized {
     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 Binder<T>;
     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 Predicate;
     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;
diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs
new file mode 100644
index 00000000000..6c181039730
--- /dev/null
+++ b/compiler/rustc_type_ir/src/macros.rs
@@ -0,0 +1,176 @@
+/// Used for types that are `Copy` and which **do not care arena
+/// allocated data** (i.e., don't need to be folded).
+macro_rules! TrivialTypeTraversalImpls {
+    ($($ty:ty,)+) => {
+        $(
+            impl<I: $crate::Interner> $crate::fold::TypeFoldable<I> for $ty {
+                fn try_fold_with<F: $crate::fold::FallibleTypeFolder<I>>(
+                    self,
+                    _: &mut F,
+                ) -> ::std::result::Result<Self, F::Error> {
+                    Ok(self)
+                }
+
+                #[inline]
+                fn fold_with<F: $crate::fold::TypeFolder<I>>(
+                    self,
+                    _: &mut F,
+                ) -> Self {
+                    self
+                }
+            }
+
+            impl<I: $crate::Interner> $crate::visit::TypeVisitable<I> for $ty {
+                #[inline]
+                fn visit_with<F: $crate::visit::TypeVisitor<I>>(
+                    &self,
+                    _: &mut F)
+                    -> ::std::ops::ControlFlow<F::BreakTy>
+                {
+                    ::std::ops::ControlFlow::Continue(())
+                }
+            }
+        )+
+    };
+}
+
+macro_rules! EnumTypeTraversalImpl {
+    (impl<$($p:tt),*> TypeFoldable<$tcx:tt> for $s:path {
+        $($variants:tt)*
+    } $(where $($wc:tt)*)*) => {
+        impl<$($p),*> $crate::fold::TypeFoldable<$tcx> for $s
+            $(where $($wc)*)*
+        {
+            fn try_fold_with<V: $crate::fold::FallibleTypeFolder<$tcx>>(
+                self,
+                folder: &mut V,
+            ) -> ::std::result::Result<Self, V::Error> {
+                EnumTypeTraversalImpl!(@FoldVariants(self, folder) input($($variants)*) output())
+            }
+        }
+    };
+
+    (impl<$($p:tt),*> TypeVisitable<$tcx:tt> for $s:path {
+        $($variants:tt)*
+    } $(where $($wc:tt)*)*) => {
+        impl<$($p),*> $crate::visit::TypeVisitable<$tcx> for $s
+            $(where $($wc)*)*
+        {
+            fn visit_with<V: $crate::visit::TypeVisitor<$tcx>>(
+                &self,
+                visitor: &mut V,
+            ) -> ::std::ops::ControlFlow<V::BreakTy> {
+                EnumTypeTraversalImpl!(@VisitVariants(self, visitor) input($($variants)*) output())
+            }
+        }
+    };
+
+    (@FoldVariants($this:expr, $folder:expr) input() output($($output:tt)*)) => {
+        Ok(match $this {
+            $($output)*
+        })
+    };
+
+    (@FoldVariants($this:expr, $folder:expr)
+     input( ($variant:path) ( $($variant_arg:ident),* ) , $($input:tt)*)
+     output( $($output:tt)*) ) => {
+        EnumTypeTraversalImpl!(
+            @FoldVariants($this, $folder)
+                input($($input)*)
+                output(
+                    $variant ( $($variant_arg),* ) => {
+                        $variant (
+                            $($crate::fold::TypeFoldable::try_fold_with($variant_arg, $folder)?),*
+                        )
+                    }
+                    $($output)*
+                )
+        )
+    };
+
+    (@FoldVariants($this:expr, $folder:expr)
+     input( ($variant:path) { $($variant_arg:ident),* $(,)? } , $($input:tt)*)
+     output( $($output:tt)*) ) => {
+        EnumTypeTraversalImpl!(
+            @FoldVariants($this, $folder)
+                input($($input)*)
+                output(
+                    $variant { $($variant_arg),* } => {
+                        $variant {
+                            $($variant_arg: $crate::fold::TypeFoldable::fold_with(
+                                $variant_arg, $folder
+                            )?),* }
+                    }
+                    $($output)*
+                )
+        )
+    };
+
+    (@FoldVariants($this:expr, $folder:expr)
+     input( ($variant:path), $($input:tt)*)
+     output( $($output:tt)*) ) => {
+        EnumTypeTraversalImpl!(
+            @FoldVariants($this, $folder)
+                input($($input)*)
+                output(
+                    $variant => { $variant }
+                    $($output)*
+                )
+        )
+    };
+
+    (@VisitVariants($this:expr, $visitor:expr) input() output($($output:tt)*)) => {
+        match $this {
+            $($output)*
+        }
+    };
+
+    (@VisitVariants($this:expr, $visitor:expr)
+     input( ($variant:path) ( $($variant_arg:ident),* ) , $($input:tt)*)
+     output( $($output:tt)*) ) => {
+        EnumTypeTraversalImpl!(
+            @VisitVariants($this, $visitor)
+                input($($input)*)
+                output(
+                    $variant ( $($variant_arg),* ) => {
+                        $($crate::visit::TypeVisitable::visit_with(
+                            $variant_arg, $visitor
+                        )?;)*
+                        ::std::ops::ControlFlow::Continue(())
+                    }
+                    $($output)*
+                )
+        )
+    };
+
+    (@VisitVariants($this:expr, $visitor:expr)
+     input( ($variant:path) { $($variant_arg:ident),* $(,)? } , $($input:tt)*)
+     output( $($output:tt)*) ) => {
+        EnumTypeTraversalImpl!(
+            @VisitVariants($this, $visitor)
+                input($($input)*)
+                output(
+                    $variant { $($variant_arg),* } => {
+                        $($crate::visit::TypeVisitable::visit_with(
+                            $variant_arg, $visitor
+                        )?;)*
+                        ::std::ops::ControlFlow::Continue(())
+                    }
+                    $($output)*
+                )
+        )
+    };
+
+    (@VisitVariants($this:expr, $visitor:expr)
+     input( ($variant:path), $($input:tt)*)
+     output( $($output:tt)*) ) => {
+        EnumTypeTraversalImpl!(
+            @VisitVariants($this, $visitor)
+                input($($input)*)
+                output(
+                    $variant => { ::std::ops::ControlFlow::Continue(()) }
+                    $($output)*
+                )
+        )
+    };
+}
diff --git a/compiler/rustc_type_ir/src/structural_impls.rs b/compiler/rustc_type_ir/src/structural_impls.rs
new file mode 100644
index 00000000000..b6abe9a7357
--- /dev/null
+++ b/compiler/rustc_type_ir/src/structural_impls.rs
@@ -0,0 +1,238 @@
+//! This module contains implementations of the `TypeFoldable` and `TypeVisitable`
+//! traits for various types in the Rust compiler. Most are written by hand, though
+//! we've recently added some macros and proc-macros to help with the tedium.
+
+use crate::fold::{FallibleTypeFolder, TypeFoldable};
+use crate::visit::{TypeVisitable, TypeVisitor};
+use crate::Interner;
+use rustc_data_structures::functor::IdFunctor;
+use rustc_index::vec::{Idx, IndexVec};
+
+use std::mem::ManuallyDrop;
+use std::ops::ControlFlow;
+use std::rc::Rc;
+use std::sync::Arc;
+
+///////////////////////////////////////////////////////////////////////////
+// Atomic structs
+//
+// For things that don't carry any arena-allocated data (and are
+// copy...), just add them to this list.
+
+TrivialTypeTraversalImpls! {
+    (),
+    bool,
+    usize,
+    u16,
+    u32,
+    u64,
+    String,
+    crate::DebruijnIndex,
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Traversal implementations.
+
+impl<I: Interner, T: TypeFoldable<I>, U: TypeFoldable<I>> TypeFoldable<I> for (T, U) {
+    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<(T, U), F::Error> {
+        Ok((self.0.try_fold_with(folder)?, self.1.try_fold_with(folder)?))
+    }
+}
+
+impl<I: Interner, T: TypeVisitable<I>, U: TypeVisitable<I>> TypeVisitable<I> for (T, U) {
+    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        self.0.visit_with(visitor)?;
+        self.1.visit_with(visitor)
+    }
+}
+
+impl<I: Interner, A: TypeFoldable<I>, B: TypeFoldable<I>, C: TypeFoldable<I>> TypeFoldable<I>
+    for (A, B, C)
+{
+    fn try_fold_with<F: FallibleTypeFolder<I>>(
+        self,
+        folder: &mut F,
+    ) -> Result<(A, B, C), F::Error> {
+        Ok((
+            self.0.try_fold_with(folder)?,
+            self.1.try_fold_with(folder)?,
+            self.2.try_fold_with(folder)?,
+        ))
+    }
+}
+
+impl<I: Interner, A: TypeVisitable<I>, B: TypeVisitable<I>, C: TypeVisitable<I>> TypeVisitable<I>
+    for (A, B, C)
+{
+    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        self.0.visit_with(visitor)?;
+        self.1.visit_with(visitor)?;
+        self.2.visit_with(visitor)
+    }
+}
+
+EnumTypeTraversalImpl! {
+    impl<I, T> TypeFoldable<I> for Option<T> {
+        (Some)(a),
+        (None),
+    } where I: Interner, T: TypeFoldable<I>
+}
+EnumTypeTraversalImpl! {
+    impl<I, T> TypeVisitable<I> for Option<T> {
+        (Some)(a),
+        (None),
+    } where I: Interner, T: TypeVisitable<I>
+}
+
+EnumTypeTraversalImpl! {
+    impl<I, T, E> TypeFoldable<I> for Result<T, E> {
+        (Ok)(a),
+        (Err)(a),
+    } where I: Interner, T: TypeFoldable<I>, E: TypeFoldable<I>,
+}
+EnumTypeTraversalImpl! {
+    impl<I, T, E> TypeVisitable<I> for Result<T, E> {
+        (Ok)(a),
+        (Err)(a),
+    } where I: Interner, T: TypeVisitable<I>, E: TypeVisitable<I>,
+}
+
+impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Rc<T> {
+    fn try_fold_with<F: FallibleTypeFolder<I>>(mut self, folder: &mut F) -> Result<Self, F::Error> {
+        // We merely want to replace the contained `T`, if at all possible,
+        // so that we don't needlessly allocate a new `Rc` or indeed clone
+        // the contained type.
+        unsafe {
+            // First step is to ensure that we have a unique reference to
+            // the contained type, which `Rc::make_mut` will accomplish (by
+            // allocating a new `Rc` and cloning the `T` only if required).
+            // This is done *before* casting to `Rc<ManuallyDrop<T>>` so that
+            // panicking during `make_mut` does not leak the `T`.
+            Rc::make_mut(&mut self);
+
+            // Casting to `Rc<ManuallyDrop<T>>` is safe because `ManuallyDrop`
+            // is `repr(transparent)`.
+            let ptr = Rc::into_raw(self).cast::<ManuallyDrop<T>>();
+            let mut unique = Rc::from_raw(ptr);
+
+            // Call to `Rc::make_mut` above guarantees that `unique` is the
+            // sole reference to the contained value, so we can avoid doing
+            // a checked `get_mut` here.
+            let slot = Rc::get_mut_unchecked(&mut unique);
+
+            // Semantically move the contained type out from `unique`, fold
+            // it, then move the folded value back into `unique`. Should
+            // folding fail, `ManuallyDrop` ensures that the "moved-out"
+            // value is not re-dropped.
+            let owned = ManuallyDrop::take(slot);
+            let folded = owned.try_fold_with(folder)?;
+            *slot = ManuallyDrop::new(folded);
+
+            // Cast back to `Rc<T>`.
+            Ok(Rc::from_raw(Rc::into_raw(unique).cast()))
+        }
+    }
+}
+
+impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Rc<T> {
+    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        (**self).visit_with(visitor)
+    }
+}
+
+impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Arc<T> {
+    fn try_fold_with<F: FallibleTypeFolder<I>>(mut self, folder: &mut F) -> Result<Self, F::Error> {
+        // We merely want to replace the contained `T`, if at all possible,
+        // so that we don't needlessly allocate a new `Arc` or indeed clone
+        // the contained type.
+        unsafe {
+            // First step is to ensure that we have a unique reference to
+            // the contained type, which `Arc::make_mut` will accomplish (by
+            // allocating a new `Arc` and cloning the `T` only if required).
+            // This is done *before* casting to `Arc<ManuallyDrop<T>>` so that
+            // panicking during `make_mut` does not leak the `T`.
+            Arc::make_mut(&mut self);
+
+            // Casting to `Arc<ManuallyDrop<T>>` is safe because `ManuallyDrop`
+            // is `repr(transparent)`.
+            let ptr = Arc::into_raw(self).cast::<ManuallyDrop<T>>();
+            let mut unique = Arc::from_raw(ptr);
+
+            // Call to `Arc::make_mut` above guarantees that `unique` is the
+            // sole reference to the contained value, so we can avoid doing
+            // a checked `get_mut` here.
+            let slot = Arc::get_mut_unchecked(&mut unique);
+
+            // Semantically move the contained type out from `unique`, fold
+            // it, then move the folded value back into `unique`. Should
+            // folding fail, `ManuallyDrop` ensures that the "moved-out"
+            // value is not re-dropped.
+            let owned = ManuallyDrop::take(slot);
+            let folded = owned.try_fold_with(folder)?;
+            *slot = ManuallyDrop::new(folded);
+
+            // Cast back to `Arc<T>`.
+            Ok(Arc::from_raw(Arc::into_raw(unique).cast()))
+        }
+    }
+}
+
+impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Arc<T> {
+    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        (**self).visit_with(visitor)
+    }
+}
+
+impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Box<T> {
+    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        self.try_map_id(|value| value.try_fold_with(folder))
+    }
+}
+
+impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Box<T> {
+    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        (**self).visit_with(visitor)
+    }
+}
+
+impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Vec<T> {
+    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        self.try_map_id(|t| t.try_fold_with(folder))
+    }
+}
+
+impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Vec<T> {
+    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        self.iter().try_for_each(|t| t.visit_with(visitor))
+    }
+}
+
+impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for &[T] {
+    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        self.iter().try_for_each(|t| t.visit_with(visitor))
+    }
+}
+
+impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Box<[T]> {
+    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        self.try_map_id(|t| t.try_fold_with(folder))
+    }
+}
+
+impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Box<[T]> {
+    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        self.iter().try_for_each(|t| t.visit_with(visitor))
+    }
+}
+
+impl<I: Interner, T: TypeFoldable<I>, Ix: Idx> TypeFoldable<I> for IndexVec<Ix, T> {
+    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        self.try_map_id(|x| x.try_fold_with(folder))
+    }
+}
+
+impl<I: Interner, T: TypeVisitable<I>, Ix: Idx> TypeVisitable<I> for IndexVec<Ix, T> {
+    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        self.iter().try_for_each(|t| t.visit_with(visitor))
+    }
+}
diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs
new file mode 100644
index 00000000000..62239fd2006
--- /dev/null
+++ b/compiler/rustc_type_ir/src/visit.rs
@@ -0,0 +1,115 @@
+//! A visiting traversal mechanism for complex data structures that contain type
+//! information.
+//!
+//! This is a read-only traversal of the data structure.
+//!
+//! This traversal has limited flexibility. Only a small number of "types of
+//! interest" within the complex data structures can receive custom
+//! visitation. These are the ones containing the most important type-related
+//! information, such as `Ty`, `Predicate`, `Region`, and `Const`.
+//!
+//! There are three groups of traits involved in each traversal.
+//! - `TypeVisitable`. This is implemented once for many types, including:
+//!   - Types of interest, for which the methods delegate to the visitor.
+//!   - All other types, including generic containers like `Vec` and `Option`.
+//!     It defines a "skeleton" of how they should be visited.
+//! - `TypeSuperVisitable`. This is implemented only for each type of interest,
+//!   and defines the visiting "skeleton" for these types.
+//! - `TypeVisitor`. This is implemented for each visitor. This defines how
+//!   types of interest are visited.
+//!
+//! This means each visit is a mixture of (a) generic visiting operations, and (b)
+//! custom visit operations that are specific to the visitor.
+//! - The `TypeVisitable` impls handle most of the traversal, and call into
+//!   `TypeVisitor` when they encounter a type of interest.
+//! - A `TypeVisitor` may call into another `TypeVisitable` impl, because some of
+//!   the types of interest are recursive and can contain other types of interest.
+//! - A `TypeVisitor` may also call into a `TypeSuperVisitable` impl, because each
+//!   visitor might provide custom handling only for some types of interest, or
+//!   only for some variants of each type of interest, and then use default
+//!   traversal for the remaining cases.
+//!
+//! For example, if you have `struct S(Ty, U)` where `S: TypeVisitable` and `U:
+//! TypeVisitable`, and an instance `s = S(ty, u)`, it would be visited like so:
+//! ```text
+//! s.visit_with(visitor) calls
+//! - ty.visit_with(visitor) calls
+//!   - visitor.visit_ty(ty) may call
+//!     - ty.super_visit_with(visitor)
+//! - u.visit_with(visitor)
+//! ```
+use crate::Interner;
+
+use std::fmt;
+use std::ops::ControlFlow;
+
+/// This trait is implemented for every type that can be visited,
+/// providing the skeleton of the traversal.
+///
+/// To implement this conveniently, use the derive macro located in
+/// `rustc_macros`.
+pub trait TypeVisitable<I: Interner>: fmt::Debug + Clone {
+    /// The entry point for visiting. To visit a value `t` with a visitor `v`
+    /// call: `t.visit_with(v)`.
+    ///
+    /// For most types, this just traverses the value, calling `visit_with` on
+    /// each field/element.
+    ///
+    /// For types of interest (such as `Ty`), the implementation of this method
+    /// that calls a visitor method specifically for that type (such as
+    /// `V::visit_ty`). This is where control transfers from `TypeFoldable` to
+    /// `TypeVisitor`.
+    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
+}
+
+pub trait TypeSuperVisitable<I: Interner>: TypeVisitable<I> {
+    /// Provides a default visit for a type of interest. This should only be
+    /// called within `TypeVisitor` methods, when a non-custom traversal is
+    /// desired for the value of the type of interest passed to that method.
+    /// For example, in `MyVisitor::visit_ty(ty)`, it is valid to call
+    /// `ty.super_visit_with(self)`, but any other visiting should be done
+    /// with `xyz.visit_with(self)`.
+    fn super_visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
+}
+
+/// This trait is implemented for every visiting traversal. There is a visit
+/// method defined for every type of interest. Each such method has a default
+/// that recurses into the type's fields in a non-custom fashion.
+pub trait TypeVisitor<I: Interner>: Sized {
+    type BreakTy = !;
+
+    fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &I::Binder<T>) -> ControlFlow<Self::BreakTy>
+    where
+        I::Binder<T>: TypeSuperVisitable<I>,
+    {
+        t.super_visit_with(self)
+    }
+
+    fn visit_ty(&mut self, t: I::Ty) -> ControlFlow<Self::BreakTy>
+    where
+        I::Ty: TypeSuperVisitable<I>,
+    {
+        t.super_visit_with(self)
+    }
+
+    fn visit_region(&mut self, r: I::Region) -> ControlFlow<Self::BreakTy>
+    where
+        I::Region: TypeSuperVisitable<I>,
+    {
+        r.super_visit_with(self)
+    }
+
+    fn visit_const(&mut self, c: I::Const) -> ControlFlow<Self::BreakTy>
+    where
+        I::Const: TypeSuperVisitable<I>,
+    {
+        c.super_visit_with(self)
+    }
+
+    fn visit_predicate(&mut self, p: I::Predicate) -> ControlFlow<Self::BreakTy>
+    where
+        I::Predicate: TypeSuperVisitable<I>,
+    {
+        p.super_visit_with(self)
+    }
+}
diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs
index f1a784b5fd2..d2c597664fa 100644
--- a/library/std/src/sys/windows/fs.rs
+++ b/library/std/src/sys/windows/fs.rs
@@ -1266,7 +1266,12 @@ fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result<FileAttr> {
     // If the fallback fails for any reason we return the original error.
     match File::open(path, &opts) {
         Ok(file) => file.file_attr(),
-        Err(e) if e.raw_os_error() == Some(c::ERROR_SHARING_VIOLATION as _) => {
+        Err(e)
+            if [Some(c::ERROR_SHARING_VIOLATION as _), Some(c::ERROR_ACCESS_DENIED as _)]
+                .contains(&e.raw_os_error()) =>
+        {
+            // `ERROR_ACCESS_DENIED` is returned when the user doesn't have permission for the resource.
+            // One such example is `System Volume Information` as default but can be created as well
             // `ERROR_SHARING_VIOLATION` will almost never be returned.
             // Usually if a file is locked you can still read some metadata.
             // However, there are special system files, such as
diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs
index 6c9c26faef6..615794958d0 100644
--- a/src/bootstrap/format.rs
+++ b/src/bootstrap/format.rs
@@ -193,10 +193,46 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
     let (tx, rx): (SyncSender<PathBuf>, _) = std::sync::mpsc::sync_channel(128);
     let walker = match paths.get(0) {
         Some(first) => {
-            let mut walker = WalkBuilder::new(first);
+            let find_shortcut_candidates = |p: &PathBuf| {
+                let mut candidates = Vec::new();
+                for candidate in WalkBuilder::new(src.clone()).max_depth(Some(3)).build() {
+                    if let Ok(entry) = candidate {
+                        if let Some(dir_name) = p.file_name() {
+                            if entry.path().is_dir() && entry.file_name() == dir_name {
+                                candidates.push(entry.into_path());
+                            }
+                        }
+                    }
+                }
+                candidates
+            };
+
+            // Only try to look for shortcut candidates for single component paths like
+            // `std` and not for e.g. relative paths like `../library/std`.
+            let should_look_for_shortcut_dir = |p: &PathBuf| p.components().count() == 1;
+
+            let mut walker = if should_look_for_shortcut_dir(first) {
+                if let [single_candidate] = &find_shortcut_candidates(first)[..] {
+                    WalkBuilder::new(single_candidate)
+                } else {
+                    WalkBuilder::new(first)
+                }
+            } else {
+                WalkBuilder::new(first)
+            };
+
             for path in &paths[1..] {
-                walker.add(path);
+                if should_look_for_shortcut_dir(path) {
+                    if let [single_candidate] = &find_shortcut_candidates(path)[..] {
+                        walker.add(single_candidate);
+                    } else {
+                        walker.add(path);
+                    }
+                } else {
+                    walker.add(path);
+                }
             }
+
             walker
         }
         None => WalkBuilder::new(src.clone()),
diff --git a/src/doc/book b/src/doc/book
-Subproject f2a78f64b668f63f581203c6bac509903f7c00e
+Subproject d94e03a18a2590ed3f1c67b859cb11528d2a2d5
diff --git a/src/doc/embedded-book b/src/doc/embedded-book
-Subproject f1a4614aa41cc544b91b79760a709e113f3451d
+Subproject 701d1551429da4cb609082c0ac99df569e33671
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject bd1829d235296952bf72ca55635e360584b8805
+Subproject 79b53665a7c61d171fb8c5ad0b73b371f9ee6ba
diff --git a/src/doc/reference b/src/doc/reference
-Subproject 22882fb3f7b4d69fdc0d1731e8b9cfcb6910537
+Subproject e5adb99c04817b7fbe08f4ffce5b36702667345
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 134376872e8c387ef369507e0ee9b5a0e327271
+Subproject efe23c4fe12e06351b8dc8c3d18312c76145510
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject e359ee27fc3da3356d71a732128c0a1abe02e53
+Subproject 41a96ab971cb45e2a184df20619ad1829765c99
diff --git a/src/doc/style-guide/src/cargo.md b/src/doc/style-guide/src/cargo.md
index f4993ba06a8..13b96ca8c5e 100644
--- a/src/doc/style-guide/src/cargo.md
+++ b/src/doc/style-guide/src/cargo.md
@@ -17,8 +17,7 @@ followed by the `description` at the end of that section.
 Don't use quotes around any standard key names; use bare keys. Only use quoted
 keys for non-standard keys whose names require them, and avoid introducing such
 key names when possible.  See the [TOML
-specification](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md#table)
-for details.
+specification](https://toml.io/en/v1.0.0#keys) for details.
 
 Put a single space both before and after the `=` between a key and value. Do
 not indent any key names; start all key names at the start of a line.
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index a302750aa1a..6c15eac2c19 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -734,8 +734,8 @@ struct RegionReplacer<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
 }
 
-impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for RegionReplacer<'a, 'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 42bdbddbce6..bf3bbeb2dd1 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -20,7 +20,7 @@ use rustc_hir::PredicateOrigin;
 use rustc_hir_analysis::hir_ty_to_ty;
 use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
 use rustc_middle::middle::resolve_lifetime as rl;
-use rustc_middle::ty::fold::TypeFolder;
+use rustc_middle::ty::fold::ir::TypeFolder;
 use rustc_middle::ty::InternalSubsts;
 use rustc_middle::ty::TypeVisitable;
 use rustc_middle::ty::{self, AdtKind, DefIdTree, EarlyBinder, Ty, TyCtxt};
diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
index 5836eb73bd9..e9dc7351b58 100644
--- a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
@@ -4,7 +4,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_index::bit_set::{BitSet, HybridBitSet};
 use rustc_lint::LateContext;
 use rustc_middle::mir::{self, visit::Visitor as _, Mutability};
-use rustc_middle::ty::{self, visit::TypeVisitor};
+use rustc_middle::ty::{self, visit::ir::TypeVisitor, TyCtxt};
 use rustc_mir_dataflow::{impls::MaybeStorageLive, Analysis, ResultsCursor};
 use std::borrow::Cow;
 use std::ops::ControlFlow;
@@ -136,7 +136,7 @@ impl<'a, 'b, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'b,
 
 struct ContainsRegion;
 
-impl TypeVisitor<'_> for ContainsRegion {
+impl TypeVisitor<TyCtxt<'_>> for ContainsRegion {
     type BreakTy = ();
 
     fn visit_region(&mut self, _: ty::Region<'_>) -> ControlFlow<Self::BreakTy> {
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index c48d27b05f0..c785d89e280 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -17,7 +17,7 @@ use rustc_lint::LateContext;
 use rustc_middle::mir::interpret::{ConstValue, Scalar};
 use rustc_middle::ty::{
     self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, DefIdTree, FnSig, IntTy, List, ParamEnv, Predicate,
-    PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy,
+    PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, ir::TypeVisitor, UintTy,
     VariantDef, VariantDiscr,
 };
 use rustc_middle::ty::{GenericArg, GenericArgKind};
@@ -838,7 +838,7 @@ pub fn for_each_top_level_late_bound_region<B>(
         index: u32,
         f: F,
     }
-    impl<'tcx, B, F: FnMut(BoundRegion) -> ControlFlow<B>> TypeVisitor<'tcx> for V<F> {
+    impl<'tcx, B, F: FnMut(BoundRegion) -> ControlFlow<B>> TypeVisitor<TyCtxt<'tcx>> for V<F> {
         type BreakTy = B;
         fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<Self::BreakTy> {
             if let RegionKind::ReLateBound(idx, bound) = r.kind() && idx.as_u32() == self.index {
diff --git a/tests/mir-opt/copy-prop/mutate_through_pointer.rs b/tests/mir-opt/copy-prop/mutate_through_pointer.rs
index 609e49d6bc9..da142e33948 100644
--- a/tests/mir-opt/copy-prop/mutate_through_pointer.rs
+++ b/tests/mir-opt/copy-prop/mutate_through_pointer.rs
@@ -1,3 +1,13 @@
+// This attempts to mutate `a` via a pointer derived from `addr_of!(a)`. That is UB
+// according to Miri. However, the decision to make this UB - and to allow
+// rustc to rely on that fact for the purpose of optimizations - has not been
+// finalized.
+//
+// As such, we include this test to ensure that copy prop does not rely on that
+// fact. Specifically, if `addr_of!(a)` could not be used to modify a, it would
+// be correct for CopyProp to replace all occurrences of `a` with `c` - but that
+// would cause `f(true)` to output `false` instead of `true`.
+
 #![feature(custom_mir, core_intrinsics)]
 #![allow(unused_assignments)]
 extern crate core;
diff --git a/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.diff
index a91a755830d..004643e36f1 100644
--- a/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.diff
+++ b/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.diff
@@ -32,7 +32,7 @@
           _5 = _3;                         // scope 3 at $DIR/sibling_ptr.rs:+4:10: +4:11
           _4 = ptr::mut_ptr::<impl *mut u8>::add(move _5, const 1_usize) -> bb1; // scope 3 at $DIR/sibling_ptr.rs:+4:10: +4:18
                                            // mir::Constant
-                                           // + span: $DIR/sibling_ptr.rs:8:12: 8:15
+                                           // + span: $DIR/sibling_ptr.rs:15:12: 15:15
                                            // + literal: Const { ty: unsafe fn(*mut u8, usize) -> *mut u8 {ptr::mut_ptr::<impl *mut u8>::add}, val: Value(<ZST>) }
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/sibling_ptr.rs b/tests/mir-opt/dataflow-const-prop/sibling_ptr.rs
index 87ef00d1829..6dfb3a4ed30 100644
--- a/tests/mir-opt/dataflow-const-prop/sibling_ptr.rs
+++ b/tests/mir-opt/dataflow-const-prop/sibling_ptr.rs
@@ -1,3 +1,10 @@
+// This attempts to modify `x.1` via a pointer derived from `addr_of_mut!(x.0)`.
+// According to Miri, that is UB. However, T-opsem has not finalized that
+// decision and as such we cannot rely on it in optimizations. Consequently,
+// DataflowConstProp must treat the `addr_of_mut!(x.0)` as potentially being
+// used to modify `x.1` - if it did not, then it might incorrectly assume that it
+// can infer the value of `x.1` at the end of this function.
+
 // unit-test: DataflowConstProp
 
 // EMIT_MIR sibling_ptr.main.DataflowConstProp.diff
@@ -7,5 +14,5 @@ fn main() {
         let p = std::ptr::addr_of_mut!(x.0);
         *p.add(1) = 1;
     }
-    let x1 = x.1;  // should not be propagated
+    let x1 = x.1; // should not be propagated
 }
diff --git a/tests/mir-opt/sroa.escaping.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa.escaping.ScalarReplacementOfAggregates.diff
index ea7f5007224..fd691fdd153 100644
--- a/tests/mir-opt/sroa.escaping.ScalarReplacementOfAggregates.diff
+++ b/tests/mir-opt/sroa.escaping.ScalarReplacementOfAggregates.diff
@@ -3,42 +3,42 @@
   
   fn escaping() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/sroa.rs:+0:19: +0:19
-      let _1: ();                          // in scope 0 at $DIR/sroa.rs:+2:5: +2:42
-      let mut _2: *const u32;              // in scope 0 at $DIR/sroa.rs:+2:7: +2:41
-      let _3: &u32;                        // in scope 0 at $DIR/sroa.rs:+2:7: +2:41
-      let _4: Escaping;                    // in scope 0 at $DIR/sroa.rs:+2:8: +2:39
-      let mut _5: u32;                     // in scope 0 at $DIR/sroa.rs:+2:34: +2:37
+      let _1: ();                          // in scope 0 at $DIR/sroa.rs:+1:5: +1:42
+      let mut _2: *const u32;              // in scope 0 at $DIR/sroa.rs:+1:7: +1:41
+      let _3: &u32;                        // in scope 0 at $DIR/sroa.rs:+1:7: +1:41
+      let _4: Escaping;                    // in scope 0 at $DIR/sroa.rs:+1:8: +1:39
+      let mut _5: u32;                     // in scope 0 at $DIR/sroa.rs:+1:34: +1:37
   
       bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/sroa.rs:+2:5: +2:42
-          StorageLive(_2);                 // scope 0 at $DIR/sroa.rs:+2:7: +2:41
-          StorageLive(_3);                 // scope 0 at $DIR/sroa.rs:+2:7: +2:41
-          StorageLive(_4);                 // scope 0 at $DIR/sroa.rs:+2:8: +2:39
-          StorageLive(_5);                 // scope 0 at $DIR/sroa.rs:+2:34: +2:37
-          _5 = g() -> bb1;                 // scope 0 at $DIR/sroa.rs:+2:34: +2:37
+          StorageLive(_1);                 // scope 0 at $DIR/sroa.rs:+1:5: +1:42
+          StorageLive(_2);                 // scope 0 at $DIR/sroa.rs:+1:7: +1:41
+          StorageLive(_3);                 // scope 0 at $DIR/sroa.rs:+1:7: +1:41
+          StorageLive(_4);                 // scope 0 at $DIR/sroa.rs:+1:8: +1:39
+          StorageLive(_5);                 // scope 0 at $DIR/sroa.rs:+1:34: +1:37
+          _5 = g() -> bb1;                 // scope 0 at $DIR/sroa.rs:+1:34: +1:37
                                            // mir::Constant
-                                           // + span: $DIR/sroa.rs:73:34: 73:35
+                                           // + span: $DIR/sroa.rs:78:34: 78:35
                                            // + literal: Const { ty: fn() -> u32 {g}, val: Value(<ZST>) }
       }
   
       bb1: {
-          _4 = Escaping { a: const 1_u32, b: const 2_u32, c: move _5 }; // scope 0 at $DIR/sroa.rs:+2:8: +2:39
-          StorageDead(_5);                 // scope 0 at $DIR/sroa.rs:+2:38: +2:39
-          _3 = &(_4.0: u32);               // scope 0 at $DIR/sroa.rs:+2:7: +2:41
-          _2 = &raw const (*_3);           // scope 0 at $DIR/sroa.rs:+2:7: +2:41
-          _1 = f(move _2) -> bb2;          // scope 0 at $DIR/sroa.rs:+2:5: +2:42
+          _4 = Escaping { a: const 1_u32, b: const 2_u32, c: move _5 }; // scope 0 at $DIR/sroa.rs:+1:8: +1:39
+          StorageDead(_5);                 // scope 0 at $DIR/sroa.rs:+1:38: +1:39
+          _3 = &(_4.0: u32);               // scope 0 at $DIR/sroa.rs:+1:7: +1:41
+          _2 = &raw const (*_3);           // scope 0 at $DIR/sroa.rs:+1:7: +1:41
+          _1 = f(move _2) -> bb2;          // scope 0 at $DIR/sroa.rs:+1:5: +1:42
                                            // mir::Constant
-                                           // + span: $DIR/sroa.rs:73:5: 73:6
+                                           // + span: $DIR/sroa.rs:78:5: 78:6
                                            // + literal: Const { ty: fn(*const u32) {f}, val: Value(<ZST>) }
       }
   
       bb2: {
-          StorageDead(_2);                 // scope 0 at $DIR/sroa.rs:+2:41: +2:42
-          StorageDead(_4);                 // scope 0 at $DIR/sroa.rs:+2:42: +2:43
-          StorageDead(_3);                 // scope 0 at $DIR/sroa.rs:+2:42: +2:43
-          StorageDead(_1);                 // scope 0 at $DIR/sroa.rs:+2:42: +2:43
-          _0 = const ();                   // scope 0 at $DIR/sroa.rs:+0:19: +3:2
-          return;                          // scope 0 at $DIR/sroa.rs:+3:2: +3:2
+          StorageDead(_2);                 // scope 0 at $DIR/sroa.rs:+1:41: +1:42
+          StorageDead(_4);                 // scope 0 at $DIR/sroa.rs:+1:42: +1:43
+          StorageDead(_3);                 // scope 0 at $DIR/sroa.rs:+1:42: +1:43
+          StorageDead(_1);                 // scope 0 at $DIR/sroa.rs:+1:42: +1:43
+          _0 = const ();                   // scope 0 at $DIR/sroa.rs:+0:19: +2:2
+          return;                          // scope 0 at $DIR/sroa.rs:+2:2: +2:2
       }
   }
   
diff --git a/tests/mir-opt/sroa.rs b/tests/mir-opt/sroa.rs
index b69de2e124e..fff92cf8d9f 100644
--- a/tests/mir-opt/sroa.rs
+++ b/tests/mir-opt/sroa.rs
@@ -68,8 +68,13 @@ fn f(a: *const u32) {
     println!("{}", unsafe { *a.add(2) });
 }
 
+// `f` uses the `&e.a` to access `e.c`. This is UB according to Miri today; however,
+// T-opsem has not finalized that decision and as such rustc should not rely on
+// it. If SROA were to rely on it, it would be (almost) correct to turn `e` into
+// three distinct locals - one for each field - and pass a reference to only one
+// of them to `f`. However, this would lead to a miscompilation because `b` and `c`
+// might no longer appear right after `a` in memory.
 pub fn escaping() {
-    // Verify this struct is not flattened.
     f(&Escaping { a: 1, b: 2, c: g() }.a);
 }
 
diff --git a/tests/ui/async-await/dont-suggest-missing-await.stderr b/tests/ui/async-await/dont-suggest-missing-await.stderr
index 8e2d42c8f13..1fa4e5db0cb 100644
--- a/tests/ui/async-await/dont-suggest-missing-await.stderr
+++ b/tests/ui/async-await/dont-suggest-missing-await.stderr
@@ -2,12 +2,15 @@ error[E0308]: mismatched types
   --> $DIR/dont-suggest-missing-await.rs:14:18
    |
 LL |         take_u32(x)
-   |         -------- ^ expected `u32`, found opaque type
+   |         -------- ^ expected `u32`, found future
    |         |
    |         arguments to this function are incorrect
    |
-   = note:     expected type `u32`
-           found opaque type `impl Future<Output = u32>`
+note: calling an async function returns a future
+  --> $DIR/dont-suggest-missing-await.rs:14:18
+   |
+LL |         take_u32(x)
+   |                  ^
 note: function defined here
   --> $DIR/dont-suggest-missing-await.rs:5:4
    |
diff --git a/tests/ui/async-await/generator-desc.stderr b/tests/ui/async-await/generator-desc.stderr
index 9fdb1ce47d7..51ac9d86bfb 100644
--- a/tests/ui/async-await/generator-desc.stderr
+++ b/tests/ui/async-await/generator-desc.stderr
@@ -17,12 +17,10 @@ error[E0308]: mismatched types
   --> $DIR/generator-desc.rs:12:16
    |
 LL |     fun(one(), two());
-   |     ---        ^^^^^ expected opaque type, found a different opaque type
+   |     ---        ^^^^^ expected future, found a different future
    |     |
    |     arguments to this function are incorrect
    |
-   = note: expected opaque type `impl Future<Output = ()>` (opaque type at <$DIR/generator-desc.rs:5:16>)
-              found opaque type `impl Future<Output = ()>` (opaque type at <$DIR/generator-desc.rs:6:16>)
    = help: consider `await`ing on both `Future`s
    = note: distinct uses of `impl Trait` result in different opaque types
 note: function defined here
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr
index 3c01fca2f4d..168ef8e9ee4 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr
+++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr
@@ -2,7 +2,7 @@ error[E0053]: method `foo` has an incompatible type for trait
   --> $DIR/async-example-desugared-boxed-in-trait.rs:15:28
    |
 LL |     async fn foo(&self) -> i32 {
-   |                            ^^^ expected `Pin<Box<dyn Future<Output = i32>>>`, found opaque type
+   |                            ^^^ expected `Pin<Box<dyn Future<Output = i32>>>`, found future
    |
 note: type in trait
   --> $DIR/async-example-desugared-boxed-in-trait.rs:11:22
diff --git a/tests/ui/async-await/issue-61076.rs b/tests/ui/async-await/issue-61076.rs
index 9c4acbe0a5b..cf6e5b4e436 100644
--- a/tests/ui/async-await/issue-61076.rs
+++ b/tests/ui/async-await/issue-61076.rs
@@ -86,7 +86,7 @@ async fn match_() {
     match tuple() { //~ HELP consider `await`ing on the `Future`
         //~^ NOTE this expression has type `impl Future<Output = Tuple>`
         Tuple(_) => {} //~ ERROR mismatched types
-        //~^ NOTE expected opaque type, found `Tuple`
+        //~^ NOTE expected future, found `Tuple`
         //~| NOTE expected opaque type `impl Future<Output = Tuple>`
     }
 }
diff --git a/tests/ui/async-await/issue-61076.stderr b/tests/ui/async-await/issue-61076.stderr
index b25b29bf50c..44de282988b 100644
--- a/tests/ui/async-await/issue-61076.stderr
+++ b/tests/ui/async-await/issue-61076.stderr
@@ -62,7 +62,7 @@ LL |     match tuple() {
    |           ------- this expression has type `impl Future<Output = Tuple>`
 LL |
 LL |         Tuple(_) => {}
-   |         ^^^^^^^^ expected opaque type, found `Tuple`
+   |         ^^^^^^^^ expected future, found `Tuple`
    |
    = note: expected opaque type `impl Future<Output = Tuple>`
                    found struct `Tuple`
diff --git a/tests/ui/async-await/issue-98634.stderr b/tests/ui/async-await/issue-98634.stderr
index 4c5dfeed9ba..5b7f18a98b5 100644
--- a/tests/ui/async-await/issue-98634.stderr
+++ b/tests/ui/async-await/issue-98634.stderr
@@ -2,10 +2,8 @@ error[E0271]: expected `callback` to be a fn item that returns `Pin<Box<dyn Futu
   --> $DIR/issue-98634.rs:45:23
    |
 LL |         StructAsync { callback }.await;
-   |                       ^^^^^^^^ expected `Pin<Box<dyn Future<Output = ()>>>`, found opaque type
+   |                       ^^^^^^^^ expected `Pin<Box<dyn Future<Output = ()>>>`, found future
    |
-   = note:   expected struct `Pin<Box<(dyn Future<Output = ()> + 'static)>>`
-           found opaque type `impl Future<Output = ()>`
 note: required by a bound in `StructAsync`
   --> $DIR/issue-98634.rs:9:35
    |
@@ -16,10 +14,8 @@ error[E0271]: expected `callback` to be a fn item that returns `Pin<Box<dyn Futu
   --> $DIR/issue-98634.rs:45:9
    |
 LL |         StructAsync { callback }.await;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<Box<dyn Future<Output = ()>>>`, found opaque type
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<Box<dyn Future<Output = ()>>>`, found future
    |
-   = note:   expected struct `Pin<Box<(dyn Future<Output = ()> + 'static)>>`
-           found opaque type `impl Future<Output = ()>`
 note: required by a bound in `StructAsync`
   --> $DIR/issue-98634.rs:9:35
    |
@@ -30,10 +26,8 @@ error[E0271]: expected `callback` to be a fn item that returns `Pin<Box<dyn Futu
   --> $DIR/issue-98634.rs:45:33
    |
 LL |         StructAsync { callback }.await;
-   |                                 ^^^^^^ expected `Pin<Box<dyn Future<Output = ()>>>`, found opaque type
+   |                                 ^^^^^^ expected `Pin<Box<dyn Future<Output = ()>>>`, found future
    |
-   = note:   expected struct `Pin<Box<(dyn Future<Output = ()> + 'static)>>`
-           found opaque type `impl Future<Output = ()>`
 note: required by a bound in `StructAsync`
   --> $DIR/issue-98634.rs:9:35
    |
diff --git a/tests/ui/async-await/issues/issue-102206.stderr b/tests/ui/async-await/issues/issue-102206.stderr
index ebb80f6e07e..750b7a886ef 100644
--- a/tests/ui/async-await/issues/issue-102206.stderr
+++ b/tests/ui/async-await/issues/issue-102206.stderr
@@ -4,12 +4,10 @@ error[E0308]: mismatched types
 LL |     std::mem::size_of_val(foo());
    |     --------------------- ^^^^^
    |     |                     |
-   |     |                     expected `&_`, found opaque type
+   |     |                     expected `&_`, found future
    |     |                     help: consider borrowing here: `&foo()`
    |     arguments to this function are incorrect
    |
-   = note: expected reference `&_`
-            found opaque type `impl Future<Output = ()>`
 note: function defined here
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
 
diff --git a/tests/ui/async-await/suggest-missing-await-closure.stderr b/tests/ui/async-await/suggest-missing-await-closure.stderr
index e47325cb4ae..d44af5b8dd8 100644
--- a/tests/ui/async-await/suggest-missing-await-closure.stderr
+++ b/tests/ui/async-await/suggest-missing-await-closure.stderr
@@ -2,12 +2,15 @@ error[E0308]: mismatched types
   --> $DIR/suggest-missing-await-closure.rs:16:18
    |
 LL |         take_u32(x)
-   |         -------- ^ expected `u32`, found opaque type
+   |         -------- ^ expected `u32`, found future
    |         |
    |         arguments to this function are incorrect
    |
-   = note:     expected type `u32`
-           found opaque type `impl Future<Output = u32>`
+note: calling an async function returns a future
+  --> $DIR/suggest-missing-await-closure.rs:16:18
+   |
+LL |         take_u32(x)
+   |                  ^
 note: function defined here
   --> $DIR/suggest-missing-await-closure.rs:6:4
    |
diff --git a/tests/ui/async-await/suggest-missing-await.stderr b/tests/ui/async-await/suggest-missing-await.stderr
index 4ed0272ac1a..f0ec34a6a55 100644
--- a/tests/ui/async-await/suggest-missing-await.stderr
+++ b/tests/ui/async-await/suggest-missing-await.stderr
@@ -2,12 +2,15 @@ error[E0308]: mismatched types
   --> $DIR/suggest-missing-await.rs:12:14
    |
 LL |     take_u32(x)
-   |     -------- ^ expected `u32`, found opaque type
+   |     -------- ^ expected `u32`, found future
    |     |
    |     arguments to this function are incorrect
    |
-   = note:     expected type `u32`
-           found opaque type `impl Future<Output = u32>`
+note: calling an async function returns a future
+  --> $DIR/suggest-missing-await.rs:12:14
+   |
+LL |     take_u32(x)
+   |              ^
 note: function defined here
   --> $DIR/suggest-missing-await.rs:3:4
    |
@@ -22,10 +25,13 @@ error[E0308]: mismatched types
   --> $DIR/suggest-missing-await.rs:22:5
    |
 LL |     dummy()
-   |     ^^^^^^^ expected `()`, found opaque type
+   |     ^^^^^^^ expected `()`, found future
    |
-   = note: expected unit type `()`
-            found opaque type `impl Future<Output = ()>`
+note: calling an async function returns a future
+  --> $DIR/suggest-missing-await.rs:22:5
+   |
+LL |     dummy()
+   |     ^^^^^^^
 help: consider `await`ing on the `Future`
    |
 LL |     dummy().await
@@ -45,7 +51,7 @@ LL | |         dummy()
 LL | |
 LL | |     } else {
 LL | |         dummy().await
-   | |         ^^^^^^^^^^^^^ expected opaque type, found `()`
+   | |         ^^^^^^^^^^^^^ expected future, found `()`
 LL | |
 LL | |     };
    | |_____- `if` and `else` have incompatible types
@@ -67,7 +73,7 @@ LL | |         0 => dummy(),
 LL | |         1 => dummy(),
    | |              ------- this is found to be of type `impl Future<Output = ()>`
 LL | |         2 => dummy().await,
-   | |              ^^^^^^^^^^^^^ expected opaque type, found `()`
+   | |              ^^^^^^^^^^^^^ expected future, found `()`
 LL | |
 LL | |     };
    | |_____- `match` arms have incompatible types
@@ -86,7 +92,7 @@ error[E0308]: mismatched types
 LL |     let _x = match dummy() {
    |                    ------- this expression has type `impl Future<Output = ()>`
 LL |         () => {}
-   |         ^^ expected opaque type, found `()`
+   |         ^^ expected future, found `()`
    |
    = note: expected opaque type `impl Future<Output = ()>`
                 found unit type `()`
@@ -102,7 +108,7 @@ LL |     match dummy_result() {
    |           -------------- this expression has type `impl Future<Output = Result<(), ()>>`
 ...
 LL |         Ok(_) => {}
-   |         ^^^^^ expected opaque type, found `Result<_, _>`
+   |         ^^^^^ expected future, found `Result<_, _>`
    |
    = note: expected opaque type `impl Future<Output = Result<(), ()>>`
                      found enum `Result<_, _>`
@@ -118,7 +124,7 @@ LL |     match dummy_result() {
    |           -------------- this expression has type `impl Future<Output = Result<(), ()>>`
 ...
 LL |         Err(_) => {}
-   |         ^^^^^^ expected opaque type, found `Result<_, _>`
+   |         ^^^^^^ expected future, found `Result<_, _>`
    |
    = note: expected opaque type `impl Future<Output = Result<(), ()>>`
                      found enum `Result<_, _>`
diff --git a/tests/ui/coherence/issue-85026.stderr b/tests/ui/coherence/issue-85026.stderr
index a5da19bbfaa..fb6e9976583 100644
--- a/tests/ui/coherence/issue-85026.stderr
+++ b/tests/ui/coherence/issue-85026.stderr
@@ -1,16 +1,16 @@
 error[E0785]: cannot define inherent `impl` for a dyn auto trait
-  --> $DIR/issue-85026.rs:5:6
+  --> $DIR/issue-85026.rs:5:1
    |
 LL | impl dyn AutoTrait {}
-   |      ^^^^^^^^^^^^^ impl requires at least one non-auto trait
+   | ^^^^^^^^^^^^^^^^^^ impl requires at least one non-auto trait
    |
    = note: define and implement a new trait or type instead
 
 error[E0785]: cannot define inherent `impl` for a dyn auto trait
-  --> $DIR/issue-85026.rs:8:6
+  --> $DIR/issue-85026.rs:8:1
    |
 LL | impl dyn Unpin {}
-   |      ^^^^^^^^^ impl requires at least one non-auto trait
+   | ^^^^^^^^^^^^^^ impl requires at least one non-auto trait
    |
    = note: define and implement a new trait or type instead
 
diff --git a/tests/ui/const-generics/wrong-normalization.stderr b/tests/ui/const-generics/wrong-normalization.stderr
index fb806bdb1e7..658a8406608 100644
--- a/tests/ui/const-generics/wrong-normalization.stderr
+++ b/tests/ui/const-generics/wrong-normalization.stderr
@@ -1,8 +1,8 @@
 error[E0118]: no nominal type found for inherent implementation
-  --> $DIR/wrong-normalization.rs:16:6
+  --> $DIR/wrong-normalization.rs:16:1
    |
 LL | impl <I8<{i8::MIN}> as Identity>::Identity {
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl requires a nominal type
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl requires a nominal type
    |
    = note: either implement a trait on it or create a newtype to wrap it instead
 
diff --git a/tests/ui/error-codes/E0116.stderr b/tests/ui/error-codes/E0116.stderr
index a5ceeb4a55d..8a027686760 100644
--- a/tests/ui/error-codes/E0116.stderr
+++ b/tests/ui/error-codes/E0116.stderr
@@ -2,7 +2,7 @@ error[E0116]: cannot define inherent `impl` for a type outside of the crate wher
   --> $DIR/E0116.rs:1:1
    |
 LL | impl Vec<u8> {}
-   | ^^^^^^^^^^^^^^^ impl for type defined outside of crate.
+   | ^^^^^^^^^^^^ impl for type defined outside of crate.
    |
    = note: define and implement a trait or new type instead
 
diff --git a/tests/ui/error-codes/E0118.stderr b/tests/ui/error-codes/E0118.stderr
index 8c6fa7947a8..442f8a4f870 100644
--- a/tests/ui/error-codes/E0118.stderr
+++ b/tests/ui/error-codes/E0118.stderr
@@ -1,8 +1,8 @@
 error[E0118]: no nominal type found for inherent implementation
-  --> $DIR/E0118.rs:1:9
+  --> $DIR/E0118.rs:1:1
    |
 LL | impl<T> T {
-   |         ^ impl requires a nominal type
+   | ^^^^^^^^^ impl requires a nominal type
    |
    = note: either implement a trait on it or create a newtype to wrap it instead
 
diff --git a/tests/ui/error-codes/E0390.stderr b/tests/ui/error-codes/E0390.stderr
index 0e5a9ca762b..ec4b5758c5b 100644
--- a/tests/ui/error-codes/E0390.stderr
+++ b/tests/ui/error-codes/E0390.stderr
@@ -1,16 +1,16 @@
 error[E0390]: cannot define inherent `impl` for primitive types
-  --> $DIR/E0390.rs:5:6
+  --> $DIR/E0390.rs:5:1
    |
 LL | impl *mut Foo {}
-   |      ^^^^^^^^
+   | ^^^^^^^^^^^^^
    |
    = help: consider using an extension trait instead
 
 error[E0390]: cannot define inherent `impl` for primitive types
-  --> $DIR/E0390.rs:7:6
+  --> $DIR/E0390.rs:7:1
    |
 LL | impl fn(Foo) {}
-   |      ^^^^^^^
+   | ^^^^^^^^^^^^
    |
    = help: consider using an extension trait instead
 
diff --git a/tests/ui/impl-trait/issue-102605.stderr b/tests/ui/impl-trait/issue-102605.stderr
index 8ff08968008..dfe18e43eee 100644
--- a/tests/ui/impl-trait/issue-102605.stderr
+++ b/tests/ui/impl-trait/issue-102605.stderr
@@ -2,12 +2,15 @@ error[E0308]: mismatched types
   --> $DIR/issue-102605.rs:13:20
    |
 LL |     convert_result(foo())
-   |     -------------- ^^^^^ expected `Result<(), _>`, found opaque type
+   |     -------------- ^^^^^ expected `Result<(), _>`, found future
    |     |
    |     arguments to this function are incorrect
    |
-   = note:     expected enum `Result<(), _>`
-           found opaque type `impl Future<Output = Result<(), String>>`
+note: calling an async function returns a future
+  --> $DIR/issue-102605.rs:13:20
+   |
+LL |     convert_result(foo())
+   |                    ^^^^^
 note: function defined here
   --> $DIR/issue-102605.rs:7:4
    |
diff --git a/tests/ui/impl-trait/issue-99914.stderr b/tests/ui/impl-trait/issue-99914.stderr
index a4b7fc1f5bc..c86e9eadc87 100644
--- a/tests/ui/impl-trait/issue-99914.stderr
+++ b/tests/ui/impl-trait/issue-99914.stderr
@@ -2,10 +2,8 @@ error[E0308]: mismatched types
   --> $DIR/issue-99914.rs:9:27
    |
 LL |     t.and_then(|t| -> _ { bar(t) });
-   |                           ^^^^^^ expected `Result<_, Error>`, found opaque type
+   |                           ^^^^^^ expected `Result<_, Error>`, found future
    |
-   = note:     expected enum `Result<_, Error>`
-           found opaque type `impl Future<Output = ()>`
 help: try wrapping the expression in `Ok`
    |
 LL |     t.and_then(|t| -> _ { Ok(bar(t)) });
diff --git a/tests/ui/impl-trait/normalize-tait-in-const.stderr b/tests/ui/impl-trait/normalize-tait-in-const.stderr
index b9fc8726ffc..99eed29207b 100644
--- a/tests/ui/impl-trait/normalize-tait-in-const.stderr
+++ b/tests/ui/impl-trait/normalize-tait-in-const.stderr
@@ -1,4 +1,4 @@
-error: internal compiler error: compiler/rustc_middle/src/ty/normalize_erasing_regions.rs:198:90: Failed to normalize <for<'a, 'b> fn(&'a Alias<'b>) {foo} as std::ops::FnOnce<(&&S,)>>::Output, maybe try to call `try_normalize_erasing_regions` instead
+error: internal compiler error: compiler/rustc_middle/src/ty/normalize_erasing_regions.rs:201:90: Failed to normalize <for<'a, 'b> fn(&'a Alias<'b>) {foo} as std::ops::FnOnce<(&&S,)>>::Output, maybe try to call `try_normalize_erasing_regions` instead
 
 query stack during panic:
 #0 [eval_to_allocation_raw] const-evaluating + checking `BAR`
diff --git a/tests/ui/impl-trait/where-allowed.stderr b/tests/ui/impl-trait/where-allowed.stderr
index 3ad0a9f9d5c..e3a9caa6460 100644
--- a/tests/ui/impl-trait/where-allowed.stderr
+++ b/tests/ui/impl-trait/where-allowed.stderr
@@ -303,10 +303,10 @@ LL | fn in_method_generic_param_default<T = impl Debug>(_: T) {}
    = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
 
 error[E0118]: no nominal type found for inherent implementation
-  --> $DIR/where-allowed.rs:233:23
+  --> $DIR/where-allowed.rs:233:1
    |
 LL | impl <T = impl Debug> T {}
-   |                       ^ impl requires a nominal type
+   | ^^^^^^^^^^^^^^^^^^^^^^^ impl requires a nominal type
    |
    = note: either implement a trait on it or create a newtype to wrap it instead
 
diff --git a/tests/ui/incoherent-inherent-impls/needs-has-incoherent-impls.stderr b/tests/ui/incoherent-inherent-impls/needs-has-incoherent-impls.stderr
index 8f70825115d..f5900afe2dc 100644
--- a/tests/ui/incoherent-inherent-impls/needs-has-incoherent-impls.stderr
+++ b/tests/ui/incoherent-inherent-impls/needs-has-incoherent-impls.stderr
@@ -1,114 +1,80 @@
 error[E0390]: cannot define inherent `impl` for a type outside of the crate where the type is defined
   --> $DIR/needs-has-incoherent-impls.rs:5:1
    |
-LL | / impl extern_crate::StructWithAttr {
-LL | |
-LL | |     fn foo() {}
-LL | | }
-   | |_^
+LL | impl extern_crate::StructWithAttr {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider moving this inherent impl into the crate defining the type if possible
 help: alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items
   --> $DIR/needs-has-incoherent-impls.rs:7:5
    |
 LL |     fn foo() {}
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^
 
 error[E0390]: cannot define inherent `impl` for a type outside of the crate where the type is defined
   --> $DIR/needs-has-incoherent-impls.rs:13:1
    |
-LL | / impl extern_crate::StructNoAttr {
-LL | |
-LL | |     fn foo() {}
-LL | | }
-   | |_^
+LL | impl extern_crate::StructNoAttr {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider moving this inherent impl into the crate defining the type if possible
 help: alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type and `#[rustc_allow_incoherent_impl]` to the relevant impl items
   --> $DIR/needs-has-incoherent-impls.rs:13:1
    |
-LL | / impl extern_crate::StructNoAttr {
-LL | |
-LL | |     fn foo() {}
-LL | | }
-   | |_^
+LL | impl extern_crate::StructNoAttr {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0390]: cannot define inherent `impl` for a type outside of the crate where the type is defined
   --> $DIR/needs-has-incoherent-impls.rs:17:1
    |
-LL | / impl extern_crate::StructNoAttr {
-LL | |
-LL | |     #[rustc_allow_incoherent_impl]
-LL | |     fn bar() {}
-LL | | }
-   | |_^
+LL | impl extern_crate::StructNoAttr {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider moving this inherent impl into the crate defining the type if possible
 help: alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type and `#[rustc_allow_incoherent_impl]` to the relevant impl items
   --> $DIR/needs-has-incoherent-impls.rs:17:1
    |
-LL | / impl extern_crate::StructNoAttr {
-LL | |
-LL | |     #[rustc_allow_incoherent_impl]
-LL | |     fn bar() {}
-LL | | }
-   | |_^
+LL | impl extern_crate::StructNoAttr {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0390]: cannot define inherent `impl` for a type outside of the crate where the type is defined
   --> $DIR/needs-has-incoherent-impls.rs:22:1
    |
-LL | / impl extern_crate::EnumWithAttr {
-LL | |
-LL | |     fn foo() {}
-LL | | }
-   | |_^
+LL | impl extern_crate::EnumWithAttr {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider moving this inherent impl into the crate defining the type if possible
 help: alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items
   --> $DIR/needs-has-incoherent-impls.rs:24:5
    |
 LL |     fn foo() {}
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^
 
 error[E0390]: cannot define inherent `impl` for a type outside of the crate where the type is defined
   --> $DIR/needs-has-incoherent-impls.rs:30:1
    |
-LL | / impl extern_crate::EnumNoAttr {
-LL | |
-LL | |     fn foo() {}
-LL | | }
-   | |_^
+LL | impl extern_crate::EnumNoAttr {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider moving this inherent impl into the crate defining the type if possible
 help: alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type and `#[rustc_allow_incoherent_impl]` to the relevant impl items
   --> $DIR/needs-has-incoherent-impls.rs:30:1
    |
-LL | / impl extern_crate::EnumNoAttr {
-LL | |
-LL | |     fn foo() {}
-LL | | }
-   | |_^
+LL | impl extern_crate::EnumNoAttr {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0390]: cannot define inherent `impl` for a type outside of the crate where the type is defined
   --> $DIR/needs-has-incoherent-impls.rs:34:1
    |
-LL | / impl extern_crate::EnumNoAttr {
-LL | |
-LL | |     #[rustc_allow_incoherent_impl]
-LL | |     fn bar() {}
-LL | | }
-   | |_^
+LL | impl extern_crate::EnumNoAttr {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider moving this inherent impl into the crate defining the type if possible
 help: alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type and `#[rustc_allow_incoherent_impl]` to the relevant impl items
   --> $DIR/needs-has-incoherent-impls.rs:34:1
    |
-LL | / impl extern_crate::EnumNoAttr {
-LL | |
-LL | |     #[rustc_allow_incoherent_impl]
-LL | |     fn bar() {}
-LL | | }
-   | |_^
+LL | impl extern_crate::EnumNoAttr {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/incoherent-inherent-impls/no-attr-empty-impl.stderr b/tests/ui/incoherent-inherent-impls/no-attr-empty-impl.stderr
index b3f8b51d0ea..6dc1680cf89 100644
--- a/tests/ui/incoherent-inherent-impls/no-attr-empty-impl.stderr
+++ b/tests/ui/incoherent-inherent-impls/no-attr-empty-impl.stderr
@@ -2,7 +2,7 @@ error[E0116]: cannot define inherent `impl` for a type outside of the crate wher
   --> $DIR/no-attr-empty-impl.rs:4:1
    |
 LL | impl extern_crate::StructWithAttr {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate.
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate.
    |
    = note: define and implement a trait or new type instead
 
@@ -10,7 +10,7 @@ error[E0116]: cannot define inherent `impl` for a type outside of the crate wher
   --> $DIR/no-attr-empty-impl.rs:7:1
    |
 LL | impl extern_crate::StructNoAttr {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate.
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate.
    |
    = note: define and implement a trait or new type instead
 
@@ -18,7 +18,7 @@ error[E0116]: cannot define inherent `impl` for a type outside of the crate wher
   --> $DIR/no-attr-empty-impl.rs:10:1
    |
 LL | impl extern_crate::EnumWithAttr {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate.
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate.
    |
    = note: define and implement a trait or new type instead
 
@@ -26,15 +26,15 @@ error[E0116]: cannot define inherent `impl` for a type outside of the crate wher
   --> $DIR/no-attr-empty-impl.rs:13:1
    |
 LL | impl extern_crate::EnumNoAttr {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate.
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate.
    |
    = note: define and implement a trait or new type instead
 
 error[E0390]: cannot define inherent `impl` for primitive types
-  --> $DIR/no-attr-empty-impl.rs:16:6
+  --> $DIR/no-attr-empty-impl.rs:16:1
    |
 LL | impl f32 {}
-   |      ^^^
+   | ^^^^^^^^
    |
    = help: consider using an extension trait instead
 
diff --git a/tests/ui/kinds-of-primitive-impl.stderr b/tests/ui/kinds-of-primitive-impl.stderr
index f4dbd1c40e8..21aac58f1f2 100644
--- a/tests/ui/kinds-of-primitive-impl.stderr
+++ b/tests/ui/kinds-of-primitive-impl.stderr
@@ -1,32 +1,32 @@
 error[E0390]: cannot define inherent `impl` for primitive types
-  --> $DIR/kinds-of-primitive-impl.rs:1:6
+  --> $DIR/kinds-of-primitive-impl.rs:1:1
    |
 LL | impl u8 {
-   |      ^^
+   | ^^^^^^^
    |
    = help: consider using an extension trait instead
 
 error[E0390]: cannot define inherent `impl` for primitive types
-  --> $DIR/kinds-of-primitive-impl.rs:6:6
+  --> $DIR/kinds-of-primitive-impl.rs:6:1
    |
 LL | impl str {
-   |      ^^^
+   | ^^^^^^^^
    |
    = help: consider using an extension trait instead
 
 error[E0390]: cannot define inherent `impl` for primitive types
-  --> $DIR/kinds-of-primitive-impl.rs:12:6
+  --> $DIR/kinds-of-primitive-impl.rs:12:1
    |
 LL | impl char {
-   |      ^^^^
+   | ^^^^^^^^^
    |
    = help: consider using an extension trait instead
 
 error[E0390]: cannot define inherent `impl` for primitive types
-  --> $DIR/kinds-of-primitive-impl.rs:21:6
+  --> $DIR/kinds-of-primitive-impl.rs:21:1
    |
 LL | impl &MyType {
-   |      ^^^^^^^
+   | ^^^^^^^^^^^^
    |
    = help: consider using an extension trait instead
    = note: you could also try moving the reference to uses of `MyType` (such as `self`) within the implementation
diff --git a/tests/ui/privacy/private-in-public-ill-formed.stderr b/tests/ui/privacy/private-in-public-ill-formed.stderr
index e7c94bc301b..abc8538e5b3 100644
--- a/tests/ui/privacy/private-in-public-ill-formed.stderr
+++ b/tests/ui/privacy/private-in-public-ill-formed.stderr
@@ -1,16 +1,16 @@
 error[E0118]: no nominal type found for inherent implementation
-  --> $DIR/private-in-public-ill-formed.rs:14:10
+  --> $DIR/private-in-public-ill-formed.rs:14:5
    |
 LL |     impl <Priv as PrivTr>::AssocAlias {
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl requires a nominal type
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl requires a nominal type
    |
    = note: either implement a trait on it or create a newtype to wrap it instead
 
 error[E0118]: no nominal type found for inherent implementation
-  --> $DIR/private-in-public-ill-formed.rs:31:10
+  --> $DIR/private-in-public-ill-formed.rs:31:5
    |
 LL |     impl <Priv as PrivTr>::AssocAlias {
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl requires a nominal type
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl requires a nominal type
    |
    = note: either implement a trait on it or create a newtype to wrap it instead
 
diff --git a/tests/ui/suggestions/if-then-neeing-semi.rs b/tests/ui/suggestions/if-then-neeing-semi.rs
index 7be4312bfba..a4eefb41508 100644
--- a/tests/ui/suggestions/if-then-neeing-semi.rs
+++ b/tests/ui/suggestions/if-then-neeing-semi.rs
@@ -26,8 +26,8 @@ async fn async_extra_semicolon_same() {
         //~^ HELP consider removing this semicolon
     } else {
         async_dummy() //~ ERROR `if` and `else` have incompatible types
-        //~^ NOTE expected `()`, found opaque type
-        //~| NOTE expected unit type `()`
+        //~^ NOTE expected `()`, found future
+        //~| NOTE calling an async function returns a future
         //~| HELP consider `await`ing on the `Future`
     };
 }
@@ -39,8 +39,8 @@ async fn async_extra_semicolon_different() {
         //~^ HELP consider removing this semicolon
     } else {
         async_dummy2() //~ ERROR `if` and `else` have incompatible types
-        //~^ NOTE expected `()`, found opaque type
-        //~| NOTE expected unit type `()`
+        //~^ NOTE expected `()`, found future
+        //~| NOTE calling an async function returns a future
         //~| HELP consider `await`ing on the `Future`
     };
 }
@@ -52,8 +52,7 @@ async fn async_different_futures() {
         //~| HELP consider `await`ing on both `Future`s
     } else {
         async_dummy2() //~ ERROR `if` and `else` have incompatible types
-        //~^ NOTE expected opaque type, found a different opaque type
-        //~| NOTE expected opaque type `impl Future<Output = ()>`
+        //~^ NOTE expected future, found a different future
         //~| NOTE distinct uses of `impl Trait` result in different opaque types
     };
 }
diff --git a/tests/ui/suggestions/if-then-neeing-semi.stderr b/tests/ui/suggestions/if-then-neeing-semi.stderr
index 567deb405fc..6833e0bab2b 100644
--- a/tests/ui/suggestions/if-then-neeing-semi.stderr
+++ b/tests/ui/suggestions/if-then-neeing-semi.stderr
@@ -9,14 +9,17 @@ LL | |         async_dummy();
 LL | |
 LL | |     } else {
 LL | |         async_dummy()
-   | |         ^^^^^^^^^^^^^ expected `()`, found opaque type
+   | |         ^^^^^^^^^^^^^ expected `()`, found future
 ...  |
 LL | |
 LL | |     };
    | |_____- `if` and `else` have incompatible types
    |
-   = note: expected unit type `()`
-            found opaque type `impl Future<Output = ()>`
+note: calling an async function returns a future
+  --> $DIR/if-then-neeing-semi.rs:28:9
+   |
+LL |         async_dummy()
+   |         ^^^^^^^^^^^^^
 help: consider `await`ing on the `Future`
    |
 LL |         async_dummy().await
@@ -38,14 +41,17 @@ LL | |         async_dummy();
 LL | |
 LL | |     } else {
 LL | |         async_dummy2()
-   | |         ^^^^^^^^^^^^^^ expected `()`, found opaque type
+   | |         ^^^^^^^^^^^^^^ expected `()`, found future
 ...  |
 LL | |
 LL | |     };
    | |_____- `if` and `else` have incompatible types
    |
-   = note: expected unit type `()`
-            found opaque type `impl Future<Output = ()>`
+note: calling an async function returns a future
+  --> $DIR/if-then-neeing-semi.rs:41:9
+   |
+LL |         async_dummy2()
+   |         ^^^^^^^^^^^^^^
 help: consider `await`ing on the `Future`
    |
 LL |         async_dummy2().await
@@ -69,14 +75,12 @@ LL | |         async_dummy()
 LL | |
 LL | |     } else {
 LL | |         async_dummy2()
-   | |         ^^^^^^^^^^^^^^ expected opaque type, found a different opaque type
-...  |
+   | |         ^^^^^^^^^^^^^^ expected future, found a different future
+LL | |
 LL | |
 LL | |     };
    | |_____- `if` and `else` have incompatible types
    |
-   = note: expected opaque type `impl Future<Output = ()>` (opaque type at <$DIR/if-then-neeing-semi.rs:18:24>)
-              found opaque type `impl Future<Output = ()>` (opaque type at <$DIR/if-then-neeing-semi.rs:20:25>)
    = note: distinct uses of `impl Trait` result in different opaque types
 help: consider `await`ing on both `Future`s
    |
diff --git a/tests/ui/suggestions/issue-81839.stderr b/tests/ui/suggestions/issue-81839.stderr
index 4af7cc9f8ec..6d0a0c7b3fa 100644
--- a/tests/ui/suggestions/issue-81839.stderr
+++ b/tests/ui/suggestions/issue-81839.stderr
@@ -10,12 +10,9 @@ LL | |             cx.answer_str("hi");
    | |             this is found to be of type `()`
 LL | |         }
 LL | |         _ => cx.answer_str("hi"),
-   | |              ^^^^^^^^^^^^^^^^^^^ expected `()`, found opaque type
+   | |              ^^^^^^^^^^^^^^^^^^^ expected `()`, found future
 LL | |     }
    | |_____- `match` arms have incompatible types
-   |
-   = note: expected unit type `()`
-            found opaque type `impl Future<Output = Test>`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/suggestions/match-prev-arm-needing-semi.rs b/tests/ui/suggestions/match-prev-arm-needing-semi.rs
index 3f863cb104e..11463c453d4 100644
--- a/tests/ui/suggestions/match-prev-arm-needing-semi.rs
+++ b/tests/ui/suggestions/match-prev-arm-needing-semi.rs
@@ -24,8 +24,8 @@ async fn async_extra_semicolon_same() {
             //~^ HELP consider removing this semicolon
         }
         false => async_dummy(), //~ ERROR `match` arms have incompatible types
-        //~^ NOTE expected `()`, found opaque type
-        //~| NOTE expected unit type `()`
+        //~^ NOTE expected `()`, found future
+        //~| NOTE calling an async function returns a future
         //~| HELP consider `await`ing on the `Future`
     };
 }
@@ -37,8 +37,8 @@ async fn async_extra_semicolon_different() {
             //~^ HELP consider removing this semicolon
         }
         false => async_dummy2(), //~ ERROR `match` arms have incompatible types
-        //~^ NOTE expected `()`, found opaque type
-        //~| NOTE expected unit type `()`
+        //~^ NOTE expected `()`, found future
+        //~| NOTE calling an async function returns a future
         //~| HELP consider `await`ing on the `Future`
     };
 }
@@ -48,8 +48,7 @@ async fn async_different_futures() {
         true => async_dummy(), //~ NOTE this is found to be
         //~| HELP consider `await`ing on both `Future`s
         false => async_dummy2(), //~ ERROR `match` arms have incompatible types
-        //~^ NOTE expected opaque type, found a different opaque type
-        //~| NOTE expected opaque type `impl Future<Output = ()>`
+        //~^ NOTE expected future, found a different future
         //~| NOTE distinct uses of `impl Trait` result in different opaque types
     };
 }
diff --git a/tests/ui/suggestions/match-prev-arm-needing-semi.stderr b/tests/ui/suggestions/match-prev-arm-needing-semi.stderr
index df18c7b0b23..cf3cf45ef40 100644
--- a/tests/ui/suggestions/match-prev-arm-needing-semi.stderr
+++ b/tests/ui/suggestions/match-prev-arm-needing-semi.stderr
@@ -9,14 +9,17 @@ LL | |             async_dummy();
 LL | |
 LL | |         }
 LL | |         false => async_dummy(),
-   | |                  ^^^^^^^^^^^^^ expected `()`, found opaque type
+   | |                  ^^^^^^^^^^^^^ expected `()`, found future
 ...  |
 LL | |
 LL | |     };
    | |_____- `match` arms have incompatible types
    |
-   = note: expected unit type `()`
-            found opaque type `impl Future<Output = ()>`
+note: calling an async function returns a future
+  --> $DIR/match-prev-arm-needing-semi.rs:26:18
+   |
+LL |         false => async_dummy(),
+   |                  ^^^^^^^^^^^^^
 help: consider `await`ing on the `Future`
    |
 LL |         false => async_dummy().await,
@@ -38,14 +41,17 @@ LL | |             async_dummy();
 LL | |
 LL | |         }
 LL | |         false => async_dummy2(),
-   | |                  ^^^^^^^^^^^^^^ expected `()`, found opaque type
+   | |                  ^^^^^^^^^^^^^^ expected `()`, found future
 ...  |
 LL | |
 LL | |     };
    | |_____- `match` arms have incompatible types
    |
-   = note: expected unit type `()`
-            found opaque type `impl Future<Output = ()>`
+note: calling an async function returns a future
+  --> $DIR/match-prev-arm-needing-semi.rs:39:18
+   |
+LL |         false => async_dummy2(),
+   |                  ^^^^^^^^^^^^^^
 help: consider `await`ing on the `Future`
    |
 LL |         false => async_dummy2().await,
@@ -67,14 +73,12 @@ LL | |         true => async_dummy(),
    | |                 ------------- this is found to be of type `impl Future<Output = ()>`
 LL | |
 LL | |         false => async_dummy2(),
-   | |                  ^^^^^^^^^^^^^^ expected opaque type, found a different opaque type
-...  |
+   | |                  ^^^^^^^^^^^^^^ expected future, found a different future
+LL | |
 LL | |
 LL | |     };
    | |_____- `match` arms have incompatible types
    |
-   = note: expected opaque type `impl Future<Output = ()>` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:16:24>)
-              found opaque type `impl Future<Output = ()>` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:18:25>)
    = note: distinct uses of `impl Trait` result in different opaque types
 help: consider `await`ing on both `Future`s
    |
diff --git a/tests/ui/suggestions/opaque-type-error.stderr b/tests/ui/suggestions/opaque-type-error.stderr
index 133ffb05873..5c90d3012ab 100644
--- a/tests/ui/suggestions/opaque-type-error.stderr
+++ b/tests/ui/suggestions/opaque-type-error.stderr
@@ -2,22 +2,20 @@ error[E0308]: `if` and `else` have incompatible types
   --> $DIR/opaque-type-error.rs:20:9
    |
 LL |   fn thing_one() -> impl Future<Output = Result<(), ()>> {
-   |                     ------------------------------------ the expected opaque type
+   |                     ------------------------------------ the expected future
 ...
 LL |   fn thing_two() -> impl Future<Output = Result<(), ()>> {
-   |                     ------------------------------------ the found opaque type
+   |                     ------------------------------------ the found future
 ...
 LL | /     if true {
 LL | |         thing_one()
    | |         ----------- expected because of this
 LL | |     } else {
 LL | |         thing_two()
-   | |         ^^^^^^^^^^^ expected opaque type, found a different opaque type
+   | |         ^^^^^^^^^^^ expected future, found a different future
 LL | |     }.await
    | |_____- `if` and `else` have incompatible types
    |
-   = note: expected opaque type `impl Future<Output = Result<(), ()>>` (opaque type at <$DIR/opaque-type-error.rs:8:19>)
-              found opaque type `impl Future<Output = Result<(), ()>>` (opaque type at <$DIR/opaque-type-error.rs:12:19>)
    = note: distinct uses of `impl Trait` result in different opaque types
 help: consider `await`ing on both `Future`s
    |
diff --git a/tests/ui/traits/trait-or-new-type-instead.stderr b/tests/ui/traits/trait-or-new-type-instead.stderr
index 4726b0668e5..6fd8a03fd8f 100644
--- a/tests/ui/traits/trait-or-new-type-instead.stderr
+++ b/tests/ui/traits/trait-or-new-type-instead.stderr
@@ -1,11 +1,8 @@
 error[E0116]: cannot define inherent `impl` for a type outside of the crate where the type is defined
   --> $DIR/trait-or-new-type-instead.rs:1:1
    |
-LL | / impl<T> Option<T> {
-LL | |
-LL | |     pub fn foo(&self) { }
-LL | | }
-   | |_^ impl for type defined outside of crate.
+LL | impl<T> Option<T> {
+   | ^^^^^^^^^^^^^^^^^ impl for type defined outside of crate.
    |
    = note: define and implement a trait or new type instead
 
diff --git a/tests/ui/type-alias-impl-trait/issue-98604.stderr b/tests/ui/type-alias-impl-trait/issue-98604.stderr
index bb9dd2365ea..fa16d321890 100644
--- a/tests/ui/type-alias-impl-trait/issue-98604.stderr
+++ b/tests/ui/type-alias-impl-trait/issue-98604.stderr
@@ -2,10 +2,8 @@ error[E0271]: expected `test` to be a fn item that returns `Pin<Box<dyn Future<O
   --> $DIR/issue-98604.rs:9:5
    |
 LL |     Box::new(test) as AsyncFnPtr;
-   |     ^^^^^^^^^^^^^^ expected `Pin<Box<dyn Future<Output = ()>>>`, found opaque type
+   |     ^^^^^^^^^^^^^^ expected `Pin<Box<dyn Future<Output = ()>>>`, found future
    |
-   = note:   expected struct `Pin<Box<(dyn Future<Output = ()> + 'static)>>`
-           found opaque type `impl Future<Output = ()>`
    = note: required for the cast from `fn() -> impl Future<Output = ()> {test}` to the object type `dyn Fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>>`
 
 error: aborting due to previous error
diff --git a/tests/ui/typeck/issue-90027-async-fn-return-suggestion.stderr b/tests/ui/typeck/issue-90027-async-fn-return-suggestion.stderr
index 6a1a9f45bc6..0d72ae118f3 100644
--- a/tests/ui/typeck/issue-90027-async-fn-return-suggestion.stderr
+++ b/tests/ui/typeck/issue-90027-async-fn-return-suggestion.stderr
@@ -18,10 +18,13 @@ error[E0308]: mismatched types
   --> $DIR/issue-90027-async-fn-return-suggestion.rs:14:5
    |
 LL |     hello()
-   |     ^^^^^^^ expected `()`, found opaque type
+   |     ^^^^^^^ expected `()`, found future
    |
-   = note: expected unit type `()`
-            found opaque type `impl Future<Output = ()>`
+note: calling an async function returns a future
+  --> $DIR/issue-90027-async-fn-return-suggestion.rs:14:5
+   |
+LL |     hello()
+   |     ^^^^^^^
 help: consider `await`ing on the `Future`
    |
 LL |     hello().await