about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-05-27 13:22:55 +0000
committerbors <bors@rust-lang.org>2024-05-27 13:22:55 +0000
commitf6e4703e91eedcc5e33ad2cf3f6c0d034782f245 (patch)
tree9fe749bc3c6f1791aeb8ad41b7deeaa9d17ca9bd
parenta59072ec4fb6824213df5e9de8cae4812fd4fe97 (diff)
parent7083131c92dd4dcbfc23216cd7eb8d7fac93fcaf (diff)
downloadrust-f6e4703e91eedcc5e33ad2cf3f6c0d034782f245.tar.gz
rust-f6e4703e91eedcc5e33ad2cf3f6c0d034782f245.zip
Auto merge of #125611 - GuillaumeGomez:rollup-dfavpgg, r=GuillaumeGomez
Rollup of 7 pull requests

Successful merges:

 - #124870 (Update Result docs to the new guarantees)
 - #125148 (codegen: tweak/extend shift comments)
 - #125522 (Add "better" edition handling on lint-docs tool)
 - #125530 (cleanup dependence of `ExtCtxt` in transcribe when macro expansion)
 - #125535 (clean-up: remove deprecated field `dist.missing-tools`)
 - #125597 (Uplift `EarlyBinder` into `rustc_type_ir`)
 - #125607 (Migrate `run-make/compile-stdin` to `rmake.rs`)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--Cargo.lock1
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs9
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs8
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs3
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs60
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs12
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/explicit.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs6
-rw-r--r--compiler/rustc_lint/src/non_local_def.rs2
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs4
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs4
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs10
-rw-r--r--compiler/rustc_middle/src/arena.rs2
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs2
-rw-r--r--compiler/rustc_middle/src/mir/consts.rs5
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs2
-rw-r--r--compiler/rustc_middle/src/query/erase.rs16
-rw-r--r--compiler/rustc_middle/src/query/mod.rs26
-rw-r--r--compiler/rustc_middle/src/query/on_disk_cache.rs2
-rw-r--r--compiler/rustc_middle/src/ty/abstract_const.rs3
-rw-r--r--compiler/rustc_middle/src/ty/adt.rs2
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs14
-rw-r--r--compiler/rustc_middle/src/ty/context.rs8
-rw-r--r--compiler/rustc_middle/src/ty/fold.rs104
-rw-r--r--compiler/rustc_middle/src/ty/generic_args.rs496
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs2
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs6
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs8
-rw-r--r--compiler/rustc_middle/src/ty/normalize_erasing_regions.rs4
-rw-r--r--compiler/rustc_middle/src/ty/parameterized.rs4
-rw-r--r--compiler/rustc_middle/src/ty/region.rs14
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs19
-rw-r--r--compiler/rustc_middle/src/ty/util.rs4
-rw-r--r--compiler/rustc_middle/src/values.rs6
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/ty.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs2
-rw-r--r--compiler/rustc_ty_utils/src/consts.rs6
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs4
-rw-r--r--compiler/rustc_type_ir/Cargo.toml1
-rw-r--r--compiler/rustc_type_ir/src/binder.rs519
-rw-r--r--compiler/rustc_type_ir/src/fold.rs96
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs11
-rw-r--r--compiler/rustc_type_ir/src/interner.rs50
-rw-r--r--compiler/rustc_type_ir/src/lib.rs2
-rw-r--r--compiler/rustc_type_ir/src/predicate.rs2
-rw-r--r--config.example.toml3
-rw-r--r--library/core/src/option.rs3
-rw-r--r--library/core/src/result.rs21
-rw-r--r--src/bootstrap/src/core/config/config.rs4
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs5
-rw-r--r--src/tools/lint-docs/src/lib.rs13
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt1
-rw-r--r--tests/run-make/compile-stdin/Makefile9
-rw-r--r--tests/run-make/compile-stdin/rmake.rs13
57 files changed, 885 insertions, 762 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 92e6a22b4b9..5e8d179e536 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4686,6 +4686,7 @@ dependencies = [
  "rustc_span",
  "rustc_type_ir_macros",
  "smallvec",
+ "tracing",
 ]
 
 [[package]]
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 5d7eb052561..f372d3a0522 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -294,12 +294,13 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     }
 }
 
-/// Returns `rhs` sufficiently masked, truncated, and/or extended so that
-/// it can be used to shift `lhs`.
+/// Returns `rhs` sufficiently masked, truncated, and/or extended so that it can be used to shift
+/// `lhs`: it has the same size as `lhs`, and the value, when interpreted unsigned (no matter its
+/// type), will not exceed the size of `lhs`.
 ///
-/// Shifts in MIR are all allowed to have mismatched LHS & RHS types.
+/// Shifts in MIR are all allowed to have mismatched LHS & RHS types, and signed RHS.
 /// The shift methods in `BuilderMethods`, however, are fully homogeneous
-/// (both parameters and the return type are all the same type).
+/// (both parameters and the return type are all the same size) and assume an unsigned RHS.
 ///
 /// If `is_unchecked` is false, this masks the RHS to ensure it stays in-bounds,
 /// as the `BuilderMethods` shifts are UB for out-of-bounds shift amounts.
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index 9fd6eb8edab..2f0daefa46a 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -110,8 +110,16 @@ pub trait BuilderMethods<'a, 'tcx>:
     fn frem(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
     fn frem_fast(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
     fn frem_algebraic(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
+    /// Generate a left-shift. Both operands must have the same size. The right operand must be
+    /// interpreted as unsigned and can be assumed to be less than the size of the left operand.
     fn shl(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
+    /// Generate a logical right-shift. Both operands must have the same size. The right operand
+    /// must be interpreted as unsigned and can be assumed to be less than the size of the left
+    /// operand.
     fn lshr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
+    /// Generate an arithmetic right-shift. Both operands must have the same size. The right operand
+    /// must be interpreted as unsigned and can be assumed to be less than the size of the left
+    /// operand.
     fn ashr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
     fn unchecked_sadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
     fn unchecked_uadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index d99ecb61085..5d3ba5d3223 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -223,7 +223,8 @@ fn expand_macro<'cx>(
             let arm_span = rhses[i].span();
 
             // rhs has holes ( `$id` and `$(...)` that need filled)
-            let tts = match transcribe(cx, &named_matches, rhs, rhs_span, transparency) {
+            let id = cx.current_expansion.id;
+            let tts = match transcribe(psess, &named_matches, rhs, rhs_span, transparency, id) {
                 Ok(tts) => tts,
                 Err(err) => {
                     let guar = err.emit();
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index 8a084dcb4fe..e1f50876b05 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -1,4 +1,3 @@
-use crate::base::ExtCtxt;
 use crate::errors::{
     CountRepetitionMisplaced, MetaVarExprUnrecognizedVar, MetaVarsDifSeqMatchers, MustRepeatOnce,
     NoSyntaxVarsExprRepeat, VarStillRepeating,
@@ -9,12 +8,13 @@ use rustc_ast::mut_visit::{self, MutVisitor};
 use rustc_ast::token::{self, Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{pluralize, Diag, PResult};
+use rustc_errors::{pluralize, Diag, DiagCtxt, PResult};
 use rustc_parse::parser::ParseNtResult;
 use rustc_span::hygiene::{LocalExpnId, Transparency};
 use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent};
 use rustc_span::{with_metavar_spans, Span, SyntaxContext};
 
+use rustc_session::parse::ParseSess;
 use smallvec::{smallvec, SmallVec};
 use std::mem;
 
@@ -99,11 +99,12 @@ impl<'a> Iterator for Frame<'a> {
 ///
 /// Along the way, we do some additional error checking.
 pub(super) fn transcribe<'a>(
-    cx: &ExtCtxt<'a>,
+    psess: &'a ParseSess,
     interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
     src: &mbe::Delimited,
     src_span: DelimSpan,
     transparency: Transparency,
+    expand_id: LocalExpnId,
 ) -> PResult<'a, TokenStream> {
     // Nothing for us to transcribe...
     if src.tts.is_empty() {
@@ -137,8 +138,9 @@ pub(super) fn transcribe<'a>(
     // again, and we are done transcribing.
     let mut result: Vec<TokenTree> = Vec::new();
     let mut result_stack = Vec::new();
-    let mut marker = Marker(cx.current_expansion.id, transparency, Default::default());
+    let mut marker = Marker(expand_id, transparency, Default::default());
 
+    let dcx = &psess.dcx;
     loop {
         // Look at the last frame on the stack.
         // If it still has a TokenTree we have not looked at yet, use that tree.
@@ -201,9 +203,7 @@ pub(super) fn transcribe<'a>(
             seq @ mbe::TokenTree::Sequence(_, seq_rep) => {
                 match lockstep_iter_size(seq, interp, &repeats) {
                     LockstepIterSize::Unconstrained => {
-                        return Err(cx
-                            .dcx()
-                            .create_err(NoSyntaxVarsExprRepeat { span: seq.span() }));
+                        return Err(dcx.create_err(NoSyntaxVarsExprRepeat { span: seq.span() }));
                     }
 
                     LockstepIterSize::Contradiction(msg) => {
@@ -211,9 +211,9 @@ pub(super) fn transcribe<'a>(
                         // happens when two meta-variables are used in the same repetition in a
                         // sequence, but they come from different sequence matchers and repeat
                         // different amounts.
-                        return Err(cx
-                            .dcx()
-                            .create_err(MetaVarsDifSeqMatchers { span: seq.span(), msg }));
+                        return Err(
+                            dcx.create_err(MetaVarsDifSeqMatchers { span: seq.span(), msg })
+                        );
                     }
 
                     LockstepIterSize::Constraint(len, _) => {
@@ -227,9 +227,7 @@ pub(super) fn transcribe<'a>(
                                 // FIXME: this really ought to be caught at macro definition
                                 // time... It happens when the Kleene operator in the matcher and
                                 // the body for the same meta-variable do not match.
-                                return Err(cx
-                                    .dcx()
-                                    .create_err(MustRepeatOnce { span: sp.entire() }));
+                                return Err(dcx.create_err(MustRepeatOnce { span: sp.entire() }));
                             }
                         } else {
                             // 0 is the initial counter (we have done 0 repetitions so far). `len`
@@ -274,7 +272,7 @@ pub(super) fn transcribe<'a>(
                         MatchedSingle(ParseNtResult::Tt(tt)) => {
                             // `tt`s are emitted into the output stream directly as "raw tokens",
                             // without wrapping them into groups.
-                            maybe_use_metavar_location(cx, &stack, sp, tt, &mut marker)
+                            maybe_use_metavar_location(psess, &stack, sp, tt, &mut marker)
                         }
                         MatchedSingle(ParseNtResult::Ident(ident, is_raw)) => {
                             marker.visit_span(&mut sp);
@@ -295,7 +293,7 @@ pub(super) fn transcribe<'a>(
                         }
                         MatchedSeq(..) => {
                             // We were unable to descend far enough. This is an error.
-                            return Err(cx.dcx().create_err(VarStillRepeating { span: sp, ident }));
+                            return Err(dcx.create_err(VarStillRepeating { span: sp, ident }));
                         }
                     };
                     result.push(tt)
@@ -314,7 +312,7 @@ pub(super) fn transcribe<'a>(
 
             // Replace meta-variable expressions with the result of their expansion.
             mbe::TokenTree::MetaVarExpr(sp, expr) => {
-                transcribe_metavar_expr(cx, expr, interp, &mut marker, &repeats, &mut result, sp)?;
+                transcribe_metavar_expr(dcx, expr, interp, &mut marker, &repeats, &mut result, sp)?;
             }
 
             // If we are entering a new delimiter, we push its contents to the `stack` to be
@@ -374,7 +372,7 @@ pub(super) fn transcribe<'a>(
 ///   combine with each other and not with tokens outside of the sequence.
 /// - The metavariable span comes from a different crate, then we prefer the more local span.
 fn maybe_use_metavar_location(
-    cx: &ExtCtxt<'_>,
+    psess: &ParseSess,
     stack: &[Frame<'_>],
     mut metavar_span: Span,
     orig_tt: &TokenTree,
@@ -412,7 +410,7 @@ fn maybe_use_metavar_location(
                 && insert(mspans, dspan.entire(), metavar_span)
         }),
     };
-    if no_collision || cx.source_map().is_imported(metavar_span) {
+    if no_collision || psess.source_map().is_imported(metavar_span) {
         return orig_tt.clone();
     }
 
@@ -573,7 +571,7 @@ fn lockstep_iter_size(
 /// * `[ $( ${count(foo, 1)} ),* ]` will return an error because `${count(foo, 1)}` is
 ///   declared inside a single repetition and the index `1` implies two nested repetitions.
 fn count_repetitions<'a>(
-    cx: &ExtCtxt<'a>,
+    dcx: &'a DiagCtxt,
     depth_user: usize,
     mut matched: &NamedMatch,
     repeats: &[(usize, usize)],
@@ -610,7 +608,7 @@ fn count_repetitions<'a>(
         .and_then(|el| el.checked_sub(repeats.len()))
         .unwrap_or_default();
     if depth_user > depth_max {
-        return Err(out_of_bounds_err(cx, depth_max + 1, sp.entire(), "count"));
+        return Err(out_of_bounds_err(dcx, depth_max + 1, sp.entire(), "count"));
     }
 
     // `repeats` records all of the nested levels at which we are currently
@@ -626,7 +624,7 @@ fn count_repetitions<'a>(
     }
 
     if let MatchedSingle(_) = matched {
-        return Err(cx.dcx().create_err(CountRepetitionMisplaced { span: sp.entire() }));
+        return Err(dcx.create_err(CountRepetitionMisplaced { span: sp.entire() }));
     }
 
     count(depth_user, depth_max, matched)
@@ -634,7 +632,7 @@ fn count_repetitions<'a>(
 
 /// Returns a `NamedMatch` item declared on the LHS given an arbitrary [Ident]
 fn matched_from_ident<'ctx, 'interp, 'rslt>(
-    cx: &ExtCtxt<'ctx>,
+    dcx: &'ctx DiagCtxt,
     ident: Ident,
     interp: &'interp FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
 ) -> PResult<'ctx, &'rslt NamedMatch>
@@ -643,12 +641,12 @@ where
 {
     let span = ident.span;
     let key = MacroRulesNormalizedIdent::new(ident);
-    interp.get(&key).ok_or_else(|| cx.dcx().create_err(MetaVarExprUnrecognizedVar { span, key }))
+    interp.get(&key).ok_or_else(|| dcx.create_err(MetaVarExprUnrecognizedVar { span, key }))
 }
 
 /// Used by meta-variable expressions when an user input is out of the actual declared bounds. For
 /// example, index(999999) in an repetition of only three elements.
-fn out_of_bounds_err<'a>(cx: &ExtCtxt<'a>, max: usize, span: Span, ty: &str) -> Diag<'a> {
+fn out_of_bounds_err<'a>(dcx: &'a DiagCtxt, max: usize, span: Span, ty: &str) -> Diag<'a> {
     let msg = if max == 0 {
         format!(
             "meta-variable expression `{ty}` with depth parameter \
@@ -660,11 +658,11 @@ fn out_of_bounds_err<'a>(cx: &ExtCtxt<'a>, max: usize, span: Span, ty: &str) ->
              must be less than {max}"
         )
     };
-    cx.dcx().struct_span_err(span, msg)
+    dcx.struct_span_err(span, msg)
 }
 
 fn transcribe_metavar_expr<'a>(
-    cx: &ExtCtxt<'a>,
+    dcx: &'a DiagCtxt,
     expr: &MetaVarExpr,
     interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
     marker: &mut Marker,
@@ -679,8 +677,8 @@ fn transcribe_metavar_expr<'a>(
     };
     match *expr {
         MetaVarExpr::Count(original_ident, depth) => {
-            let matched = matched_from_ident(cx, original_ident, interp)?;
-            let count = count_repetitions(cx, depth, matched, repeats, sp)?;
+            let matched = matched_from_ident(dcx, original_ident, interp)?;
+            let count = count_repetitions(dcx, depth, matched, repeats, sp)?;
             let tt = TokenTree::token_alone(
                 TokenKind::lit(token::Integer, sym::integer(count), None),
                 visited_span(),
@@ -689,7 +687,7 @@ fn transcribe_metavar_expr<'a>(
         }
         MetaVarExpr::Ignore(original_ident) => {
             // Used to ensure that `original_ident` is present in the LHS
-            let _ = matched_from_ident(cx, original_ident, interp)?;
+            let _ = matched_from_ident(dcx, original_ident, interp)?;
         }
         MetaVarExpr::Index(depth) => match repeats.iter().nth_back(depth) {
             Some((index, _)) => {
@@ -698,7 +696,7 @@ fn transcribe_metavar_expr<'a>(
                     visited_span(),
                 ));
             }
-            None => return Err(out_of_bounds_err(cx, repeats.len(), sp.entire(), "index")),
+            None => return Err(out_of_bounds_err(dcx, repeats.len(), sp.entire(), "index")),
         },
         MetaVarExpr::Len(depth) => match repeats.iter().nth_back(depth) {
             Some((_, length)) => {
@@ -707,7 +705,7 @@ fn transcribe_metavar_expr<'a>(
                     visited_span(),
                 ));
             }
-            None => return Err(out_of_bounds_err(cx, repeats.len(), sp.entire(), "len")),
+            None => return Err(out_of_bounds_err(dcx, repeats.len(), sp.entire(), "len")),
         },
     }
     Ok(())
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 39ced1c803f..8928711253c 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -449,7 +449,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateBound<'_, 'tcx> {
 pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_m_def_id: LocalDefId,
-) -> Result<&'tcx DefIdMap<ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed> {
+) -> Result<&'tcx DefIdMap<ty::EarlyBinder<'tcx, Ty<'tcx>>>, ErrorGuaranteed> {
     let impl_m = tcx.opt_associated_item(impl_m_def_id.to_def_id()).unwrap();
     let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap();
     let impl_trait_ref =
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 40cd65b899e..75e35e7bf50 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -1277,7 +1277,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
 }
 
 #[instrument(level = "debug", skip(tcx))]
-fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<'_>> {
+fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFnSig<'_>> {
     use rustc_hir::Node::*;
     use rustc_hir::*;
 
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index dd1d209389d..50c93e9f1d7 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -82,14 +82,14 @@ fn opaque_type_bounds<'tcx>(
 pub(super) fn explicit_item_bounds(
     tcx: TyCtxt<'_>,
     def_id: LocalDefId,
-) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> {
+) -> ty::EarlyBinder<'_, &'_ [(ty::Clause<'_>, Span)]> {
     explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::All)
 }
 
 pub(super) fn explicit_item_super_predicates(
     tcx: TyCtxt<'_>,
     def_id: LocalDefId,
-) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> {
+) -> ty::EarlyBinder<'_, &'_ [(ty::Clause<'_>, Span)]> {
     explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::SelfOnly)
 }
 
@@ -97,7 +97,7 @@ pub(super) fn explicit_item_bounds_with_filter(
     tcx: TyCtxt<'_>,
     def_id: LocalDefId,
     filter: PredicateFilter,
-) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> {
+) -> ty::EarlyBinder<'_, &'_ [(ty::Clause<'_>, Span)]> {
     match tcx.opt_rpitit_info(def_id.to_def_id()) {
         // RPITIT's bounds are the same as opaque type bounds, but with
         // a projection self type.
@@ -166,7 +166,7 @@ pub(super) fn explicit_item_bounds_with_filter(
     ty::EarlyBinder::bind(bounds)
 }
 
-pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<ty::Clauses<'_>> {
+pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<'_, ty::Clauses<'_>> {
     tcx.explicit_item_bounds(def_id).map_bound(|bounds| {
         tcx.mk_clauses_from_iter(util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound)))
     })
@@ -175,7 +175,7 @@ pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<ty:
 pub(super) fn item_super_predicates(
     tcx: TyCtxt<'_>,
     def_id: DefId,
-) -> ty::EarlyBinder<ty::Clauses<'_>> {
+) -> ty::EarlyBinder<'_, ty::Clauses<'_>> {
     tcx.explicit_item_super_predicates(def_id).map_bound(|bounds| {
         tcx.mk_clauses_from_iter(
             util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound)).filter_only_self(),
@@ -186,7 +186,7 @@ pub(super) fn item_super_predicates(
 pub(super) fn item_non_self_assumptions(
     tcx: TyCtxt<'_>,
     def_id: DefId,
-) -> ty::EarlyBinder<ty::Clauses<'_>> {
+) -> ty::EarlyBinder<'_, ty::Clauses<'_>> {
     let all_bounds: FxIndexSet<_> = tcx.item_bounds(def_id).skip_binder().iter().collect();
     let own_bounds: FxIndexSet<_> =
         tcx.item_super_predicates(def_id).skip_binder().iter().collect();
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 1475e53c47c..ed942cc50bb 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -309,7 +309,7 @@ fn get_path_containing_arg_in_pat<'hir>(
     arg_path
 }
 
-pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty<'_>> {
+pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, Ty<'_>> {
     use rustc_hir::*;
     use rustc_middle::ty::Ty;
 
@@ -512,7 +512,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
 pub(super) fn type_of_opaque(
     tcx: TyCtxt<'_>,
     def_id: DefId,
-) -> Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> {
+) -> Result<ty::EarlyBinder<'_, Ty<'_>>, CyclePlaceholder> {
     if let Some(def_id) = def_id.as_local() {
         use rustc_hir::*;
 
diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
index 1de7a0f7bc7..bbfadbb5c30 100644
--- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
@@ -6,7 +6,7 @@ use super::utils::*;
 
 #[derive(Debug)]
 pub struct ExplicitPredicatesMap<'tcx> {
-    map: FxIndexMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>,
+    map: FxIndexMap<DefId, ty::EarlyBinder<'tcx, RequiredPredicates<'tcx>>>,
 }
 
 impl<'tcx> ExplicitPredicatesMap<'tcx> {
@@ -18,7 +18,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
         &mut self,
         tcx: TyCtxt<'tcx>,
         def_id: DefId,
-    ) -> &ty::EarlyBinder<RequiredPredicates<'tcx>> {
+    ) -> &ty::EarlyBinder<'tcx, RequiredPredicates<'tcx>> {
         self.map.entry(def_id).or_insert_with(|| {
             let predicates = if def_id.is_local() {
                 tcx.explicit_predicates_of(def_id)
diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
index e6c582667ba..af08f50f655 100644
--- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
@@ -15,7 +15,7 @@ use super::utils::*;
 ///     now be filled with inferred predicates.
 pub(super) fn infer_predicates(
     tcx: TyCtxt<'_>,
-) -> FxIndexMap<DefId, ty::EarlyBinder<RequiredPredicates<'_>>> {
+) -> FxIndexMap<DefId, ty::EarlyBinder<'_, RequiredPredicates<'_>>> {
     debug!("infer_predicates");
 
     let mut explicit_map = ExplicitPredicatesMap::new();
@@ -101,7 +101,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
     span: Span,
-    global_inferred_outlives: &FxIndexMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>,
+    global_inferred_outlives: &FxIndexMap<DefId, ty::EarlyBinder<'tcx, RequiredPredicates<'tcx>>>,
     required_predicates: &mut RequiredPredicates<'tcx>,
     explicit_map: &mut ExplicitPredicatesMap<'tcx>,
 ) {
@@ -322,7 +322,7 @@ fn check_inferred_predicates<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: DefId,
     args: ty::GenericArgsRef<'tcx>,
-    global_inferred_outlives: &FxIndexMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>,
+    global_inferred_outlives: &FxIndexMap<DefId, ty::EarlyBinder<'tcx, RequiredPredicates<'tcx>>>,
     required_predicates: &mut RequiredPredicates<'tcx>,
 ) {
     // Load the current set of inferred and explicit predicates from `global_inferred_outlives`
diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs
index b3e93748a16..87ee5f53628 100644
--- a/compiler/rustc_lint/src/non_local_def.rs
+++ b/compiler/rustc_lint/src/non_local_def.rs
@@ -270,7 +270,7 @@ fn impl_trait_ref_has_enough_non_local_candidates<'tcx>(
     tcx: TyCtxt<'tcx>,
     infer_span: Span,
     trait_def_id: DefId,
-    binder: EarlyBinder<TraitRef<'tcx>>,
+    binder: EarlyBinder<'tcx, TraitRef<'tcx>>,
     mut did_has_local_parent: impl FnMut(DefId) -> bool,
 ) -> bool {
     let infcx = tcx
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 42e12a88fa5..13867319e5c 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -3757,7 +3757,7 @@ declare_lint! {
     ///
     /// ### Example
     ///
-    /// ```rust,compile_fail
+    /// ```rust,edition2018,compile_fail
     /// #![deny(rust_2021_incompatible_or_patterns)]
     ///
     /// macro_rules! match_any {
@@ -3797,7 +3797,7 @@ declare_lint! {
     ///
     /// ### Example
     ///
-    /// ```rust,compile_fail
+    /// ```rust,edition2018,compile_fail
     /// #![deny(rust_2021_prelude_collisions)]
     ///
     /// trait Foo {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 695525e755d..19bb943e6bc 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1074,7 +1074,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         self,
         index: DefIndex,
         tcx: TyCtxt<'tcx>,
-    ) -> ty::EarlyBinder<&'tcx [(ty::Clause<'tcx>, Span)]> {
+    ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> {
         let lazy = self.root.tables.explicit_item_bounds.get(self, index);
         let output = if lazy.is_default() {
             &mut []
@@ -1088,7 +1088,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         self,
         index: DefIndex,
         tcx: TyCtxt<'tcx>,
-    ) -> ty::EarlyBinder<&'tcx [(ty::Clause<'tcx>, Span)]> {
+    ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> {
         let lazy = self.root.tables.explicit_item_super_predicates.get(self, index);
         let output = if lazy.is_default() {
             &mut []
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 825034cf96a..c2cf5b6b712 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -418,19 +418,19 @@ define_tables! {
     // As an optimization, we only store this for trait aliases,
     // since it's identical to super_predicates_of for traits.
     implied_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>,
-    type_of: Table<DefIndex, LazyValue<ty::EarlyBinder<Ty<'static>>>>,
+    type_of: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, Ty<'static>>>>,
     variances_of: Table<DefIndex, LazyArray<ty::Variance>>,
-    fn_sig: Table<DefIndex, LazyValue<ty::EarlyBinder<ty::PolyFnSig<'static>>>>,
+    fn_sig: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, ty::PolyFnSig<'static>>>>,
     codegen_fn_attrs: Table<DefIndex, LazyValue<CodegenFnAttrs>>,
     impl_trait_header: Table<DefIndex, LazyValue<ty::ImplTraitHeader<'static>>>,
-    const_param_default: Table<DefIndex, LazyValue<ty::EarlyBinder<rustc_middle::ty::Const<'static>>>>,
+    const_param_default: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, rustc_middle::ty::Const<'static>>>>,
     object_lifetime_default: Table<DefIndex, LazyValue<ObjectLifetimeDefault>>,
     optimized_mir: Table<DefIndex, LazyValue<mir::Body<'static>>>,
     mir_for_ctfe: Table<DefIndex, LazyValue<mir::Body<'static>>>,
     closure_saved_names_of_captured_variables: Table<DefIndex, LazyValue<IndexVec<FieldIdx, Symbol>>>,
     mir_coroutine_witnesses: Table<DefIndex, LazyValue<mir::CoroutineLayout<'static>>>,
     promoted_mir: Table<DefIndex, LazyValue<IndexVec<mir::Promoted, mir::Body<'static>>>>,
-    thir_abstract_const: Table<DefIndex, LazyValue<ty::EarlyBinder<ty::Const<'static>>>>,
+    thir_abstract_const: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, ty::Const<'static>>>>,
     impl_parent: Table<DefIndex, RawDefId>,
     constness: Table<DefIndex, hir::Constness>,
     defaultness: Table<DefIndex, hir::Defaultness>,
@@ -459,7 +459,7 @@ define_tables! {
     macro_definition: Table<DefIndex, LazyValue<ast::DelimArgs>>,
     proc_macro: Table<DefIndex, MacroKind>,
     deduced_param_attrs: Table<DefIndex, LazyArray<DeducedParamAttrs>>,
-    trait_impl_trait_tys: Table<DefIndex, LazyValue<DefIdMap<ty::EarlyBinder<Ty<'static>>>>>,
+    trait_impl_trait_tys: Table<DefIndex, LazyValue<DefIdMap<ty::EarlyBinder<'static, Ty<'static>>>>>,
     doc_link_resolutions: Table<DefIndex, LazyValue<DocLinkResMap>>,
     doc_link_traits_in_scope: Table<DefIndex, LazyArray<DefId>>,
     assumed_wf_types_for_rpitit: Table<DefIndex, LazyArray<(Ty<'static>, Span)>>,
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index b0e72eaf5a4..bf6ab800064 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -108,7 +108,7 @@ macro_rules! arena_types {
             [decode] trait_impl_trait_tys:
                 rustc_data_structures::unord::UnordMap<
                     rustc_hir::def_id::DefId,
-                    rustc_middle::ty::EarlyBinder<rustc_middle::ty::Ty<'tcx>>
+                    rustc_middle::ty::EarlyBinder<'tcx, rustc_middle::ty::Ty<'tcx>>
                 >,
             [] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<'tcx>,
             [] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData<'tcx>,
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 34748afa863..d39422b2b04 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -121,7 +121,7 @@ impl<'tcx> TyCtxt<'tcx> {
         LocalModDefId::new_unchecked(id)
     }
 
-    pub fn impl_subject(self, def_id: DefId) -> EarlyBinder<ImplSubject<'tcx>> {
+    pub fn impl_subject(self, def_id: DefId) -> EarlyBinder<'tcx, ImplSubject<'tcx>> {
         match self.impl_trait_ref(def_id) {
             Some(t) => t.map_bound(ImplSubject::Trait),
             None => self.type_of(def_id).map_bound(ImplSubject::Inherent),
diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs
index d025dc360a2..e107c2c12bd 100644
--- a/compiler/rustc_middle/src/mir/consts.rs
+++ b/compiler/rustc_middle/src/mir/consts.rs
@@ -220,7 +220,10 @@ pub enum Const<'tcx> {
 }
 
 impl<'tcx> Const<'tcx> {
-    pub fn identity_unevaluated(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::EarlyBinder<Const<'tcx>> {
+    pub fn identity_unevaluated(
+        tcx: TyCtxt<'tcx>,
+        def_id: DefId,
+    ) -> ty::EarlyBinder<'tcx, Const<'tcx>> {
         ty::EarlyBinder::bind(Const::Unevaluated(
             UnevaluatedConst {
                 def: def_id,
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 2b2b9392a70..02e5174a715 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -624,7 +624,7 @@ impl<'tcx> Body<'tcx> {
 
     /// Returns the return type; it always return first element from `local_decls` array.
     #[inline]
-    pub fn bound_return_ty(&self) -> ty::EarlyBinder<Ty<'tcx>> {
+    pub fn bound_return_ty(&self) -> ty::EarlyBinder<'tcx, Ty<'tcx>> {
         ty::EarlyBinder::bind(self.local_decls[RETURN_PLACE].ty)
     }
 
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index 320d49ea646..1e36f034cc2 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -114,9 +114,11 @@ impl EraseType for Result<CoerceUnsizedInfo, rustc_errors::ErrorGuaranteed> {
     type Result = [u8; size_of::<Result<CoerceUnsizedInfo, rustc_errors::ErrorGuaranteed>>()];
 }
 
-impl EraseType for Result<Option<ty::EarlyBinder<ty::Const<'_>>>, rustc_errors::ErrorGuaranteed> {
+impl EraseType
+    for Result<Option<ty::EarlyBinder<'_, ty::Const<'_>>>, rustc_errors::ErrorGuaranteed>
+{
     type Result = [u8; size_of::<
-        Result<Option<ty::EarlyBinder<ty::Const<'static>>>, rustc_errors::ErrorGuaranteed>,
+        Result<Option<ty::EarlyBinder<'static, ty::Const<'static>>>, rustc_errors::ErrorGuaranteed>,
     >()];
 }
 
@@ -165,8 +167,8 @@ impl EraseType for Result<&'_ ty::List<Ty<'_>>, ty::util::AlwaysRequiresDrop> {
         [u8; size_of::<Result<&'static ty::List<Ty<'static>>, ty::util::AlwaysRequiresDrop>>()];
 }
 
-impl EraseType for Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> {
-    type Result = [u8; size_of::<Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder>>()];
+impl EraseType for Result<ty::EarlyBinder<'_, Ty<'_>>, CyclePlaceholder> {
+    type Result = [u8; size_of::<Result<ty::EarlyBinder<'static, Ty<'_>>, CyclePlaceholder>>()];
 }
 
 impl<T> EraseType for Option<&'_ T> {
@@ -185,15 +187,15 @@ impl EraseType for Option<ty::ImplTraitHeader<'_>> {
     type Result = [u8; size_of::<Option<ty::ImplTraitHeader<'static>>>()];
 }
 
-impl EraseType for Option<ty::EarlyBinder<Ty<'_>>> {
-    type Result = [u8; size_of::<Option<ty::EarlyBinder<Ty<'static>>>>()];
+impl EraseType for Option<ty::EarlyBinder<'_, Ty<'_>>> {
+    type Result = [u8; size_of::<Option<ty::EarlyBinder<'static, Ty<'static>>>>()];
 }
 
 impl EraseType for rustc_hir::MaybeOwner<'_> {
     type Result = [u8; size_of::<rustc_hir::MaybeOwner<'static>>()];
 }
 
-impl<T: EraseType> EraseType for ty::EarlyBinder<T> {
+impl<T: EraseType> EraseType for ty::EarlyBinder<'_, T> {
     type Result = T::Result;
 }
 
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 8ca7a465c2a..6ad4b7c40fb 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -209,7 +209,7 @@ rustc_queries! {
 
     /// Given the def_id of a const-generic parameter, computes the associated default const
     /// parameter. e.g. `fn example<const N: usize=3>` called on `N` would return `3`.
-    query const_param_default(param: DefId) -> ty::EarlyBinder<ty::Const<'tcx>> {
+    query const_param_default(param: DefId) -> ty::EarlyBinder<'tcx, ty::Const<'tcx>> {
         desc { |tcx| "computing const default for a given parameter `{}`", tcx.def_path_str(param)  }
         cache_on_disk_if { param.is_local() }
         separate_provide_extern
@@ -219,7 +219,7 @@ rustc_queries! {
     /// to an alias, it will "skip" this alias to return the aliased type.
     ///
     /// [`DefId`]: rustc_hir::def_id::DefId
-    query type_of(key: DefId) -> ty::EarlyBinder<Ty<'tcx>> {
+    query type_of(key: DefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> {
         desc { |tcx|
             "{action} `{path}`",
             action = {
@@ -240,7 +240,7 @@ rustc_queries! {
     /// Specialized instance of `type_of` that detects cycles that are due to
     /// revealing opaque because of an auto trait bound. Unless `CyclePlaceholder` needs
     /// to be handled separately, call `type_of` instead.
-    query type_of_opaque(key: DefId) -> Result<ty::EarlyBinder<Ty<'tcx>>, CyclePlaceholder> {
+    query type_of_opaque(key: DefId) -> Result<ty::EarlyBinder<'tcx, Ty<'tcx>>, CyclePlaceholder> {
         desc { |tcx|
             "computing type of opaque `{path}`",
             path = tcx.def_path_str(key),
@@ -257,7 +257,7 @@ rustc_queries! {
     }
 
     query collect_return_position_impl_trait_in_trait_tys(key: DefId)
-        -> Result<&'tcx DefIdMap<ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed>
+        -> Result<&'tcx DefIdMap<ty::EarlyBinder<'tcx, Ty<'tcx>>>, ErrorGuaranteed>
     {
         desc { "comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process" }
         cache_on_disk_if { key.is_local() }
@@ -363,7 +363,7 @@ rustc_queries! {
     /// `key` is the `DefId` of the associated type or opaque type.
     ///
     /// Bounds from the parent (e.g. with nested impl trait) are not included.
-    query explicit_item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx [(ty::Clause<'tcx>, Span)]> {
+    query explicit_item_bounds(key: DefId) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> {
         desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
         separate_provide_extern
@@ -373,7 +373,7 @@ rustc_queries! {
     /// share the `Self` type of the item. These are a subset of the bounds
     /// that may explicitly be used for things like closure signature
     /// deduction.
-    query explicit_item_super_predicates(key: DefId) -> ty::EarlyBinder<&'tcx [(ty::Clause<'tcx>, Span)]> {
+    query explicit_item_super_predicates(key: DefId) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> {
         desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
         separate_provide_extern
@@ -399,15 +399,15 @@ rustc_queries! {
     /// ```
     ///
     /// Bounds from the parent (e.g. with nested impl trait) are not included.
-    query item_bounds(key: DefId) -> ty::EarlyBinder<ty::Clauses<'tcx>> {
+    query item_bounds(key: DefId) -> ty::EarlyBinder<'tcx, ty::Clauses<'tcx>> {
         desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) }
     }
 
-    query item_super_predicates(key: DefId) -> ty::EarlyBinder<ty::Clauses<'tcx>> {
+    query item_super_predicates(key: DefId) -> ty::EarlyBinder<'tcx, ty::Clauses<'tcx>> {
         desc { |tcx| "elaborating item assumptions for `{}`", tcx.def_path_str(key) }
     }
 
-    query item_non_self_assumptions(key: DefId) -> ty::EarlyBinder<ty::Clauses<'tcx>> {
+    query item_non_self_assumptions(key: DefId) -> ty::EarlyBinder<'tcx, ty::Clauses<'tcx>> {
         desc { |tcx| "elaborating item assumptions for `{}`", tcx.def_path_str(key) }
     }
 
@@ -504,7 +504,7 @@ rustc_queries! {
     /// Try to build an abstract representation of the given constant.
     query thir_abstract_const(
         key: DefId
-    ) -> Result<Option<ty::EarlyBinder<ty::Const<'tcx>>>, ErrorGuaranteed> {
+    ) -> Result<Option<ty::EarlyBinder<'tcx, ty::Const<'tcx>>>, ErrorGuaranteed> {
         desc {
             |tcx| "building an abstract representation for `{}`", tcx.def_path_str(key),
         }
@@ -704,7 +704,7 @@ rustc_queries! {
         separate_provide_extern
     }
 
-    query adt_sized_constraint(key: DefId) -> Option<ty::EarlyBinder<Ty<'tcx>>> {
+    query adt_sized_constraint(key: DefId) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
         desc { |tcx| "computing the `Sized` constraint for `{}`", tcx.def_path_str(key) }
     }
 
@@ -849,7 +849,7 @@ rustc_queries! {
 
     query self_ty_of_trait_impl_enabling_order_dep_trait_object_hack(
         key: DefId
-    ) -> Option<ty::EarlyBinder<ty::Ty<'tcx>>> {
+    ) -> Option<ty::EarlyBinder<'tcx, ty::Ty<'tcx>>> {
         desc { |tcx| "computing self type wrt issue #33140 `{}`", tcx.def_path_str(key) }
     }
 
@@ -888,7 +888,7 @@ rustc_queries! {
     }
 
     /// Computes the signature of the function.
-    query fn_sig(key: DefId) -> ty::EarlyBinder<ty::PolyFnSig<'tcx>> {
+    query fn_sig(key: DefId) -> ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>> {
         desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
         separate_provide_extern
diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs
index 941911c2230..ccd0c7cb10c 100644
--- a/compiler/rustc_middle/src/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/query/on_disk_cache.rs
@@ -752,7 +752,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx UnordSet<LocalDefId>
 }
 
 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
-    for &'tcx UnordMap<DefId, ty::EarlyBinder<Ty<'tcx>>>
+    for &'tcx UnordMap<DefId, ty::EarlyBinder<'tcx, Ty<'tcx>>>
 {
     #[inline]
     fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs
index dc46b470b6f..7fb5e9aadae 100644
--- a/compiler/rustc_middle/src/ty/abstract_const.rs
+++ b/compiler/rustc_middle/src/ty/abstract_const.rs
@@ -30,7 +30,8 @@ impl From<ErrorGuaranteed> for NotConstEvaluatable {
 
 TrivialTypeTraversalImpls! { NotConstEvaluatable }
 
-pub type BoundAbstractConst<'tcx> = Result<Option<EarlyBinder<ty::Const<'tcx>>>, ErrorGuaranteed>;
+pub type BoundAbstractConst<'tcx> =
+    Result<Option<EarlyBinder<'tcx, ty::Const<'tcx>>>, ErrorGuaranteed>;
 
 impl<'tcx> TyCtxt<'tcx> {
     pub fn expand_abstract_consts<T: TypeFoldable<TyCtxt<'tcx>>>(self, ac: T) -> T {
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 48193754077..8e946bc8b31 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -579,7 +579,7 @@ impl<'tcx> AdtDef<'tcx> {
 
     /// Returns a type such that `Self: Sized` if and only if that type is `Sized`,
     /// or `None` if the type is always sized.
-    pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> Option<ty::EarlyBinder<Ty<'tcx>>> {
+    pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
         if self.is_struct() { tcx.adt_sized_constraint(self.did()) } else { None }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 40a0dbeb2c2..6416bbbe889 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -184,6 +184,15 @@ impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
         Const::new_var(tcx, vid, ty)
     }
 
+    fn new_bound(
+        interner: TyCtxt<'tcx>,
+        debruijn: ty::DebruijnIndex,
+        var: ty::BoundVar,
+        ty: Ty<'tcx>,
+    ) -> Self {
+        Const::new_bound(interner, debruijn, var, ty)
+    }
+
     fn new_anon_bound(
         tcx: TyCtxt<'tcx>,
         debruijn: ty::DebruijnIndex,
@@ -486,7 +495,10 @@ impl<'tcx> Const<'tcx> {
     }
 }
 
-pub fn const_param_default(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Const<'_>> {
+pub fn const_param_default<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+) -> ty::EarlyBinder<'tcx, Const<'tcx>> {
     let default_def_id = match tcx.hir_node_by_def_id(def_id) {
         hir::Node::GenericParam(hir::GenericParam {
             kind: hir::GenericParamKind::Const { default: Some(ac), .. },
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index e618323c810..c09cb95de88 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -149,8 +149,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         self.generics_of(def_id)
     }
 
-    fn type_of_instantiated(self, def_id: DefId, args: ty::GenericArgsRef<'tcx>) -> Ty<'tcx> {
-        self.type_of(def_id).instantiate(self, args)
+    fn type_of(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> {
+        self.type_of(def_id)
     }
 
     fn alias_ty_kind(self, alias: ty::AliasTy<'tcx>) -> ty::AliasTyKind {
@@ -679,7 +679,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// In order to break cycles involving `AnonConst`, we need to set the expected type by side
     /// effect. However, we do not want this as a general capability, so this interface restricts
     /// to the only allowed case.
-    pub fn feed_anon_const_type(self, key: LocalDefId, value: ty::EarlyBinder<Ty<'tcx>>) {
+    pub fn feed_anon_const_type(self, key: LocalDefId, value: ty::EarlyBinder<'tcx, Ty<'tcx>>) {
         debug_assert_eq!(self.def_kind(key), DefKind::AnonConst);
         TyCtxtFeed { tcx: self, key }.type_of(value)
     }
@@ -2741,7 +2741,7 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn impl_trait_ref(
         self,
         def_id: impl IntoQueryParam<DefId>,
-    ) -> Option<ty::EarlyBinder<ty::TraitRef<'tcx>>> {
+    ) -> Option<ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>>> {
         Some(self.impl_trait_header(def_id)?.trait_ref)
     }
 
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index d432aeada2c..b5b36cbd1ba 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -3,7 +3,9 @@ use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir::def_id::DefId;
 use tracing::{debug, instrument};
 
-pub use rustc_type_ir::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
+pub use rustc_type_ir::fold::{
+    shift_region, shift_vars, FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable,
+};
 
 ///////////////////////////////////////////////////////////////////////////
 // Some sample folders
@@ -412,103 +414,3 @@ impl<'tcx> TyCtxt<'tcx> {
         Binder::bind_with_vars(inner, bound_vars)
     }
 }
-
-///////////////////////////////////////////////////////////////////////////
-// Shifter
-//
-// Shifts the De Bruijn indices on all escaping bound vars by a
-// fixed amount. Useful in instantiation or when otherwise introducing
-// a binding level that is not intended to capture the existing bound
-// vars. See comment on `shift_vars_through_binders` method in
-// `rustc_middle/src/ty/generic_args.rs` for more details.
-
-struct Shifter<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    current_index: ty::DebruijnIndex,
-    amount: u32,
-}
-
-impl<'tcx> Shifter<'tcx> {
-    pub fn new(tcx: TyCtxt<'tcx>, amount: u32) -> Self {
-        Shifter { tcx, current_index: ty::INNERMOST, amount }
-    }
-}
-
-impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Shifter<'tcx> {
-    fn interner(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
-        &mut self,
-        t: ty::Binder<'tcx, T>,
-    ) -> ty::Binder<'tcx, T> {
-        self.current_index.shift_in(1);
-        let t = t.super_fold_with(self);
-        self.current_index.shift_out(1);
-        t
-    }
-
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        match *r {
-            ty::ReBound(debruijn, br) if debruijn >= self.current_index => {
-                let debruijn = debruijn.shifted_in(self.amount);
-                ty::Region::new_bound(self.tcx, debruijn, br)
-            }
-            _ => r,
-        }
-    }
-
-    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        match *ty.kind() {
-            ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => {
-                let debruijn = debruijn.shifted_in(self.amount);
-                Ty::new_bound(self.tcx, debruijn, bound_ty)
-            }
-
-            _ if ty.has_vars_bound_at_or_above(self.current_index) => ty.super_fold_with(self),
-            _ => ty,
-        }
-    }
-
-    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        if let ty::ConstKind::Bound(debruijn, bound_ct) = ct.kind()
-            && debruijn >= self.current_index
-        {
-            let debruijn = debruijn.shifted_in(self.amount);
-            ty::Const::new_bound(self.tcx, debruijn, bound_ct, ct.ty())
-        } else {
-            ct.super_fold_with(self)
-        }
-    }
-
-    fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
-        if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p }
-    }
-}
-
-pub fn shift_region<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    region: ty::Region<'tcx>,
-    amount: u32,
-) -> ty::Region<'tcx> {
-    match *region {
-        ty::ReBound(debruijn, br) if amount > 0 => {
-            ty::Region::new_bound(tcx, debruijn.shifted_in(amount), br)
-        }
-        _ => region,
-    }
-}
-
-pub fn shift_vars<'tcx, T>(tcx: TyCtxt<'tcx>, value: T, amount: u32) -> T
-where
-    T: TypeFoldable<TyCtxt<'tcx>>,
-{
-    debug!("shift_vars(value={:?}, amount={})", value, amount);
-
-    if amount == 0 || !value.has_escaping_bound_vars() {
-        return value;
-    }
-
-    value.fold_with(&mut Shifter::new(tcx, amount))
-}
diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs
index c7b15c64b08..7a516b9f2c8 100644
--- a/compiler/rustc_middle/src/ty/generic_args.rs
+++ b/compiler/rustc_middle/src/ty/generic_args.rs
@@ -1,10 +1,10 @@
 // Generic arguments.
 
 use crate::ty::codec::{TyDecoder, TyEncoder};
-use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
+use crate::ty::fold::{FallibleTypeFolder, TypeFoldable};
 use crate::ty::sty::{ClosureArgs, CoroutineArgs, CoroutineClosureArgs, InlineConstArgs};
-use crate::ty::visit::{TypeVisitable, TypeVisitableExt, TypeVisitor};
-use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
+use crate::ty::visit::{TypeVisitable, TypeVisitor};
+use crate::ty::{self, Lift, List, Ty, TyCtxt};
 
 use rustc_ast_ir::visit::VisitorResult;
 use rustc_ast_ir::walk_visitable_list;
@@ -12,19 +12,15 @@ use rustc_data_structures::intern::Interned;
 use rustc_errors::{DiagArgValue, IntoDiagArg};
 use rustc_hir::def_id::DefId;
 use rustc_macros::extension;
-use rustc_macros::{
-    Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable,
-};
+use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
 use rustc_serialize::{Decodable, Encodable};
 use rustc_type_ir::WithCachedTypeInfo;
 use smallvec::SmallVec;
-use tracing::debug;
 
 use core::intrinsics;
 use std::marker::PhantomData;
 use std::mem;
 use std::num::NonZero;
-use std::ops::Deref;
 use std::ptr::NonNull;
 
 pub type GenericArgKind<'tcx> = rustc_type_ir::GenericArgKind<TyCtxt<'tcx>>;
@@ -576,490 +572,6 @@ impl<'tcx, T: TypeVisitable<TyCtxt<'tcx>>> TypeVisitable<TyCtxt<'tcx>> for &'tcx
     }
 }
 
-/// Similar to [`super::Binder`] except that it tracks early bound generics, i.e. `struct Foo<T>(T)`
-/// needs `T` instantiated immediately. This type primarily exists to avoid forgetting to call
-/// `instantiate`.
-///
-/// If you don't have anything to `instantiate`, you may be looking for
-/// [`instantiate_identity`](EarlyBinder::instantiate_identity) or [`skip_binder`](EarlyBinder::skip_binder).
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
-#[derive(Encodable, Decodable, HashStable)]
-pub struct EarlyBinder<T> {
-    value: T,
-}
-
-/// For early binders, you should first call `instantiate` before using any visitors.
-impl<'tcx, T> !TypeFoldable<TyCtxt<'tcx>> for ty::EarlyBinder<T> {}
-impl<'tcx, T> !TypeVisitable<TyCtxt<'tcx>> for ty::EarlyBinder<T> {}
-
-impl<T> EarlyBinder<T> {
-    pub fn bind(value: T) -> EarlyBinder<T> {
-        EarlyBinder { value }
-    }
-
-    pub fn as_ref(&self) -> EarlyBinder<&T> {
-        EarlyBinder { value: &self.value }
-    }
-
-    pub fn map_bound_ref<F, U>(&self, f: F) -> EarlyBinder<U>
-    where
-        F: FnOnce(&T) -> U,
-    {
-        self.as_ref().map_bound(f)
-    }
-
-    pub fn map_bound<F, U>(self, f: F) -> EarlyBinder<U>
-    where
-        F: FnOnce(T) -> U,
-    {
-        let value = f(self.value);
-        EarlyBinder { value }
-    }
-
-    pub fn try_map_bound<F, U, E>(self, f: F) -> Result<EarlyBinder<U>, E>
-    where
-        F: FnOnce(T) -> Result<U, E>,
-    {
-        let value = f(self.value)?;
-        Ok(EarlyBinder { value })
-    }
-
-    pub fn rebind<U>(&self, value: U) -> EarlyBinder<U> {
-        EarlyBinder { value }
-    }
-
-    /// Skips the binder and returns the "bound" value.
-    /// This can be used to extract data that does not depend on generic parameters
-    /// (e.g., getting the `DefId` of the inner value or getting the number of
-    /// arguments of an `FnSig`). Otherwise, consider using
-    /// [`instantiate_identity`](EarlyBinder::instantiate_identity).
-    ///
-    /// To skip the binder on `x: &EarlyBinder<T>` to obtain `&T`, leverage
-    /// [`EarlyBinder::as_ref`](EarlyBinder::as_ref): `x.as_ref().skip_binder()`.
-    ///
-    /// See also [`Binder::skip_binder`](super::Binder::skip_binder), which is
-    /// the analogous operation on [`super::Binder`].
-    pub fn skip_binder(self) -> T {
-        self.value
-    }
-}
-
-impl<T> EarlyBinder<Option<T>> {
-    pub fn transpose(self) -> Option<EarlyBinder<T>> {
-        self.value.map(|value| EarlyBinder { value })
-    }
-}
-
-impl<'tcx, 's, I: IntoIterator> EarlyBinder<I>
-where
-    I::Item: TypeFoldable<TyCtxt<'tcx>>,
-{
-    pub fn iter_instantiated(
-        self,
-        tcx: TyCtxt<'tcx>,
-        args: &'s [GenericArg<'tcx>],
-    ) -> IterInstantiated<'s, 'tcx, I> {
-        IterInstantiated { it: self.value.into_iter(), tcx, args }
-    }
-
-    /// Similar to [`instantiate_identity`](EarlyBinder::instantiate_identity),
-    /// but on an iterator of `TypeFoldable` values.
-    pub fn instantiate_identity_iter(self) -> I::IntoIter {
-        self.value.into_iter()
-    }
-}
-
-pub struct IterInstantiated<'s, 'tcx, I: IntoIterator> {
-    it: I::IntoIter,
-    tcx: TyCtxt<'tcx>,
-    args: &'s [GenericArg<'tcx>],
-}
-
-impl<'tcx, I: IntoIterator> Iterator for IterInstantiated<'_, 'tcx, I>
-where
-    I::Item: TypeFoldable<TyCtxt<'tcx>>,
-{
-    type Item = I::Item;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        Some(EarlyBinder { value: self.it.next()? }.instantiate(self.tcx, self.args))
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.it.size_hint()
-    }
-}
-
-impl<'tcx, I: IntoIterator> DoubleEndedIterator for IterInstantiated<'_, 'tcx, I>
-where
-    I::IntoIter: DoubleEndedIterator,
-    I::Item: TypeFoldable<TyCtxt<'tcx>>,
-{
-    fn next_back(&mut self) -> Option<Self::Item> {
-        Some(EarlyBinder { value: self.it.next_back()? }.instantiate(self.tcx, self.args))
-    }
-}
-
-impl<'tcx, I: IntoIterator> ExactSizeIterator for IterInstantiated<'_, 'tcx, I>
-where
-    I::IntoIter: ExactSizeIterator,
-    I::Item: TypeFoldable<TyCtxt<'tcx>>,
-{
-}
-
-impl<'tcx, 's, I: IntoIterator> EarlyBinder<I>
-where
-    I::Item: Deref,
-    <I::Item as Deref>::Target: Copy + TypeFoldable<TyCtxt<'tcx>>,
-{
-    pub fn iter_instantiated_copied(
-        self,
-        tcx: TyCtxt<'tcx>,
-        args: &'s [GenericArg<'tcx>],
-    ) -> IterInstantiatedCopied<'s, 'tcx, I> {
-        IterInstantiatedCopied { it: self.value.into_iter(), tcx, args }
-    }
-
-    /// Similar to [`instantiate_identity`](EarlyBinder::instantiate_identity),
-    /// but on an iterator of values that deref to a `TypeFoldable`.
-    pub fn instantiate_identity_iter_copied(
-        self,
-    ) -> impl Iterator<Item = <I::Item as Deref>::Target> {
-        self.value.into_iter().map(|v| *v)
-    }
-}
-
-pub struct IterInstantiatedCopied<'a, 'tcx, I: IntoIterator> {
-    it: I::IntoIter,
-    tcx: TyCtxt<'tcx>,
-    args: &'a [GenericArg<'tcx>],
-}
-
-impl<'tcx, I: IntoIterator> Iterator for IterInstantiatedCopied<'_, 'tcx, I>
-where
-    I::Item: Deref,
-    <I::Item as Deref>::Target: Copy + TypeFoldable<TyCtxt<'tcx>>,
-{
-    type Item = <I::Item as Deref>::Target;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        self.it.next().map(|value| EarlyBinder { value: *value }.instantiate(self.tcx, self.args))
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.it.size_hint()
-    }
-}
-
-impl<'tcx, I: IntoIterator> DoubleEndedIterator for IterInstantiatedCopied<'_, 'tcx, I>
-where
-    I::IntoIter: DoubleEndedIterator,
-    I::Item: Deref,
-    <I::Item as Deref>::Target: Copy + TypeFoldable<TyCtxt<'tcx>>,
-{
-    fn next_back(&mut self) -> Option<Self::Item> {
-        self.it
-            .next_back()
-            .map(|value| EarlyBinder { value: *value }.instantiate(self.tcx, self.args))
-    }
-}
-
-impl<'tcx, I: IntoIterator> ExactSizeIterator for IterInstantiatedCopied<'_, 'tcx, I>
-where
-    I::IntoIter: ExactSizeIterator,
-    I::Item: Deref,
-    <I::Item as Deref>::Target: Copy + TypeFoldable<TyCtxt<'tcx>>,
-{
-}
-
-pub struct EarlyBinderIter<T> {
-    t: T,
-}
-
-impl<T: IntoIterator> EarlyBinder<T> {
-    pub fn transpose_iter(self) -> EarlyBinderIter<T::IntoIter> {
-        EarlyBinderIter { t: self.value.into_iter() }
-    }
-}
-
-impl<T: Iterator> Iterator for EarlyBinderIter<T> {
-    type Item = EarlyBinder<T::Item>;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        self.t.next().map(|value| EarlyBinder { value })
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.t.size_hint()
-    }
-}
-
-impl<'tcx, T: TypeFoldable<TyCtxt<'tcx>>> ty::EarlyBinder<T> {
-    pub fn instantiate(self, tcx: TyCtxt<'tcx>, args: &[GenericArg<'tcx>]) -> T {
-        let mut folder = ArgFolder { tcx, args, binders_passed: 0 };
-        self.value.fold_with(&mut folder)
-    }
-
-    /// Makes the identity replacement `T0 => T0, ..., TN => TN`.
-    /// Conceptually, this converts universally bound variables into placeholders
-    /// when inside of a given item.
-    ///
-    /// For example, consider `for<T> fn foo<T>(){ .. }`:
-    /// - Outside of `foo`, `T` is bound (represented by the presence of `EarlyBinder`).
-    /// - Inside of the body of `foo`, we treat `T` as a placeholder by calling
-    /// `instantiate_identity` to discharge the `EarlyBinder`.
-    pub fn instantiate_identity(self) -> T {
-        self.value
-    }
-
-    /// Returns the inner value, but only if it contains no bound vars.
-    pub fn no_bound_vars(self) -> Option<T> {
-        if !self.value.has_param() { Some(self.value) } else { None }
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////
-// The actual instantiation engine itself is a type folder.
-
-struct ArgFolder<'a, 'tcx> {
-    tcx: TyCtxt<'tcx>,
-    args: &'a [GenericArg<'tcx>],
-
-    /// Number of region binders we have passed through while doing the instantiation
-    binders_passed: u32,
-}
-
-impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ArgFolder<'a, 'tcx> {
-    #[inline]
-    fn interner(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
-        &mut self,
-        t: ty::Binder<'tcx, T>,
-    ) -> ty::Binder<'tcx, T> {
-        self.binders_passed += 1;
-        let t = t.super_fold_with(self);
-        self.binders_passed -= 1;
-        t
-    }
-
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        #[cold]
-        #[inline(never)]
-        fn region_param_out_of_range(data: ty::EarlyParamRegion, args: &[GenericArg<'_>]) -> ! {
-            bug!(
-                "Region parameter out of range when instantiating in region {} (index={}, args = {:?})",
-                data.name,
-                data.index,
-                args,
-            )
-        }
-
-        #[cold]
-        #[inline(never)]
-        fn region_param_invalid(data: ty::EarlyParamRegion, other: GenericArgKind<'_>) -> ! {
-            bug!(
-                "Unexpected parameter {:?} when instantiating in region {} (index={})",
-                other,
-                data.name,
-                data.index
-            )
-        }
-
-        // Note: This routine only handles regions that are bound on
-        // type declarations and other outer declarations, not those
-        // bound in *fn types*. Region instantiation of the bound
-        // regions that appear in a function signature is done using
-        // the specialized routine `ty::replace_late_regions()`.
-        match *r {
-            ty::ReEarlyParam(data) => {
-                let rk = self.args.get(data.index as usize).map(|k| k.unpack());
-                match rk {
-                    Some(GenericArgKind::Lifetime(lt)) => self.shift_region_through_binders(lt),
-                    Some(other) => region_param_invalid(data, other),
-                    None => region_param_out_of_range(data, self.args),
-                }
-            }
-            ty::ReBound(..)
-            | ty::ReLateParam(_)
-            | ty::ReStatic
-            | ty::RePlaceholder(_)
-            | ty::ReErased
-            | ty::ReError(_) => r,
-            ty::ReVar(_) => bug!("unexpected region: {r:?}"),
-        }
-    }
-
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        if !t.has_param() {
-            return t;
-        }
-
-        match *t.kind() {
-            ty::Param(p) => self.ty_for_param(p, t),
-            _ => t.super_fold_with(self),
-        }
-    }
-
-    fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        if let ty::ConstKind::Param(p) = c.kind() {
-            self.const_for_param(p, c)
-        } else {
-            c.super_fold_with(self)
-        }
-    }
-}
-
-impl<'a, 'tcx> ArgFolder<'a, 'tcx> {
-    fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> {
-        // Look up the type in the args. It really should be in there.
-        let opt_ty = self.args.get(p.index as usize).map(|k| k.unpack());
-        let ty = match opt_ty {
-            Some(GenericArgKind::Type(ty)) => ty,
-            Some(kind) => self.type_param_expected(p, source_ty, kind),
-            None => self.type_param_out_of_range(p, source_ty),
-        };
-
-        self.shift_vars_through_binders(ty)
-    }
-
-    #[cold]
-    #[inline(never)]
-    fn type_param_expected(&self, p: ty::ParamTy, ty: Ty<'tcx>, kind: GenericArgKind<'tcx>) -> ! {
-        bug!(
-            "expected type for `{:?}` ({:?}/{}) but found {:?} when instantiating, args={:?}",
-            p,
-            ty,
-            p.index,
-            kind,
-            self.args,
-        )
-    }
-
-    #[cold]
-    #[inline(never)]
-    fn type_param_out_of_range(&self, p: ty::ParamTy, ty: Ty<'tcx>) -> ! {
-        bug!(
-            "type parameter `{:?}` ({:?}/{}) out of range when instantiating, args={:?}",
-            p,
-            ty,
-            p.index,
-            self.args,
-        )
-    }
-
-    fn const_for_param(&self, p: ParamConst, source_ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        // Look up the const in the args. It really should be in there.
-        let opt_ct = self.args.get(p.index as usize).map(|k| k.unpack());
-        let ct = match opt_ct {
-            Some(GenericArgKind::Const(ct)) => ct,
-            Some(kind) => self.const_param_expected(p, source_ct, kind),
-            None => self.const_param_out_of_range(p, source_ct),
-        };
-
-        self.shift_vars_through_binders(ct)
-    }
-
-    #[cold]
-    #[inline(never)]
-    fn const_param_expected(
-        &self,
-        p: ty::ParamConst,
-        ct: ty::Const<'tcx>,
-        kind: GenericArgKind<'tcx>,
-    ) -> ! {
-        bug!(
-            "expected const for `{:?}` ({:?}/{}) but found {:?} when instantiating args={:?}",
-            p,
-            ct,
-            p.index,
-            kind,
-            self.args,
-        )
-    }
-
-    #[cold]
-    #[inline(never)]
-    fn const_param_out_of_range(&self, p: ty::ParamConst, ct: ty::Const<'tcx>) -> ! {
-        bug!(
-            "const parameter `{:?}` ({:?}/{}) out of range when instantiating args={:?}",
-            p,
-            ct,
-            p.index,
-            self.args,
-        )
-    }
-
-    /// It is sometimes necessary to adjust the De Bruijn indices during instantiation. This occurs
-    /// when we are instantating a type with escaping bound vars into a context where we have
-    /// passed through binders. That's quite a mouthful. Let's see an example:
-    ///
-    /// ```
-    /// type Func<A> = fn(A);
-    /// type MetaFunc = for<'a> fn(Func<&'a i32>);
-    /// ```
-    ///
-    /// The type `MetaFunc`, when fully expanded, will be
-    /// ```ignore (illustrative)
-    /// for<'a> fn(fn(&'a i32))
-    /// //      ^~ ^~ ^~~
-    /// //      |  |  |
-    /// //      |  |  DebruijnIndex of 2
-    /// //      Binders
-    /// ```
-    /// Here the `'a` lifetime is bound in the outer function, but appears as an argument of the
-    /// inner one. Therefore, that appearance will have a DebruijnIndex of 2, because we must skip
-    /// over the inner binder (remember that we count De Bruijn indices from 1). However, in the
-    /// definition of `MetaFunc`, the binder is not visible, so the type `&'a i32` will have a
-    /// De Bruijn index of 1. It's only during the instantiation that we can see we must increase the
-    /// depth by 1 to account for the binder that we passed through.
-    ///
-    /// As a second example, consider this twist:
-    ///
-    /// ```
-    /// type FuncTuple<A> = (A,fn(A));
-    /// type MetaFuncTuple = for<'a> fn(FuncTuple<&'a i32>);
-    /// ```
-    ///
-    /// Here the final type will be:
-    /// ```ignore (illustrative)
-    /// for<'a> fn((&'a i32, fn(&'a i32)))
-    /// //          ^~~         ^~~
-    /// //          |           |
-    /// //   DebruijnIndex of 1 |
-    /// //               DebruijnIndex of 2
-    /// ```
-    /// As indicated in the diagram, here the same type `&'a i32` is instantiated once, but in the
-    /// first case we do not increase the De Bruijn index and in the second case we do. The reason
-    /// is that only in the second case have we passed through a fn binder.
-    fn shift_vars_through_binders<T: TypeFoldable<TyCtxt<'tcx>>>(&self, val: T) -> T {
-        debug!(
-            "shift_vars(val={:?}, binders_passed={:?}, has_escaping_bound_vars={:?})",
-            val,
-            self.binders_passed,
-            val.has_escaping_bound_vars()
-        );
-
-        if self.binders_passed == 0 || !val.has_escaping_bound_vars() {
-            return val;
-        }
-
-        let result = ty::fold::shift_vars(TypeFolder::interner(self), val, self.binders_passed);
-        debug!("shift_vars: shifted result = {:?}", result);
-
-        result
-    }
-
-    fn shift_region_through_binders(&self, region: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        if self.binders_passed == 0 || !region.has_escaping_bound_vars() {
-            return region;
-        }
-        ty::fold::shift_region(self.tcx, region, self.binders_passed)
-    }
-}
-
 /// Stores the user-given args to reach some fully qualified path
 /// (e.g., `<T>::Item` or `<T as Trait>::Item`).
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 69a86bda43b..89ba8cd2ad4 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -88,7 +88,7 @@ impl GenericParamDef {
     pub fn default_value<'tcx>(
         &self,
         tcx: TyCtxt<'tcx>,
-    ) -> Option<EarlyBinder<ty::GenericArg<'tcx>>> {
+    ) -> Option<EarlyBinder<'tcx, ty::GenericArg<'tcx>>> {
         match self.kind {
             GenericParamDefKind::Type { has_default, .. } if has_default => {
                 Some(tcx.type_of(self.def_id).map_bound(|t| t.into()))
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 7da7f69a954..a887047f62f 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -764,7 +764,7 @@ impl<'tcx> Instance<'tcx> {
         self.def.has_polymorphic_mir_body().then_some(self.args)
     }
 
-    pub fn instantiate_mir<T>(&self, tcx: TyCtxt<'tcx>, v: EarlyBinder<&T>) -> T
+    pub fn instantiate_mir<T>(&self, tcx: TyCtxt<'tcx>, v: EarlyBinder<'tcx, &T>) -> T
     where
         T: TypeFoldable<TyCtxt<'tcx>> + Copy,
     {
@@ -782,7 +782,7 @@ impl<'tcx> Instance<'tcx> {
         &self,
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        v: EarlyBinder<T>,
+        v: EarlyBinder<'tcx, T>,
     ) -> T
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
@@ -800,7 +800,7 @@ impl<'tcx> Instance<'tcx> {
         &self,
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        v: EarlyBinder<T>,
+        v: EarlyBinder<'tcx, T>,
     ) -> Result<T, NormalizationError<'tcx>>
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 79cfeb71d47..f24074cb472 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -114,9 +114,9 @@ pub use self::rvalue_scopes::RvalueScopes;
 pub use self::sty::{
     AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig,
     ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, CoroutineClosureArgs,
-    CoroutineClosureArgsParts, CoroutineClosureSignature, FnSig, GenSig, InlineConstArgs,
-    InlineConstArgsParts, ParamConst, ParamTy, PolyFnSig, TyKind, TypeAndMut, UpvarArgs,
-    VarianceDiagInfo,
+    CoroutineClosureArgsParts, CoroutineClosureSignature, EarlyBinder, FnSig, GenSig,
+    InlineConstArgs, InlineConstArgsParts, ParamConst, ParamTy, PolyFnSig, TyKind, TypeAndMut,
+    UpvarArgs, VarianceDiagInfo,
 };
 pub use self::trait_def::TraitDef;
 pub use self::typeck_results::{
@@ -266,7 +266,7 @@ pub struct ImplHeader<'tcx> {
 
 #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 pub struct ImplTraitHeader<'tcx> {
-    pub trait_ref: ty::EarlyBinder<ty::TraitRef<'tcx>>,
+    pub trait_ref: ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>>,
     pub polarity: ImplPolarity,
     pub safety: hir::Safety,
 }
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index e2cfabfdafa..fb16cf5bd36 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -125,7 +125,7 @@ impl<'tcx> TyCtxt<'tcx> {
         self,
         param_args: GenericArgsRef<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        value: EarlyBinder<T>,
+        value: EarlyBinder<'tcx, T>,
     ) -> T
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
@@ -143,7 +143,7 @@ impl<'tcx> TyCtxt<'tcx> {
         self,
         param_args: GenericArgsRef<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        value: EarlyBinder<T>,
+        value: EarlyBinder<'tcx, T>,
     ) -> Result<T, NormalizationError<'tcx>>
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs
index 571c6e918dc..f394b3c990c 100644
--- a/compiler/rustc_middle/src/ty/parameterized.rs
+++ b/compiler/rustc_middle/src/ty/parameterized.rs
@@ -33,8 +33,8 @@ impl<T: ParameterizedOverTcx> ParameterizedOverTcx for ty::Binder<'static, T> {
     type Value<'tcx> = ty::Binder<'tcx, T::Value<'tcx>>;
 }
 
-impl<T: ParameterizedOverTcx> ParameterizedOverTcx for ty::EarlyBinder<T> {
-    type Value<'tcx> = ty::EarlyBinder<T::Value<'tcx>>;
+impl<T: ParameterizedOverTcx> ParameterizedOverTcx for ty::EarlyBinder<'static, T> {
+    type Value<'tcx> = ty::EarlyBinder<'tcx, T::Value<'tcx>>;
 }
 
 #[macro_export]
diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs
index 0807cbf91d1..4e85af90170 100644
--- a/compiler/rustc_middle/src/ty/region.rs
+++ b/compiler/rustc_middle/src/ty/region.rs
@@ -138,6 +138,14 @@ impl<'tcx> Region<'tcx> {
 }
 
 impl<'tcx> rustc_type_ir::inherent::Region<TyCtxt<'tcx>> for Region<'tcx> {
+    fn new_bound(
+        interner: TyCtxt<'tcx>,
+        debruijn: ty::DebruijnIndex,
+        var: ty::BoundRegion,
+    ) -> Self {
+        Region::new_bound(interner, debruijn, var)
+    }
+
     fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
         Region::new_bound(tcx, debruijn, ty::BoundRegion { var, kind: ty::BoundRegionKind::BrAnon })
     }
@@ -327,6 +335,12 @@ pub struct EarlyParamRegion {
     pub name: Symbol,
 }
 
+impl rustc_type_ir::inherent::ParamLike for EarlyParamRegion {
+    fn index(self) -> u32 {
+        self.index
+    }
+}
+
 impl std::fmt::Debug for EarlyParamRegion {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         write!(f, "{}/#{}", self.name, self.index)
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 40f3db89df5..5cf96d29837 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -40,6 +40,7 @@ pub type TypeAndMut<'tcx> = ir::TypeAndMut<TyCtxt<'tcx>>;
 pub type AliasTy<'tcx> = ir::AliasTy<TyCtxt<'tcx>>;
 pub type FnSig<'tcx> = ir::FnSig<TyCtxt<'tcx>>;
 pub type Binder<'tcx, T> = ir::Binder<TyCtxt<'tcx>, T>;
+pub type EarlyBinder<'tcx, T> = ir::EarlyBinder<TyCtxt<'tcx>, T>;
 
 pub trait Article {
     fn article(&self) -> &'static str;
@@ -954,6 +955,12 @@ pub struct ParamTy {
     pub name: Symbol,
 }
 
+impl rustc_type_ir::inherent::ParamLike for ParamTy {
+    fn index(self) -> u32 {
+        self.index
+    }
+}
+
 impl<'tcx> ParamTy {
     pub fn new(index: u32, name: Symbol) -> ParamTy {
         ParamTy { index, name }
@@ -982,6 +989,12 @@ pub struct ParamConst {
     pub name: Symbol,
 }
 
+impl rustc_type_ir::inherent::ParamLike for ParamConst {
+    fn index(self) -> u32 {
+        self.index
+    }
+}
+
 impl ParamConst {
     pub fn new(index: u32, name: Symbol) -> ParamConst {
         ParamConst { index, name }
@@ -1423,6 +1436,10 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
         Ty::new_var(tcx, vid)
     }
 
+    fn new_bound(interner: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundTy) -> Self {
+        Ty::new_bound(interner, debruijn, var)
+    }
+
     fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
         Ty::new_bound(tcx, debruijn, ty::BoundTy { var, kind: ty::BoundTyKind::Anon })
     }
@@ -2055,7 +2072,7 @@ impl<'tcx> Ty<'tcx> {
     fn async_destructor_combinator(
         tcx: TyCtxt<'tcx>,
         lang_item: LangItem,
-    ) -> ty::EarlyBinder<Ty<'tcx>> {
+    ) -> ty::EarlyBinder<'tcx, Ty<'tcx>> {
         tcx.fn_sig(tcx.require_lang_item(lang_item, None))
             .map_bound(|fn_sig| fn_sig.output().no_bound_vars().unwrap())
     }
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 5a3d90221eb..cacaa859d52 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -694,7 +694,7 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn coroutine_hidden_types(
         self,
         def_id: DefId,
-    ) -> impl Iterator<Item = ty::EarlyBinder<Ty<'tcx>>> {
+    ) -> impl Iterator<Item = ty::EarlyBinder<'tcx, Ty<'tcx>>> {
         let coroutine_layout = self.mir_coroutine_witnesses(def_id);
         coroutine_layout
             .as_ref()
@@ -709,7 +709,7 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn bound_coroutine_hidden_types(
         self,
         def_id: DefId,
-    ) -> impl Iterator<Item = ty::EarlyBinder<ty::Binder<'tcx, Ty<'tcx>>>> {
+    ) -> impl Iterator<Item = ty::EarlyBinder<'tcx, ty::Binder<'tcx, Ty<'tcx>>>> {
         let coroutine_layout = self.mir_coroutine_witnesses(def_id);
         coroutine_layout
             .as_ref()
diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs
index 79f36cfe569..4ae475d35d1 100644
--- a/compiler/rustc_middle/src/values.rs
+++ b/compiler/rustc_middle/src/values.rs
@@ -23,7 +23,7 @@ impl<'tcx> Value<TyCtxt<'tcx>> for Ty<'_> {
     }
 }
 
-impl<'tcx> Value<TyCtxt<'tcx>> for Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> {
+impl<'tcx> Value<TyCtxt<'tcx>> for Result<ty::EarlyBinder<'_, Ty<'_>>, CyclePlaceholder> {
     fn from_cycle_error(_tcx: TyCtxt<'tcx>, _: &CycleError, guar: ErrorGuaranteed) -> Self {
         Err(CyclePlaceholder(guar))
     }
@@ -111,7 +111,7 @@ impl<'tcx> Value<TyCtxt<'tcx>> for Representability {
     }
 }
 
-impl<'tcx> Value<TyCtxt<'tcx>> for ty::EarlyBinder<Ty<'_>> {
+impl<'tcx> Value<TyCtxt<'tcx>> for ty::EarlyBinder<'_, Ty<'_>> {
     fn from_cycle_error(
         tcx: TyCtxt<'tcx>,
         cycle_error: &CycleError,
@@ -121,7 +121,7 @@ impl<'tcx> Value<TyCtxt<'tcx>> for ty::EarlyBinder<Ty<'_>> {
     }
 }
 
-impl<'tcx> Value<TyCtxt<'tcx>> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>> {
+impl<'tcx> Value<TyCtxt<'tcx>> for ty::EarlyBinder<'_, ty::Binder<'_, ty::FnSig<'_>>> {
     fn from_cycle_error(
         tcx: TyCtxt<'tcx>,
         cycle_error: &CycleError,
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
index a511989d972..66708def00f 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -194,7 +194,7 @@ where
     }
 }
 
-impl<'tcx, S, V> Stable<'tcx> for ty::EarlyBinder<S>
+impl<'tcx, S, V> Stable<'tcx> for ty::EarlyBinder<'tcx, S>
 where
     S: Stable<'tcx, T = V>,
 {
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 77ac4be35ea..87c8b1cda50 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -2097,7 +2097,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
     let args = translate_args(selcx.infcx, param_env, impl_def_id, args, assoc_ty.defining_node);
     let ty = tcx.type_of(assoc_ty.item.def_id);
     let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst);
-    let term: ty::EarlyBinder<ty::Term<'tcx>> = if is_const {
+    let term: ty::EarlyBinder<'tcx, ty::Term<'tcx>> = if is_const {
         let did = assoc_ty.item.def_id;
         let identity_args = crate::traits::GenericArgs::identity_for_item(tcx, did);
         let uv = ty::UnevaluatedConst::new(did, identity_args);
diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs
index 67ffb8a58b5..58447f6d6a3 100644
--- a/compiler/rustc_ty_utils/src/consts.rs
+++ b/compiler/rustc_ty_utils/src/consts.rs
@@ -398,10 +398,10 @@ impl<'a, 'tcx> visit::Visitor<'a, 'tcx> for IsThirPolymorphic<'a, 'tcx> {
 }
 
 /// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead.
-fn thir_abstract_const(
-    tcx: TyCtxt<'_>,
+fn thir_abstract_const<'tcx>(
+    tcx: TyCtxt<'tcx>,
     def: LocalDefId,
-) -> Result<Option<ty::EarlyBinder<ty::Const<'_>>>, ErrorGuaranteed> {
+) -> Result<Option<ty::EarlyBinder<'tcx, ty::Const<'tcx>>>, ErrorGuaranteed> {
     if !tcx.features().generic_const_exprs {
         return Ok(None);
     }
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 617e8a54365..38950c97c9d 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -77,7 +77,7 @@ fn defaultness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Defaultness {
 fn adt_sized_constraint<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: DefId,
-) -> Option<ty::EarlyBinder<Ty<'tcx>>> {
+) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
     if let Some(def_id) = def_id.as_local() {
         if let ty::Representability::Infinite(_) = tcx.representability(def_id) {
             return None;
@@ -253,7 +253,7 @@ fn param_env_reveal_all_normalized(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamE
 fn self_ty_of_trait_impl_enabling_order_dep_trait_object_hack(
     tcx: TyCtxt<'_>,
     def_id: DefId,
-) -> Option<EarlyBinder<Ty<'_>>> {
+) -> Option<EarlyBinder<'_, Ty<'_>>> {
     let impl_ =
         tcx.impl_trait_header(def_id).unwrap_or_else(|| bug!("called on inherent impl {def_id:?}"));
 
diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml
index cef3f4e8ce0..18a09067a2c 100644
--- a/compiler/rustc_type_ir/Cargo.toml
+++ b/compiler/rustc_type_ir/Cargo.toml
@@ -15,6 +15,7 @@ rustc_serialize = { path = "../rustc_serialize", optional = true }
 rustc_span = { path = "../rustc_span", optional = true }
 rustc_type_ir_macros = { path = "../rustc_type_ir_macros" }
 smallvec = { version = "1.8.1", default-features = false }
+tracing = "0.1"
 # tidy-alphabetical-end
 
 [features]
diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs
index 5336b915a1d..e50d59ba5f0 100644
--- a/compiler/rustc_type_ir/src/binder.rs
+++ b/compiler/rustc_type_ir/src/binder.rs
@@ -1,12 +1,14 @@
 use std::fmt::Debug;
 use std::hash::Hash;
+use std::marker::PhantomData;
 use std::ops::{ControlFlow, Deref};
 
 #[cfg(feature = "nightly")]
-use rustc_macros::HashStable_NoContext;
+use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
 use rustc_serialize::Decodable;
+use tracing::debug;
 
-use crate::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
+use crate::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
 use crate::inherent::*;
 use crate::lift::Lift;
 use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
@@ -338,3 +340,516 @@ impl<I: Interner> TypeVisitor<I> for ValidateBoundVars<I> {
         ControlFlow::Continue(())
     }
 }
+
+/// Similar to [`super::Binder`] except that it tracks early bound generics, i.e. `struct Foo<T>(T)`
+/// needs `T` instantiated immediately. This type primarily exists to avoid forgetting to call
+/// `instantiate`.
+///
+/// If you don't have anything to `instantiate`, you may be looking for
+/// [`instantiate_identity`](EarlyBinder::instantiate_identity) or [`skip_binder`](EarlyBinder::skip_binder).
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = "T: Clone"),
+    Copy(bound = "T: Copy"),
+    PartialEq(bound = "T: PartialEq"),
+    Eq(bound = "T: Eq"),
+    Ord(bound = "T: Ord"),
+    PartialOrd(bound = "T: Ord"),
+    Hash(bound = "T: Hash"),
+    Debug(bound = "T: Debug")
+)]
+#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
+pub struct EarlyBinder<I: Interner, T> {
+    value: T,
+    _tcx: PhantomData<I>,
+}
+
+/// For early binders, you should first call `instantiate` before using any visitors.
+#[cfg(feature = "nightly")]
+impl<I: Interner, T> !TypeFoldable<I> for ty::EarlyBinder<I, T> {}
+
+/// For early binders, you should first call `instantiate` before using any visitors.
+#[cfg(feature = "nightly")]
+impl<I: Interner, T> !TypeVisitable<I> for ty::EarlyBinder<I, T> {}
+
+impl<I: Interner, T> EarlyBinder<I, T> {
+    pub fn bind(value: T) -> EarlyBinder<I, T> {
+        EarlyBinder { value, _tcx: PhantomData }
+    }
+
+    pub fn as_ref(&self) -> EarlyBinder<I, &T> {
+        EarlyBinder { value: &self.value, _tcx: PhantomData }
+    }
+
+    pub fn map_bound_ref<F, U>(&self, f: F) -> EarlyBinder<I, U>
+    where
+        F: FnOnce(&T) -> U,
+    {
+        self.as_ref().map_bound(f)
+    }
+
+    pub fn map_bound<F, U>(self, f: F) -> EarlyBinder<I, U>
+    where
+        F: FnOnce(T) -> U,
+    {
+        let value = f(self.value);
+        EarlyBinder { value, _tcx: PhantomData }
+    }
+
+    pub fn try_map_bound<F, U, E>(self, f: F) -> Result<EarlyBinder<I, U>, E>
+    where
+        F: FnOnce(T) -> Result<U, E>,
+    {
+        let value = f(self.value)?;
+        Ok(EarlyBinder { value, _tcx: PhantomData })
+    }
+
+    pub fn rebind<U>(&self, value: U) -> EarlyBinder<I, U> {
+        EarlyBinder { value, _tcx: PhantomData }
+    }
+
+    /// Skips the binder and returns the "bound" value.
+    /// This can be used to extract data that does not depend on generic parameters
+    /// (e.g., getting the `DefId` of the inner value or getting the number of
+    /// arguments of an `FnSig`). Otherwise, consider using
+    /// [`instantiate_identity`](EarlyBinder::instantiate_identity).
+    ///
+    /// To skip the binder on `x: &EarlyBinder<I, T>` to obtain `&T`, leverage
+    /// [`EarlyBinder::as_ref`](EarlyBinder::as_ref): `x.as_ref().skip_binder()`.
+    ///
+    /// See also [`Binder::skip_binder`](super::Binder::skip_binder), which is
+    /// the analogous operation on [`super::Binder`].
+    pub fn skip_binder(self) -> T {
+        self.value
+    }
+}
+
+impl<I: Interner, T> EarlyBinder<I, Option<T>> {
+    pub fn transpose(self) -> Option<EarlyBinder<I, T>> {
+        self.value.map(|value| EarlyBinder { value, _tcx: PhantomData })
+    }
+}
+
+impl<'s, I: Interner, Iter: IntoIterator> EarlyBinder<I, Iter>
+where
+    Iter::Item: TypeFoldable<I>,
+{
+    pub fn iter_instantiated(
+        self,
+        tcx: I,
+        args: &'s [I::GenericArg],
+    ) -> IterInstantiated<'s, I, Iter> {
+        IterInstantiated { it: self.value.into_iter(), tcx, args }
+    }
+
+    /// Similar to [`instantiate_identity`](EarlyBinder::instantiate_identity),
+    /// but on an iterator of `TypeFoldable` values.
+    pub fn instantiate_identity_iter(self) -> Iter::IntoIter {
+        self.value.into_iter()
+    }
+}
+
+pub struct IterInstantiated<'s, I: Interner, Iter: IntoIterator> {
+    it: Iter::IntoIter,
+    tcx: I,
+    args: &'s [I::GenericArg],
+}
+
+impl<I: Interner, Iter: IntoIterator> Iterator for IterInstantiated<'_, I, Iter>
+where
+    Iter::Item: TypeFoldable<I>,
+{
+    type Item = Iter::Item;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        Some(
+            EarlyBinder { value: self.it.next()?, _tcx: PhantomData }
+                .instantiate(self.tcx, self.args),
+        )
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.it.size_hint()
+    }
+}
+
+impl<I: Interner, Iter: IntoIterator> DoubleEndedIterator for IterInstantiated<'_, I, Iter>
+where
+    Iter::IntoIter: DoubleEndedIterator,
+    Iter::Item: TypeFoldable<I>,
+{
+    fn next_back(&mut self) -> Option<Self::Item> {
+        Some(
+            EarlyBinder { value: self.it.next_back()?, _tcx: PhantomData }
+                .instantiate(self.tcx, self.args),
+        )
+    }
+}
+
+impl<I: Interner, Iter: IntoIterator> ExactSizeIterator for IterInstantiated<'_, I, Iter>
+where
+    Iter::IntoIter: ExactSizeIterator,
+    Iter::Item: TypeFoldable<I>,
+{
+}
+
+impl<'s, I: Interner, Iter: IntoIterator> EarlyBinder<I, Iter>
+where
+    Iter::Item: Deref,
+    <Iter::Item as Deref>::Target: Copy + TypeFoldable<I>,
+{
+    pub fn iter_instantiated_copied(
+        self,
+        tcx: I,
+        args: &'s [I::GenericArg],
+    ) -> IterInstantiatedCopied<'s, I, Iter> {
+        IterInstantiatedCopied { it: self.value.into_iter(), tcx, args }
+    }
+
+    /// Similar to [`instantiate_identity`](EarlyBinder::instantiate_identity),
+    /// but on an iterator of values that deref to a `TypeFoldable`.
+    pub fn instantiate_identity_iter_copied(
+        self,
+    ) -> impl Iterator<Item = <Iter::Item as Deref>::Target> {
+        self.value.into_iter().map(|v| *v)
+    }
+}
+
+pub struct IterInstantiatedCopied<'a, I: Interner, Iter: IntoIterator> {
+    it: Iter::IntoIter,
+    tcx: I,
+    args: &'a [I::GenericArg],
+}
+
+impl<I: Interner, Iter: IntoIterator> Iterator for IterInstantiatedCopied<'_, I, Iter>
+where
+    Iter::Item: Deref,
+    <Iter::Item as Deref>::Target: Copy + TypeFoldable<I>,
+{
+    type Item = <Iter::Item as Deref>::Target;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.it.next().map(|value| {
+            EarlyBinder { value: *value, _tcx: PhantomData }.instantiate(self.tcx, self.args)
+        })
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.it.size_hint()
+    }
+}
+
+impl<I: Interner, Iter: IntoIterator> DoubleEndedIterator for IterInstantiatedCopied<'_, I, Iter>
+where
+    Iter::IntoIter: DoubleEndedIterator,
+    Iter::Item: Deref,
+    <Iter::Item as Deref>::Target: Copy + TypeFoldable<I>,
+{
+    fn next_back(&mut self) -> Option<Self::Item> {
+        self.it.next_back().map(|value| {
+            EarlyBinder { value: *value, _tcx: PhantomData }.instantiate(self.tcx, self.args)
+        })
+    }
+}
+
+impl<I: Interner, Iter: IntoIterator> ExactSizeIterator for IterInstantiatedCopied<'_, I, Iter>
+where
+    Iter::IntoIter: ExactSizeIterator,
+    Iter::Item: Deref,
+    <Iter::Item as Deref>::Target: Copy + TypeFoldable<I>,
+{
+}
+
+pub struct EarlyBinderIter<I, T> {
+    t: T,
+    _tcx: PhantomData<I>,
+}
+
+impl<I: Interner, T: IntoIterator> EarlyBinder<I, T> {
+    pub fn transpose_iter(self) -> EarlyBinderIter<I, T::IntoIter> {
+        EarlyBinderIter { t: self.value.into_iter(), _tcx: PhantomData }
+    }
+}
+
+impl<I: Interner, T: Iterator> Iterator for EarlyBinderIter<I, T> {
+    type Item = EarlyBinder<I, T::Item>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.t.next().map(|value| EarlyBinder { value, _tcx: PhantomData })
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.t.size_hint()
+    }
+}
+
+impl<I: Interner, T: TypeFoldable<I>> ty::EarlyBinder<I, T> {
+    pub fn instantiate(self, tcx: I, args: &[I::GenericArg]) -> T {
+        let mut folder = ArgFolder { tcx, args, binders_passed: 0 };
+        self.value.fold_with(&mut folder)
+    }
+
+    /// Makes the identity replacement `T0 => T0, ..., TN => TN`.
+    /// Conceptually, this converts universally bound variables into placeholders
+    /// when inside of a given item.
+    ///
+    /// For example, consider `for<T> fn foo<T>(){ .. }`:
+    /// - Outside of `foo`, `T` is bound (represented by the presence of `EarlyBinder`).
+    /// - Inside of the body of `foo`, we treat `T` as a placeholder by calling
+    /// `instantiate_identity` to discharge the `EarlyBinder`.
+    pub fn instantiate_identity(self) -> T {
+        self.value
+    }
+
+    /// Returns the inner value, but only if it contains no bound vars.
+    pub fn no_bound_vars(self) -> Option<T> {
+        if !self.value.has_param() { Some(self.value) } else { None }
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// The actual instantiation engine itself is a type folder.
+
+struct ArgFolder<'a, I: Interner> {
+    tcx: I,
+    args: &'a [I::GenericArg],
+
+    /// Number of region binders we have passed through while doing the instantiation
+    binders_passed: u32,
+}
+
+impl<'a, I: Interner> TypeFolder<I> for ArgFolder<'a, I> {
+    #[inline]
+    fn interner(&self) -> I {
+        self.tcx
+    }
+
+    fn fold_binder<T: TypeFoldable<I>>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> {
+        self.binders_passed += 1;
+        let t = t.super_fold_with(self);
+        self.binders_passed -= 1;
+        t
+    }
+
+    fn fold_region(&mut self, r: I::Region) -> I::Region {
+        // Note: This routine only handles regions that are bound on
+        // type declarations and other outer declarations, not those
+        // bound in *fn types*. Region instantiation of the bound
+        // regions that appear in a function signature is done using
+        // the specialized routine `ty::replace_late_regions()`.
+        match r.kind() {
+            ty::ReEarlyParam(data) => {
+                let rk = self.args.get(data.index() as usize).map(|k| k.kind());
+                match rk {
+                    Some(ty::GenericArgKind::Lifetime(lt)) => self.shift_region_through_binders(lt),
+                    Some(other) => self.region_param_expected(data, r, other),
+                    None => self.region_param_out_of_range(data, r),
+                }
+            }
+            ty::ReBound(..)
+            | ty::ReLateParam(_)
+            | ty::ReStatic
+            | ty::RePlaceholder(_)
+            | ty::ReErased
+            | ty::ReError(_) => r,
+            ty::ReVar(_) => panic!("unexpected region: {r:?}"),
+        }
+    }
+
+    fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
+        if !t.has_param() {
+            return t;
+        }
+
+        match t.kind() {
+            ty::Param(p) => self.ty_for_param(p, t),
+            _ => t.super_fold_with(self),
+        }
+    }
+
+    fn fold_const(&mut self, c: I::Const) -> I::Const {
+        if let ty::ConstKind::Param(p) = c.kind() {
+            self.const_for_param(p, c)
+        } else {
+            c.super_fold_with(self)
+        }
+    }
+}
+
+impl<'a, I: Interner> ArgFolder<'a, I> {
+    fn ty_for_param(&self, p: I::ParamTy, source_ty: I::Ty) -> I::Ty {
+        // Look up the type in the args. It really should be in there.
+        let opt_ty = self.args.get(p.index() as usize).map(|k| k.kind());
+        let ty = match opt_ty {
+            Some(ty::GenericArgKind::Type(ty)) => ty,
+            Some(kind) => self.type_param_expected(p, source_ty, kind),
+            None => self.type_param_out_of_range(p, source_ty),
+        };
+
+        self.shift_vars_through_binders(ty)
+    }
+
+    #[cold]
+    #[inline(never)]
+    fn type_param_expected(&self, p: I::ParamTy, ty: I::Ty, kind: ty::GenericArgKind<I>) -> ! {
+        panic!(
+            "expected type for `{:?}` ({:?}/{}) but found {:?} when instantiating, args={:?}",
+            p,
+            ty,
+            p.index(),
+            kind,
+            self.args,
+        )
+    }
+
+    #[cold]
+    #[inline(never)]
+    fn type_param_out_of_range(&self, p: I::ParamTy, ty: I::Ty) -> ! {
+        panic!(
+            "type parameter `{:?}` ({:?}/{}) out of range when instantiating, args={:?}",
+            p,
+            ty,
+            p.index(),
+            self.args,
+        )
+    }
+
+    fn const_for_param(&self, p: I::ParamConst, source_ct: I::Const) -> I::Const {
+        // Look up the const in the args. It really should be in there.
+        let opt_ct = self.args.get(p.index() as usize).map(|k| k.kind());
+        let ct = match opt_ct {
+            Some(ty::GenericArgKind::Const(ct)) => ct,
+            Some(kind) => self.const_param_expected(p, source_ct, kind),
+            None => self.const_param_out_of_range(p, source_ct),
+        };
+
+        self.shift_vars_through_binders(ct)
+    }
+
+    #[cold]
+    #[inline(never)]
+    fn const_param_expected(
+        &self,
+        p: I::ParamConst,
+        ct: I::Const,
+        kind: ty::GenericArgKind<I>,
+    ) -> ! {
+        panic!(
+            "expected const for `{:?}` ({:?}/{}) but found {:?} when instantiating args={:?}",
+            p,
+            ct,
+            p.index(),
+            kind,
+            self.args,
+        )
+    }
+
+    #[cold]
+    #[inline(never)]
+    fn const_param_out_of_range(&self, p: I::ParamConst, ct: I::Const) -> ! {
+        panic!(
+            "const parameter `{:?}` ({:?}/{}) out of range when instantiating args={:?}",
+            p,
+            ct,
+            p.index(),
+            self.args,
+        )
+    }
+
+    #[cold]
+    #[inline(never)]
+    fn region_param_expected(
+        &self,
+        ebr: I::EarlyParamRegion,
+        r: I::Region,
+        kind: ty::GenericArgKind<I>,
+    ) -> ! {
+        panic!(
+            "expected region for `{:?}` ({:?}/{}) but found {:?} when instantiating args={:?}",
+            ebr,
+            r,
+            ebr.index(),
+            kind,
+            self.args,
+        )
+    }
+
+    #[cold]
+    #[inline(never)]
+    fn region_param_out_of_range(&self, ebr: I::EarlyParamRegion, r: I::Region) -> ! {
+        panic!(
+            "const parameter `{:?}` ({:?}/{}) out of range when instantiating args={:?}",
+            ebr,
+            r,
+            ebr.index(),
+            self.args,
+        )
+    }
+
+    /// It is sometimes necessary to adjust the De Bruijn indices during instantiation. This occurs
+    /// when we are instantating a type with escaping bound vars into a context where we have
+    /// passed through binders. That's quite a mouthful. Let's see an example:
+    ///
+    /// ```
+    /// type Func<A> = fn(A);
+    /// type MetaFunc = for<'a> fn(Func<&'a i32>);
+    /// ```
+    ///
+    /// The type `MetaFunc`, when fully expanded, will be
+    /// ```ignore (illustrative)
+    /// for<'a> fn(fn(&'a i32))
+    /// //      ^~ ^~ ^~~
+    /// //      |  |  |
+    /// //      |  |  DebruijnIndex of 2
+    /// //      Binders
+    /// ```
+    /// Here the `'a` lifetime is bound in the outer function, but appears as an argument of the
+    /// inner one. Therefore, that appearance will have a DebruijnIndex of 2, because we must skip
+    /// over the inner binder (remember that we count De Bruijn indices from 1). However, in the
+    /// definition of `MetaFunc`, the binder is not visible, so the type `&'a i32` will have a
+    /// De Bruijn index of 1. It's only during the instantiation that we can see we must increase the
+    /// depth by 1 to account for the binder that we passed through.
+    ///
+    /// As a second example, consider this twist:
+    ///
+    /// ```
+    /// type FuncTuple<A> = (A,fn(A));
+    /// type MetaFuncTuple = for<'a> fn(FuncTuple<&'a i32>);
+    /// ```
+    ///
+    /// Here the final type will be:
+    /// ```ignore (illustrative)
+    /// for<'a> fn((&'a i32, fn(&'a i32)))
+    /// //          ^~~         ^~~
+    /// //          |           |
+    /// //   DebruijnIndex of 1 |
+    /// //               DebruijnIndex of 2
+    /// ```
+    /// As indicated in the diagram, here the same type `&'a i32` is instantiated once, but in the
+    /// first case we do not increase the De Bruijn index and in the second case we do. The reason
+    /// is that only in the second case have we passed through a fn binder.
+    fn shift_vars_through_binders<T: TypeFoldable<I>>(&self, val: T) -> T {
+        debug!(
+            "shift_vars(val={:?}, binders_passed={:?}, has_escaping_bound_vars={:?})",
+            val,
+            self.binders_passed,
+            val.has_escaping_bound_vars()
+        );
+
+        if self.binders_passed == 0 || !val.has_escaping_bound_vars() {
+            return val;
+        }
+
+        let result = ty::fold::shift_vars(TypeFolder::interner(self), val, self.binders_passed);
+        debug!("shift_vars: shifted result = {:?}", result);
+
+        result
+    }
+
+    fn shift_region_through_binders(&self, region: I::Region) -> I::Region {
+        if self.binders_passed == 0 || !region.has_escaping_bound_vars() {
+            return region;
+        }
+        ty::fold::shift_region(self.tcx, region, self.binders_passed)
+    }
+}
diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs
index 405aba30241..501311ff72f 100644
--- a/compiler/rustc_type_ir/src/fold.rs
+++ b/compiler/rustc_type_ir/src/fold.rs
@@ -47,8 +47,10 @@
 
 use rustc_index::{Idx, IndexVec};
 use std::mem;
+use tracing::debug;
 
-use crate::visit::TypeVisitable;
+use crate::inherent::*;
+use crate::visit::{TypeVisitable, TypeVisitableExt as _};
 use crate::{self as ty, Interner, Lrc};
 
 #[cfg(feature = "nightly")]
@@ -325,3 +327,95 @@ impl<I: Interner, T: TypeFoldable<I>, Ix: Idx> TypeFoldable<I> for IndexVec<Ix,
         self.raw.try_fold_with(folder).map(IndexVec::from_raw)
     }
 }
+
+///////////////////////////////////////////////////////////////////////////
+// Shifter
+//
+// Shifts the De Bruijn indices on all escaping bound vars by a
+// fixed amount. Useful in instantiation or when otherwise introducing
+// a binding level that is not intended to capture the existing bound
+// vars. See comment on `shift_vars_through_binders` method in
+// `rustc_middle/src/ty/generic_args.rs` for more details.
+
+struct Shifter<I: Interner> {
+    tcx: I,
+    current_index: ty::DebruijnIndex,
+    amount: u32,
+}
+
+impl<I: Interner> Shifter<I> {
+    pub fn new(tcx: I, amount: u32) -> Self {
+        Shifter { tcx, current_index: ty::INNERMOST, amount }
+    }
+}
+
+impl<I: Interner> TypeFolder<I> for Shifter<I> {
+    fn interner(&self) -> I {
+        self.tcx
+    }
+
+    fn fold_binder<T: TypeFoldable<I>>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> {
+        self.current_index.shift_in(1);
+        let t = t.super_fold_with(self);
+        self.current_index.shift_out(1);
+        t
+    }
+
+    fn fold_region(&mut self, r: I::Region) -> I::Region {
+        match r.kind() {
+            ty::ReBound(debruijn, br) if debruijn >= self.current_index => {
+                let debruijn = debruijn.shifted_in(self.amount);
+                Region::new_bound(self.tcx, debruijn, br)
+            }
+            _ => r,
+        }
+    }
+
+    fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
+        match ty.kind() {
+            ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => {
+                let debruijn = debruijn.shifted_in(self.amount);
+                Ty::new_bound(self.tcx, debruijn, bound_ty)
+            }
+
+            _ if ty.has_vars_bound_at_or_above(self.current_index) => ty.super_fold_with(self),
+            _ => ty,
+        }
+    }
+
+    fn fold_const(&mut self, ct: I::Const) -> I::Const {
+        match ct.kind() {
+            ty::ConstKind::Bound(debruijn, bound_ct) if debruijn >= self.current_index => {
+                let debruijn = debruijn.shifted_in(self.amount);
+                Const::new_bound(self.tcx, debruijn, bound_ct, ct.ty())
+            }
+            _ => ct.super_fold_with(self),
+        }
+    }
+
+    fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate {
+        if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p }
+    }
+}
+
+pub fn shift_region<I: Interner>(tcx: I, region: I::Region, amount: u32) -> I::Region {
+    match region.kind() {
+        ty::ReBound(debruijn, br) if amount > 0 => {
+            Region::new_bound(tcx, debruijn.shifted_in(amount), br)
+        }
+        _ => region,
+    }
+}
+
+pub fn shift_vars<I: Interner, T>(tcx: I, value: T, amount: u32) -> T
+where
+    T: TypeFoldable<I>,
+{
+    debug!("shift_vars(value={:?}, amount={})", value, amount);
+
+    if amount == 0 || !value.has_escaping_bound_vars() {
+        return value;
+    }
+
+    value.fold_with(&mut Shifter::new(tcx, amount))
+}
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index 77fe30a4660..e7e893f27da 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -29,6 +29,8 @@ pub trait Ty<I: Interner<Ty = Self>>:
 
     fn new_var(interner: I, var: ty::TyVid) -> Self;
 
+    fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundTy) -> Self;
+
     fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self;
 
     fn new_alias(interner: I, kind: ty::AliasTyKind, alias_ty: ty::AliasTy<I>) -> Self;
@@ -65,7 +67,10 @@ pub trait Region<I: Interner<Region = Self>>:
     + Into<I::GenericArg>
     + IntoKind<Kind = ty::RegionKind<I>>
     + Flags
+    + TypeVisitable<I>
 {
+    fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundRegion) -> Self;
+
     fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self;
 
     fn new_static(interner: I) -> Self;
@@ -87,6 +92,8 @@ pub trait Const<I: Interner<Const = Self>>:
 
     fn new_var(interner: I, var: ty::ConstVid, ty: I::Ty) -> Self;
 
+    fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundConst, ty: I::Ty) -> Self;
+
     fn new_anon_bound(
         interner: I,
         debruijn: ty::DebruijnIndex,
@@ -162,3 +169,7 @@ pub trait BoundVarLike<I: Interner> {
 
     fn assert_eq(self, var: I::BoundVarKind);
 }
+
+pub trait ParamLike {
+    fn index(self) -> u32;
+}
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index c77414afc52..e49db171a53 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -7,26 +7,22 @@ use crate::inherent::*;
 use crate::ir_print::IrPrint;
 use crate::solve::inspect::CanonicalGoalEvaluationStep;
 use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
-use crate::{
-    AliasTerm, AliasTermKind, AliasTy, AliasTyKind, CanonicalVarInfo, CoercePredicate,
-    DebugWithInfcx, ExistentialProjection, ExistentialTraitRef, FnSig, GenericArgKind,
-    NormalizesTo, ProjectionPredicate, SubtypePredicate, TermKind, TraitPredicate, TraitRef,
-};
+use crate::{self as ty, DebugWithInfcx};
 
 pub trait Interner:
     Sized
     + Copy
-    + IrPrint<AliasTy<Self>>
-    + IrPrint<AliasTerm<Self>>
-    + IrPrint<TraitRef<Self>>
-    + IrPrint<TraitPredicate<Self>>
-    + IrPrint<ExistentialTraitRef<Self>>
-    + IrPrint<ExistentialProjection<Self>>
-    + IrPrint<ProjectionPredicate<Self>>
-    + IrPrint<NormalizesTo<Self>>
-    + IrPrint<SubtypePredicate<Self>>
-    + IrPrint<CoercePredicate<Self>>
-    + IrPrint<FnSig<Self>>
+    + IrPrint<ty::AliasTy<Self>>
+    + IrPrint<ty::AliasTerm<Self>>
+    + IrPrint<ty::TraitRef<Self>>
+    + IrPrint<ty::TraitPredicate<Self>>
+    + IrPrint<ty::ExistentialTraitRef<Self>>
+    + IrPrint<ty::ExistentialProjection<Self>>
+    + IrPrint<ty::ProjectionPredicate<Self>>
+    + IrPrint<ty::NormalizesTo<Self>>
+    + IrPrint<ty::SubtypePredicate<Self>>
+    + IrPrint<ty::CoercePredicate<Self>>
+    + IrPrint<ty::FnSig<Self>>
 {
     type DefId: Copy + Debug + Hash + Eq + TypeVisitable<Self>;
     type AdtDef: Copy + Debug + Hash + Eq;
@@ -39,9 +35,9 @@ pub trait Interner:
         + DebugWithInfcx<Self>
         + Hash
         + Eq
-        + IntoKind<Kind = GenericArgKind<Self>>
+        + IntoKind<Kind = ty::GenericArgKind<Self>>
         + TypeVisitable<Self>;
-    type Term: Copy + Debug + Hash + Eq + IntoKind<Kind = TermKind<Self>> + TypeVisitable<Self>;
+    type Term: Copy + Debug + Hash + Eq + IntoKind<Kind = ty::TermKind<Self>> + TypeVisitable<Self>;
 
     type BoundVarKinds: Copy
         + Debug
@@ -51,7 +47,7 @@ pub trait Interner:
         + Default;
     type BoundVarKind: Copy + Debug + Hash + Eq;
 
-    type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator<Item = CanonicalVarInfo<Self>>;
+    type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator<Item = ty::CanonicalVarInfo<Self>>;
     type PredefinedOpaques: Copy + Debug + Hash + Eq;
     type DefiningOpaqueTypes: Copy + Debug + Hash + Default + Eq + TypeVisitable<Self>;
     type ExternalConstraints: Copy + Debug + Hash + Eq;
@@ -65,7 +61,7 @@ pub trait Interner:
     type Ty: Ty<Self>;
     type Tys: Tys<Self>;
     type FnInputTys: Copy + Debug + Hash + Eq + Deref<Target = [Self::Ty]> + TypeVisitable<Self>;
-    type ParamTy: Copy + Debug + Hash + Eq;
+    type ParamTy: Copy + Debug + Hash + Eq + ParamLike;
     type BoundTy: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
     type PlaceholderTy: PlaceholderLike;
 
@@ -81,14 +77,14 @@ pub trait Interner:
     // Kinds of consts
     type Const: Const<Self>;
     type PlaceholderConst: PlaceholderLike;
-    type ParamConst: Copy + Debug + Hash + Eq;
+    type ParamConst: Copy + Debug + Hash + Eq + ParamLike;
     type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
     type ValueConst: Copy + Debug + Hash + Eq;
     type ExprConst: Copy + DebugWithInfcx<Self> + Hash + Eq;
 
     // Kinds of regions
     type Region: Region<Self>;
-    type EarlyParamRegion: Copy + Debug + Hash + Eq;
+    type EarlyParamRegion: Copy + Debug + Hash + Eq + ParamLike;
     type LateParamRegion: Copy + Debug + Hash + Eq;
     type BoundRegion: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
     type PlaceholderRegion: PlaceholderLike;
@@ -99,23 +95,23 @@ pub trait Interner:
     type Clause: Clause<Self>;
     type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags;
 
-    fn mk_canonical_var_infos(self, infos: &[CanonicalVarInfo<Self>]) -> Self::CanonicalVars;
+    fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars;
 
     type GenericsOf: GenericsOf<Self>;
     fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf;
 
     // FIXME: Remove after uplifting `EarlyBinder`
-    fn type_of_instantiated(self, def_id: Self::DefId, args: Self::GenericArgs) -> Self::Ty;
+    fn type_of(self, def_id: Self::DefId) -> ty::EarlyBinder<Self, Self::Ty>;
 
-    fn alias_ty_kind(self, alias: AliasTy<Self>) -> AliasTyKind;
+    fn alias_ty_kind(self, alias: ty::AliasTy<Self>) -> ty::AliasTyKind;
 
-    fn alias_term_kind(self, alias: AliasTerm<Self>) -> AliasTermKind;
+    fn alias_term_kind(self, alias: ty::AliasTerm<Self>) -> ty::AliasTermKind;
 
     fn trait_ref_and_own_args_for_alias(
         self,
         def_id: Self::DefId,
         args: Self::GenericArgs,
-    ) -> (TraitRef<Self>, Self::OwnItemArgs);
+    ) -> (ty::TraitRef<Self>, Self::OwnItemArgs);
 
     fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs;
 
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 4a461b5b5f3..217c056d0ba 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -1,6 +1,6 @@
 #![cfg_attr(
     feature = "nightly",
-    feature(associated_type_defaults, min_specialization, never_type, rustc_attrs)
+    feature(associated_type_defaults, min_specialization, never_type, rustc_attrs, negative_impls)
 )]
 #![allow(rustc::usage_of_ty_tykind)]
 #![cfg_attr(feature = "nightly", allow(internal_features))]
diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs
index 4e12c6b3d67..48a6f79993c 100644
--- a/compiler/rustc_type_ir/src/predicate.rs
+++ b/compiler/rustc_type_ir/src/predicate.rs
@@ -567,7 +567,7 @@ impl<I: Interner> AliasTerm<I> {
                 I::Const::new_unevaluated(
                     interner,
                     ty::UnevaluatedConst::new(self.def_id, self.args),
-                    interner.type_of_instantiated(self.def_id, self.args),
+                    interner.type_of(self.def_id).instantiate(interner, &self.args),
                 )
                 .into()
             }
diff --git a/config.example.toml b/config.example.toml
index 228521747ed..61655dad638 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -904,9 +904,6 @@
 # on linux
 #src-tarball = true
 
-# Whether to allow failures when building tools
-#missing-tools = false
-
 # List of compression formats to use when generating dist tarballs. The list of
 # formats is provided to rust-installer, which must support all of them.
 #
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 1e3ed0f7c49..9a527073602 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -137,10 +137,13 @@
 //!
 //! [^extern_fn]: this remains true for any argument/return types and any other ABI: `extern "abi" fn` (_e.g._, `extern "system" fn`)
 //!
+//! Under some conditions the above types `T` are also null pointer optimized when wrapped in a [`Result`][result_repr].
+//!
 //! [`Box<U>`]: ../../std/boxed/struct.Box.html
 //! [`num::NonZero*`]: crate::num
 //! [`ptr::NonNull<U>`]: crate::ptr::NonNull
 //! [function call ABI]: ../primitive.fn.html#abi-compatibility
+//! [result_repr]: crate::result#representation
 //!
 //! This is called the "null pointer optimization" or NPO.
 //!
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index 4c6dc4bba43..f8cdcc000c5 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -228,6 +228,27 @@
 //! [`Err(E)`]: Err
 //! [io::Error]: ../../std/io/struct.Error.html "io::Error"
 //!
+//! # Representation
+//!
+//! In some cases, [`Result<T, E>`] will gain the same size, alignment, and ABI
+//! guarantees as [`Option<U>`] has. One of either the `T` or `E` type must be a
+//! type that qualifies for the `Option` [representation guarantees][opt-rep],
+//! and the *other* type must meet all of the following conditions:
+//! * Is a zero-sized type with alignment 1 (a "1-ZST").
+//! * Has no fields.
+//! * Does not have the `#[non_exhaustive]` attribute.
+//!
+//! For example, `NonZeroI32` qualifies for the `Option` representation
+//! guarantees, and `()` is a zero-sized type with alignment 1, no fields, and
+//! it isn't `non_exhaustive`. This means that both `Result<NonZeroI32, ()>` and
+//! `Result<(), NonZeroI32>` have the same size, alignment, and ABI guarantees
+//! as `Option<NonZeroI32>`. The only difference is the implied semantics:
+//! * `Option<NonZeroI32>` is "a non-zero i32 might be present"
+//! * `Result<NonZeroI32, ()>` is "a non-zero i32 success result, if any"
+//! * `Result<(), NonZeroI32>` is "a non-zero i32 error result, if any"
+//!
+//! [opt-rep]: ../option/index.html#representation "Option Representation"
+//!
 //! # Method overview
 //!
 //! In addition to working with pattern matching, [`Result`] provides a
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index d13dc9d1d17..70d32f2f6d9 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -314,7 +314,6 @@ pub struct Config {
     pub save_toolstates: Option<PathBuf>,
     pub print_step_timings: bool,
     pub print_step_rusage: bool,
-    pub missing_tools: bool, // FIXME: Deprecated field. Remove it at 2024.
 
     // Fallback musl-root for all targets
     pub musl_root: Option<PathBuf>,
@@ -905,7 +904,6 @@ define_config! {
         sign_folder: Option<String> = "sign-folder",
         upload_addr: Option<String> = "upload-addr",
         src_tarball: Option<bool> = "src-tarball",
-        missing_tools: Option<bool> = "missing-tools",
         compression_formats: Option<Vec<String>> = "compression-formats",
         compression_profile: Option<String> = "compression-profile",
         include_mingw_linker: Option<bool> = "include-mingw-linker",
@@ -1936,7 +1934,6 @@ impl Config {
                 sign_folder,
                 upload_addr,
                 src_tarball,
-                missing_tools,
                 compression_formats,
                 compression_profile,
                 include_mingw_linker,
@@ -1946,7 +1943,6 @@ impl Config {
             config.dist_compression_formats = compression_formats;
             set(&mut config.dist_compression_profile, compression_profile);
             set(&mut config.rust_dist_src, src_tarball);
-            set(&mut config.missing_tools, missing_tools);
             set(&mut config.dist_include_mingw_linker, include_mingw_linker)
         }
 
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index 2f9eaf51c34..bfe3622e40d 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -190,4 +190,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Warning,
         summary: "`rust.lld` has a new default value of `true` on `x86_64-unknown-linux-gnu`. Starting at stage1, `rust-lld` will thus be this target's default linker. No config changes should be necessary.",
     },
+    ChangeInfo {
+        change_id: 125535,
+        severity: ChangeSeverity::Warning,
+        summary: "Removed `dist.missing-tools` configuration as it was deprecated long time ago.",
+    },
 ];
diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs
index 22ab576b077..c79b377727a 100644
--- a/src/tools/lint-docs/src/lib.rs
+++ b/src/tools/lint-docs/src/lib.rs
@@ -441,10 +441,19 @@ impl<'a> LintExtractor<'a> {
         fs::write(&tempfile, source)
             .map_err(|e| format!("failed to write {}: {}", tempfile.display(), e))?;
         let mut cmd = Command::new(self.rustc_path);
-        if options.contains(&"edition2015") {
+        if options.contains(&"edition2024") {
+            cmd.arg("--edition=2024");
+        } else if options.contains(&"edition2021") {
+            cmd.arg("--edition=2021");
+        } else if options.contains(&"edition2018") {
+            cmd.arg("--edition=2018");
+        } else if options.contains(&"edition2015") {
             cmd.arg("--edition=2015");
+        } else if options.contains(&"edition") {
+            panic!("lint-docs: unknown edition");
         } else {
-            cmd.arg("--edition=2018");
+            // defaults to latest edition
+            cmd.arg("--edition=2021");
         }
         cmd.arg("--error-format=json");
         cmd.arg("--target").arg(self.rustc_target);
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 9a6ae18abea..55d65fe8987 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -18,7 +18,6 @@ run-make/cdylib-fewer-symbols/Makefile
 run-make/cdylib/Makefile
 run-make/codegen-options-parsing/Makefile
 run-make/comment-section/Makefile
-run-make/compile-stdin/Makefile
 run-make/compiler-lookup-paths-2/Makefile
 run-make/compiler-lookup-paths/Makefile
 run-make/compiler-rt-works-on-mingw/Makefile
diff --git a/tests/run-make/compile-stdin/Makefile b/tests/run-make/compile-stdin/Makefile
deleted file mode 100644
index b3d7cc777a0..00000000000
--- a/tests/run-make/compile-stdin/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-# When provided standard input piped directly into rustc, this test checks that the compilation completes successfully and that the output can be executed.
-# See https://github.com/rust-lang/rust/pull/28805
-
-# ignore-cross-compile
-include ../tools.mk
-
-all:
-	echo 'fn main(){}' | $(RUSTC) -
-	$(call RUN,rust_out)
diff --git a/tests/run-make/compile-stdin/rmake.rs b/tests/run-make/compile-stdin/rmake.rs
new file mode 100644
index 00000000000..f93080dfdc4
--- /dev/null
+++ b/tests/run-make/compile-stdin/rmake.rs
@@ -0,0 +1,13 @@
+// When provided standard input piped directly into rustc, this test checks that the compilation
+// completes successfully and that the output can be executed.
+//
+// See <https://github.com/rust-lang/rust/pull/28805>.
+
+//@ ignore-cross-compile
+
+use run_make_support::{run, rustc};
+
+fn main() {
+    rustc().arg("-").stdin("fn main() {}").run();
+    run("rust_out");
+}