about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock33
-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/mir/syntax.rs4
-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_mir_transform/src/validate.rs26
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/ty.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs64
-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
m---------library/backtrace0
-rw-r--r--library/core/src/option.rs3
-rw-r--r--library/core/src/result.rs21
-rw-r--r--library/core/src/str/count.rs2
-rw-r--r--library/std/Cargo.toml4
-rw-r--r--src/bootstrap/src/core/config/config.rs4
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs5
-rwxr-xr-xsrc/ci/docker/run.sh1
-rw-r--r--src/ci/github-actions/jobs.yml6
-rwxr-xr-xsrc/ci/scripts/verify-line-endings.sh22
-rw-r--r--src/librustdoc/clean/types.rs7
-rw-r--r--src/librustdoc/html/format.rs29
-rw-r--r--src/librustdoc/html/render/mod.rs29
-rw-r--r--src/librustdoc/html/render/print_item.rs13
-rw-r--r--src/tools/lint-docs/src/lib.rs13
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/tests/panic/mir-validation.stderr2
-rw-r--r--src/tools/run-make-support/src/diff/mod.rs5
-rw-r--r--src/tools/run-make-support/src/lib.rs67
-rw-r--r--src/tools/run-make-support/src/rustdoc.rs7
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt2
-rw-r--r--src/tools/tidy/src/ui_tests.rs8
-rw-r--r--tests/crashes/123255.rs13
-rw-r--r--tests/crashes/123276.rs25
-rw-r--r--tests/crashes/123887.rs15
-rw-r--r--tests/crashes/125013-1.rs5
-rw-r--r--tests/crashes/125013-2.rs16
-rw-r--r--tests/crashes/125014.rs17
-rw-r--r--tests/crashes/125059.rs12
-rw-r--r--tests/crashes/125323.rs6
-rw-r--r--tests/crashes/125476.rs4
-rw-r--r--tests/crashes/125512.rs10
-rw-r--r--tests/crashes/125553.rs15
-rw-r--r--tests/crashes/125556.rs14
-rw-r--r--tests/run-make/compile-stdin/Makefile9
-rw-r--r--tests/run-make/compile-stdin/rmake.rs13
-rw-r--r--tests/run-make/rustdoc-verify-output-files/Makefile32
-rw-r--r--tests/run-make/rustdoc-verify-output-files/rmake.rs49
-rw-r--r--tests/rustdoc/const-display.rs6
-rw-r--r--tests/ui/const-generics/generic_const_exprs/ice-125520-layout-mismatch-mulwithoverflow.rs27
-rw-r--r--tests/ui/const-generics/generic_const_exprs/ice-125520-layout-mismatch-mulwithoverflow.stderr125
-rw-r--r--tests/ui/const-generics/issues/issue-105821.rs2
-rw-r--r--tests/ui/higher-ranked/leak-check/leak-check-in-selection-5-ambig.rs28
-rw-r--r--tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.next.stderr22
-rw-r--r--tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.old.stderr22
-rw-r--r--tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.rs32
-rw-r--r--tests/ui/traits/next-solver/normalize/ambig-goal-infer-in-type-oulives.rs29
99 files changed, 1623 insertions, 881 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 92e6a22b4b9..6e86f6c02f1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -8,8 +8,17 @@ version = "0.21.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
 dependencies = [
+ "gimli 0.28.1",
+]
+
+[[package]]
+name = "addr2line"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
+dependencies = [
  "compiler_builtins",
- "gimli",
+ "gimli 0.29.0",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
 ]
@@ -287,7 +296,7 @@ version = "0.3.71"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d"
 dependencies = [
- "addr2line",
+ "addr2line 0.21.0",
  "cc",
  "cfg-if",
  "libc",
@@ -1576,6 +1585,17 @@ dependencies = [
 ]
 
 [[package]]
+name = "gimli"
+version = "0.29.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
+dependencies = [
+ "compiler_builtins",
+ "rustc-std-workspace-alloc",
+ "rustc-std-workspace-core",
+]
+
+[[package]]
 name = "glob"
 version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3234,7 +3254,7 @@ dependencies = [
 name = "run_make_support"
 version = "0.0.0"
 dependencies = [
- "gimli",
+ "gimli 0.28.1",
  "object 0.34.0",
  "regex",
  "similar",
@@ -4686,6 +4706,7 @@ dependencies = [
  "rustc_span",
  "rustc_type_ir_macros",
  "smallvec",
+ "tracing",
 ]
 
 [[package]]
@@ -5129,7 +5150,7 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
 name = "std"
 version = "0.0.0"
 dependencies = [
- "addr2line",
+ "addr2line 0.22.0",
  "alloc",
  "cfg-if",
  "compiler_builtins",
@@ -5408,7 +5429,7 @@ version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4db52ee8fec06e119b692ef3dd2c4cf621a99204c1b8c47407870ed050305b9b"
 dependencies = [
- "gimli",
+ "gimli 0.28.1",
  "hashbrown",
  "object 0.32.2",
  "tracing",
@@ -5908,7 +5929,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "37a19a21a537f635c16c7576f22d0f2f7d63353c1337ad4ce0d8001c7952a25b"
 dependencies = [
  "compiler_builtins",
- "gimli",
+ "gimli 0.28.1",
  "rustc-std-workspace-core",
 ]
 
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/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 2b28496faec..2d485211433 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -1008,8 +1008,8 @@ pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>;
 /// element:
 ///
 ///  - [`Downcast`](ProjectionElem::Downcast): This projection sets the place's variant index to the
-///    given one, and makes no other changes. A `Downcast` projection on a place with its variant
-///    index already set is not well-formed.
+///    given one, and makes no other changes. A `Downcast` projection must always be followed
+///    immediately by a `Field` projection.
 ///  - [`Field`](ProjectionElem::Field): `Field` projections take their parent place and create a
 ///    place referring to one of the fields of the type. The resulting address is the parent
 ///    address, plus the offset of the field. The type becomes the type of the field. If the parent
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_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index 66cc65de647..6df32169eec 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -689,8 +689,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                         if Some(adt_def.did()) == self.tcx.lang_items().dyn_metadata() {
                             self.fail(
                                 location,
-                                format!("You can't project to field {f:?} of `DynMetadata` because \
-                                         layout is weird and thinks it doesn't have fields."),
+                                format!(
+                                    "You can't project to field {f:?} of `DynMetadata` because \
+                                         layout is weird and thinks it doesn't have fields."
+                                ),
                             );
                         }
 
@@ -839,7 +841,25 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
             && cntxt != PlaceContext::NonUse(NonUseContext::VarDebugInfo)
             && place.projection[1..].contains(&ProjectionElem::Deref)
         {
-            self.fail(location, format!("{place:?}, has deref at the wrong place"));
+            self.fail(
+                location,
+                format!("place {place:?} has deref as a later projection (it is only permitted as the first projection)"),
+            );
+        }
+
+        // Ensure all downcast projections are followed by field projections.
+        let mut projections_iter = place.projection.iter();
+        while let Some(proj) = projections_iter.next() {
+            if matches!(proj, ProjectionElem::Downcast(..)) {
+                if !matches!(projections_iter.next(), Some(ProjectionElem::Field(..))) {
+                    self.fail(
+                        location,
+                        format!(
+                            "place {place:?} has `Downcast` projection not followed by `Field`"
+                        ),
+                    );
+                }
+            }
         }
 
         self.super_place(place, cntxt, location);
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/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
index 9590a82c067..f6ec6549084 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
@@ -99,6 +99,13 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
             previous call to `try_evaluate_added_goals!`"
         );
 
+        // We only check for leaks from universes which were entered inside
+        // of the query.
+        self.infcx.leak_check(self.max_input_universe, None).map_err(|e| {
+            trace!(?e, "failed the leak check");
+            NoSolution
+        })?;
+
         // When normalizing, we've replaced the expected term with an unconstrained
         // inference variable. This means that we dropped information which could
         // have been important. We handle this by instead returning the nested goals
@@ -121,7 +128,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         };
 
         let external_constraints =
-            self.compute_external_query_constraints(normalization_nested_goals)?;
+            self.compute_external_query_constraints(certainty, normalization_nested_goals);
         let (var_values, mut external_constraints) =
             (self.var_values, external_constraints).fold_with(&mut EagerResolver::new(self.infcx));
         // Remove any trivial region constraints once we've resolved regions
@@ -170,30 +177,37 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     #[instrument(level = "trace", skip(self), ret)]
     fn compute_external_query_constraints(
         &self,
+        certainty: Certainty,
         normalization_nested_goals: NestedNormalizationGoals<'tcx>,
-    ) -> Result<ExternalConstraintsData<'tcx>, NoSolution> {
-        // We only check for leaks from universes which were entered inside
-        // of the query.
-        self.infcx.leak_check(self.max_input_universe, None).map_err(|e| {
-            trace!(?e, "failed the leak check");
-            NoSolution
-        })?;
-
-        // Cannot use `take_registered_region_obligations` as we may compute the response
-        // inside of a `probe` whenever we have multiple choices inside of the solver.
-        let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned();
-        let mut region_constraints = self.infcx.with_region_constraints(|region_constraints| {
-            make_query_region_constraints(
-                self.tcx(),
-                region_obligations
-                    .iter()
-                    .map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())),
-                region_constraints,
-            )
-        });
-
-        let mut seen = FxHashSet::default();
-        region_constraints.outlives.retain(|outlives| seen.insert(*outlives));
+    ) -> ExternalConstraintsData<'tcx> {
+        // We only return region constraints once the certainty is `Yes`. This
+        // is necessary as we may drop nested goals on ambiguity, which may result
+        // in unconstrained inference variables in the region constraints. It also
+        // prevents us from emitting duplicate region constraints, avoiding some
+        // unnecessary work. This slightly weakens the leak check in case it uses
+        // region constraints from an ambiguous nested goal. This is tested in both
+        // `tests/ui/higher-ranked/leak-check/leak-check-in-selection-5-ambig.rs` and
+        // `tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.rs`.
+        let region_constraints = if certainty == Certainty::Yes {
+            // Cannot use `take_registered_region_obligations` as we may compute the response
+            // inside of a `probe` whenever we have multiple choices inside of the solver.
+            let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned();
+            let mut region_constraints = self.infcx.with_region_constraints(|region_constraints| {
+                make_query_region_constraints(
+                    self.tcx(),
+                    region_obligations.iter().map(|r_o| {
+                        (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())
+                    }),
+                    region_constraints,
+                )
+            });
+
+            let mut seen = FxHashSet::default();
+            region_constraints.outlives.retain(|outlives| seen.insert(*outlives));
+            region_constraints
+        } else {
+            Default::default()
+        };
 
         let mut opaque_types = self.infcx.clone_opaque_types_for_query_response();
         // Only return opaque type keys for newly-defined opaques
@@ -201,7 +215,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
             self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a)
         });
 
-        Ok(ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals })
+        ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals }
     }
 
     /// After calling a canonical query, we apply the constraints returned
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/backtrace b/library/backtrace
-Subproject e15130618237eb3e2d4b622549f9647b4c1d9ca
+Subproject 5e05efa87905fb5b351a2bc5644d60c57d6d932
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/library/core/src/str/count.rs b/library/core/src/str/count.rs
index 28567a7e753..d8667864fe5 100644
--- a/library/core/src/str/count.rs
+++ b/library/core/src/str/count.rs
@@ -24,7 +24,7 @@ const UNROLL_INNER: usize = 4;
 
 #[inline]
 pub(super) fn count_chars(s: &str) -> usize {
-    if s.len() < USIZE_SIZE * UNROLL_INNER {
+    if cfg!(feature = "optimize_for_size") || s.len() < USIZE_SIZE * UNROLL_INNER {
         // Avoid entering the optimized implementation for strings where the
         // difference is not likely to matter, or where it might even be slower.
         // That said, a ton of thought was not spent on the particular threshold
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index bc78c63c577..79a504c5a5e 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -24,11 +24,11 @@ hashbrown = { version = "0.14", default-features = false, features = ['rustc-dep
 std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = ['rustc-dep-of-std'] }
 
 # Dependencies of the `backtrace` crate
-rustc-demangle = { version = "0.1.21", features = ['rustc-dep-of-std'] }
+rustc-demangle = { version = "0.1.24", features = ['rustc-dep-of-std'] }
 
 [target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies]
 miniz_oxide = { version = "0.7.0", optional = true, default-features = false }
-addr2line = { version = "0.21.0", optional = true, default-features = false }
+addr2line = { version = "0.22.0", optional = true, default-features = false }
 
 [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
 libc = { version = "0.2.153", default-features = false, features = ['rustc-dep-of-std'], public = true }
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/ci/docker/run.sh b/src/ci/docker/run.sh
index 22dcb808c74..a4c59b3067e 100755
--- a/src/ci/docker/run.sh
+++ b/src/ci/docker/run.sh
@@ -270,7 +270,6 @@ else
   args="$args --volume $root_dir:/checkout$SRC_MOUNT_OPTION"
   args="$args --volume $objdir:/checkout/obj"
   args="$args --volume $HOME/.cargo:/cargo"
-  args="$args --volume $HOME/rustsrc:$HOME/rustsrc"
   args="$args --volume /tmp/toolstate:/tmp/toolstate"
 
   id=$(id -u)
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 05470eebf01..174aaeec6b5 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -61,6 +61,12 @@ envs:
 
   try:
     <<: *production
+    # The following env var activates faster `try` builds in `opt-dist` by, e.g.
+    # - building only the more commonly useful components (we rarely need e.g. rust-docs in try
+    #   builds)
+    # - not running `opt-dist`'s post-optimization smoke tests on the resulting toolchain
+    #
+    # If you *want* these to happen however, temporarily uncomment it before triggering a try build.
     DIST_TRY_BUILD: 1
 
   auto:
diff --git a/src/ci/scripts/verify-line-endings.sh b/src/ci/scripts/verify-line-endings.sh
index f3cac13ea48..5f4b4aeb0e4 100755
--- a/src/ci/scripts/verify-line-endings.sh
+++ b/src/ci/scripts/verify-line-endings.sh
@@ -4,21 +4,21 @@
 # We check both in rust-lang/rust and in a submodule to make sure both are
 # accurate. Submodules are checked out significantly later than the main
 # repository in this script, so settings can (and do!) change between then.
-#
-# Linux (and maybe macOS) builders don't currently have dos2unix so just only
-# run this step on Windows.
 
 set -euo pipefail
 IFS=$'\n\t'
 
 source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
 
-if isWindows; then
-    # print out the git configuration so we can better investigate failures in
-    # the following
-    git config --list --show-origin
-    dos2unix -ih Cargo.lock src/tools/rust-installer/install-template.sh
-    endings=$(dos2unix -ic Cargo.lock src/tools/rust-installer/install-template.sh)
-    # if endings has non-zero length, error out
-    if [ -n "$endings" ]; then exit 1 ; fi
+# print out the git configuration so we can better investigate failures in
+# the following
+git config --list --show-origin
+# -U is necessary on Windows to stop grep automatically converting the line ending
+endings=$(grep -Ul $(printf '\r$') Cargo.lock src/tools/cargo/Cargo.lock) || true
+# if endings has non-zero length, error out
+if [[ -n $endings ]]; then
+    echo "Error: found DOS line endings"
+    # Print the files with DOS line endings
+    echo "$endings"
+    exit 1
 fi
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 7aab07c06a3..7490688e36c 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -627,7 +627,7 @@ impl Item {
         ) -> hir::FnHeader {
             let sig = tcx.fn_sig(def_id).skip_binder();
             let constness =
-                if tcx.is_const_fn(def_id) && is_unstable_const_fn(tcx, def_id).is_none() {
+                if tcx.is_const_fn(def_id) || is_unstable_const_fn(tcx, def_id).is_some() {
                     hir::Constness::Const
                 } else {
                     hir::Constness::NotConst
@@ -649,9 +649,8 @@ impl Item {
                         hir::Safety::Unsafe
                     },
                     abi,
-                    constness: if abi == Abi::RustIntrinsic
-                        && tcx.is_const_fn(def_id)
-                        && is_unstable_const_fn(tcx, def_id).is_none()
+                    constness: if tcx.is_const_fn(def_id)
+                        || is_unstable_const_fn(tcx, def_id).is_some()
                     {
                         hir::Constness::Const
                     } else {
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 587c464b0ed..57949001774 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -13,7 +13,7 @@ use std::fmt::{self, Display, Write};
 use std::iter::{self, once};
 
 use rustc_ast as ast;
-use rustc_attr::{ConstStability, StabilityLevel};
+use rustc_attr::{ConstStability, StabilityLevel, StableSince};
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
@@ -1633,17 +1633,24 @@ impl PrintWithSpace for hir::Mutability {
 
 pub(crate) fn print_constness_with_space(
     c: &hir::Constness,
-    s: Option<ConstStability>,
+    overall_stab: Option<StableSince>,
+    const_stab: Option<ConstStability>,
 ) -> &'static str {
-    match (c, s) {
-        // const stable or when feature(staged_api) is not set
-        (
-            hir::Constness::Const,
-            Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }),
-        )
-        | (hir::Constness::Const, None) => "const ",
-        // const unstable or not const
-        _ => "",
+    match c {
+        hir::Constness::Const => match (overall_stab, const_stab) {
+            // const stable...
+            (_, Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }))
+            // ...or when feature(staged_api) is not set...
+            | (_, None)
+            // ...or when const unstable, but overall unstable too
+            | (None, Some(ConstStability { level: StabilityLevel::Unstable { .. }, .. })) => {
+                "const "
+            }
+            // const unstable (and overall stable)
+            (Some(_), Some(ConstStability { level: StabilityLevel::Unstable { .. }, .. })) => "",
+        },
+        // not const
+        hir::Constness::NotConst => "",
     }
 }
 
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index f3ae4b76883..8ee4cc5c75e 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -928,9 +928,11 @@ fn assoc_method(
     // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove
     // this condition.
     let constness = match render_mode {
-        RenderMode::Normal => {
-            print_constness_with_space(&header.constness, meth.const_stability(tcx))
-        }
+        RenderMode::Normal => print_constness_with_space(
+            &header.constness,
+            meth.stable_since(tcx),
+            meth.const_stability(tcx),
+        ),
         RenderMode::ForDeref { .. } => "",
     };
     let asyncness = header.asyncness.print_with_space();
@@ -1016,18 +1018,23 @@ fn render_stability_since_raw_with_extra(
                 .map(|since| (format!("const since {since}"), format!("const: {since}")))
         }
         Some(ConstStability { level: StabilityLevel::Unstable { issue, .. }, feature, .. }) => {
-            let unstable = if let Some(n) = issue {
-                format!(
-                    "<a \
+            if stable_version.is_none() {
+                // don't display const unstable if entirely unstable
+                None
+            } else {
+                let unstable = if let Some(n) = issue {
+                    format!(
+                        "<a \
                         href=\"https://github.com/rust-lang/rust/issues/{n}\" \
                         title=\"Tracking issue for {feature}\"\
                        >unstable</a>"
-                )
-            } else {
-                String::from("unstable")
-            };
+                    )
+                } else {
+                    String::from("unstable")
+                };
 
-            Some((String::from("const unstable"), format!("const: {unstable}")))
+                Some((String::from("const unstable"), format!("const: {unstable}")))
+            }
         }
         _ => None,
     };
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index c7a23aa8503..c5b88c7a951 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -615,7 +615,18 @@ fn extra_info_tags<'a, 'tcx: 'a>(
 fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &clean::Function) {
     let tcx = cx.tcx();
     let header = it.fn_header(tcx).expect("printing a function which isn't a function");
-    let constness = print_constness_with_space(&header.constness, it.const_stability(tcx));
+    debug!(
+        "item_function/const: {:?} {:?} {:?} {:?}",
+        it.name,
+        &header.constness,
+        it.stable_since(tcx),
+        it.const_stability(tcx),
+    );
+    let constness = print_constness_with_space(
+        &header.constness,
+        it.stable_since(tcx),
+        it.const_stability(tcx),
+    );
     let safety = header.safety.print_with_space();
     let abi = print_abi_with_space(header.abi).to_string();
     let asyncness = header.asyncness.print_with_space();
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/miri/rust-version b/src/tools/miri/rust-version
index 3b24a903d3a..cf698c31801 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-a59072ec4fb6824213df5e9de8cae4812fd4fe97
+d86e1229411c086e1267c80dd9872959ca13b8b9
diff --git a/src/tools/miri/tests/panic/mir-validation.stderr b/src/tools/miri/tests/panic/mir-validation.stderr
index d5dd53d7b4e..534e2d5881f 100644
--- a/src/tools/miri/tests/panic/mir-validation.stderr
+++ b/src/tools/miri/tests/panic/mir-validation.stderr
@@ -1,6 +1,6 @@
 thread 'rustc' panicked at compiler/rustc_mir_transform/src/validate.rs:LL:CC:
 broken MIR in Item(DefId) (after phase change to runtime-optimized) at bb0[1]:
-(*(_2.0: *mut i32)), has deref at the wrong place
+place (*(_2.0: *mut i32)) has deref as a later projection (it is only permitted as the first projection)
 stack backtrace:
 
 error: the compiler unexpectedly panicked. this is a bug.
diff --git a/src/tools/run-make-support/src/diff/mod.rs b/src/tools/run-make-support/src/diff/mod.rs
index 332126939c0..d864ddf4eb1 100644
--- a/src/tools/run-make-support/src/diff/mod.rs
+++ b/src/tools/run-make-support/src/diff/mod.rs
@@ -51,7 +51,10 @@ impl Diff {
     /// Specify the actual output for the diff from a file.
     pub fn actual_file<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
         let path = path.as_ref();
-        let content = std::fs::read_to_string(path).expect("failed to read file");
+        let content = match std::fs::read_to_string(path) {
+            Ok(c) => c,
+            Err(e) => panic!("failed to read `{}`: {:?}", path.display(), e),
+        };
         let name = path.to_string_lossy().to_string();
 
         self.actual = Some(content);
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 9854d91e19e..d96c8b89127 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -12,6 +12,8 @@ pub mod rustc;
 pub mod rustdoc;
 
 use std::env;
+use std::fs;
+use std::io;
 use std::path::{Path, PathBuf};
 use std::process::{Command, Output};
 
@@ -201,6 +203,71 @@ pub fn set_host_rpath(cmd: &mut Command) {
     });
 }
 
+/// Copy a directory into another.
+pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
+    fn copy_dir_all_inner(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
+        let dst = dst.as_ref();
+        if !dst.is_dir() {
+            fs::create_dir_all(&dst)?;
+        }
+        for entry in fs::read_dir(src)? {
+            let entry = entry?;
+            let ty = entry.file_type()?;
+            if ty.is_dir() {
+                copy_dir_all_inner(entry.path(), dst.join(entry.file_name()))?;
+            } else {
+                fs::copy(entry.path(), dst.join(entry.file_name()))?;
+            }
+        }
+        Ok(())
+    }
+
+    if let Err(e) = copy_dir_all_inner(&src, &dst) {
+        // Trying to give more context about what exactly caused the failure
+        panic!(
+            "failed to copy `{}` to `{}`: {:?}",
+            src.as_ref().display(),
+            dst.as_ref().display(),
+            e
+        );
+    }
+}
+
+/// Check that all files in `dir1` exist and have the same content in `dir2`. Panic otherwise.
+pub fn recursive_diff(dir1: impl AsRef<Path>, dir2: impl AsRef<Path>) {
+    fn read_file(path: &Path) -> Vec<u8> {
+        match fs::read(path) {
+            Ok(c) => c,
+            Err(e) => panic!("Failed to read `{}`: {:?}", path.display(), e),
+        }
+    }
+
+    let dir2 = dir2.as_ref();
+    for entry in fs::read_dir(dir1).unwrap() {
+        let entry = entry.unwrap();
+        let entry_name = entry.file_name();
+        let path = entry.path();
+
+        if path.is_dir() {
+            recursive_diff(&path, &dir2.join(entry_name));
+        } else {
+            let path2 = dir2.join(entry_name);
+            let file1 = read_file(&path);
+            let file2 = read_file(&path2);
+
+            // We don't use `assert_eq!` because they are `Vec<u8>`, so not great for display.
+            // Why not using String? Because there might be minified files or even potentially
+            // binary ones, so that would display useless output.
+            assert!(
+                file1 == file2,
+                "`{}` and `{}` have different content",
+                path.display(),
+                path2.display(),
+            );
+        }
+    }
+}
+
 /// Implement common helpers for command wrappers. This assumes that the command wrapper is a struct
 /// containing a `cmd: Command` field and a `output` function. The provided helpers are:
 ///
diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-support/src/rustdoc.rs
index c4f4e9f9bd2..9c77f1ca462 100644
--- a/src/tools/run-make-support/src/rustdoc.rs
+++ b/src/tools/run-make-support/src/rustdoc.rs
@@ -151,6 +151,13 @@ impl Rustdoc {
         self
     }
 
+    /// Specify the output format.
+    pub fn output_format(&mut self, format: &str) -> &mut Self {
+        self.cmd.arg("--output-format");
+        self.cmd.arg(format);
+        self
+    }
+
     #[track_caller]
     pub fn run_fail_assert_exit_code(&mut self, code: i32) -> Output {
         let caller_location = std::panic::Location::caller();
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 9a6ae18abea..2329b8b44de 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
@@ -227,7 +226,6 @@ run-make/rlib-format-packed-bundled-libs/Makefile
 run-make/rmeta-preferred/Makefile
 run-make/rustc-macro-dep-files/Makefile
 run-make/rustdoc-io-error/Makefile
-run-make/rustdoc-verify-output-files/Makefile
 run-make/sanitizer-cdylib-link/Makefile
 run-make/sanitizer-dylib-link/Makefile
 run-make/sanitizer-staticlib-link/Makefile
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 37324639edf..055d620361f 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -12,10 +12,10 @@ use std::path::{Path, PathBuf};
 // should all be 1000 or lower. Limits significantly smaller than 1000 are also
 // desirable, because large numbers of files are unwieldy in general. See issue
 // #73494.
-const ENTRY_LIMIT: usize = 900;
+const ENTRY_LIMIT: u32 = 900;
 // FIXME: The following limits should be reduced eventually.
 
-const ISSUES_ENTRY_LIMIT: usize = 1676;
+const ISSUES_ENTRY_LIMIT: u32 = 1676;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
     "rs",     // test source files
@@ -53,7 +53,7 @@ const EXTENSION_EXCEPTION_PATHS: &[&str] = &[
 ];
 
 fn check_entries(tests_path: &Path, bad: &mut bool) {
-    let mut directories: HashMap<PathBuf, usize> = HashMap::new();
+    let mut directories: HashMap<PathBuf, u32> = HashMap::new();
 
     for dir in Walk::new(&tests_path.join("ui")) {
         if let Ok(entry) = dir {
@@ -62,7 +62,7 @@ fn check_entries(tests_path: &Path, bad: &mut bool) {
         }
     }
 
-    let (mut max, mut max_issues) = (0usize, 0usize);
+    let (mut max, mut max_issues) = (0, 0);
     for (dir_path, count) in directories {
         let is_issues_dir = tests_path.join("ui/issues") == dir_path;
         let (limit, maxcnt) = if is_issues_dir {
diff --git a/tests/crashes/123255.rs b/tests/crashes/123255.rs
new file mode 100644
index 00000000000..a94a2a0422e
--- /dev/null
+++ b/tests/crashes/123255.rs
@@ -0,0 +1,13 @@
+//@ known-bug: rust-lang/rust#123255
+//@ edition:2021
+#![crate_type = "lib"]
+
+pub fn a() {}
+
+mod handlers {
+    pub struct C(&());
+    pub fn c() -> impl Fn() -> C {
+        let a1 = ();
+        || C((crate::a(), a1).into())
+    }
+}
diff --git a/tests/crashes/123276.rs b/tests/crashes/123276.rs
new file mode 100644
index 00000000000..d2246f59583
--- /dev/null
+++ b/tests/crashes/123276.rs
@@ -0,0 +1,25 @@
+//@ known-bug: rust-lang/rust#123276
+//@ edition:2021
+
+async fn create_task() {
+    _ = Some(async { bind(documentation_filter()) });
+}
+
+async fn bind<Fut, F: Filter<Future = Fut>>(_: F) {}
+
+fn documentation_filter() -> impl Filter {
+    AndThen
+}
+
+trait Filter {
+    type Future;
+}
+
+struct AndThen;
+
+impl Filter for AndThen
+where
+    Foo: Filter,
+{
+    type Future = ();
+}
diff --git a/tests/crashes/123887.rs b/tests/crashes/123887.rs
new file mode 100644
index 00000000000..68e2fb0325c
--- /dev/null
+++ b/tests/crashes/123887.rs
@@ -0,0 +1,15 @@
+//@ known-bug: rust-lang/rust#123887
+//@ compile-flags: -Clink-dead-code
+
+#![feature(extern_types)]
+#![feature(unsized_fn_params)]
+
+extern "C" {
+    pub type ExternType;
+}
+
+impl ExternType {
+    pub fn f(self) {}
+}
+
+pub fn main() {}
diff --git a/tests/crashes/125013-1.rs b/tests/crashes/125013-1.rs
new file mode 100644
index 00000000000..ae66d7a1466
--- /dev/null
+++ b/tests/crashes/125013-1.rs
@@ -0,0 +1,5 @@
+//@ known-bug: rust-lang/rust#125013
+//@ edition:2021
+use io::{self as std};
+use std::ops::Deref::{self as io};
+pub fn main() {}
diff --git a/tests/crashes/125013-2.rs b/tests/crashes/125013-2.rs
new file mode 100644
index 00000000000..a14c8a76b63
--- /dev/null
+++ b/tests/crashes/125013-2.rs
@@ -0,0 +1,16 @@
+//@ known-bug: rust-lang/rust#125013
+//@ edition:2021
+mod a {
+  pub mod b {
+    pub mod c {
+      pub trait D {}
+    }
+  }
+}
+
+use a::*;
+
+use e as b;
+use b::c::D as e;
+
+fn main() { }
diff --git a/tests/crashes/125014.rs b/tests/crashes/125014.rs
new file mode 100644
index 00000000000..b29042ee598
--- /dev/null
+++ b/tests/crashes/125014.rs
@@ -0,0 +1,17 @@
+//@ known-bug: rust-lang/rust#125014
+//@ compile-flags: -Znext-solver=coherence
+#![feature(specialization)]
+
+trait Foo {}
+
+impl Foo for <u16 as Assoc>::Output {}
+
+impl Foo for u32 {}
+
+trait Assoc {
+    type Output;
+}
+impl Output for u32 {}
+impl Assoc for <u16 as Assoc>::Output {
+    default type Output = bool;
+}
diff --git a/tests/crashes/125059.rs b/tests/crashes/125059.rs
new file mode 100644
index 00000000000..7e9f7414816
--- /dev/null
+++ b/tests/crashes/125059.rs
@@ -0,0 +1,12 @@
+//@ known-bug: rust-lang/rust#125059
+#![feature(deref_patterns)]
+#![allow(incomplete_features)]
+
+fn simple_vec(vec: Vec<u32>) -> u32 {
+   (|| match Vec::<u32>::new() {
+        deref!([]) => 100,
+        _ => 2000,
+    })()
+}
+
+fn main() {}
diff --git a/tests/crashes/125323.rs b/tests/crashes/125323.rs
new file mode 100644
index 00000000000..180b7bbad09
--- /dev/null
+++ b/tests/crashes/125323.rs
@@ -0,0 +1,6 @@
+//@ known-bug: rust-lang/rust#125323
+fn main() {
+    for _ in 0..0 {
+        [(); loop {}];
+    }
+}
diff --git a/tests/crashes/125476.rs b/tests/crashes/125476.rs
new file mode 100644
index 00000000000..aa9a081388d
--- /dev/null
+++ b/tests/crashes/125476.rs
@@ -0,0 +1,4 @@
+//@ known-bug: rust-lang/rust#125476
+//@ only-x86_64
+pub struct Data([u8; usize::MAX >> 16]);
+const _: &'static [Data] = &[];
diff --git a/tests/crashes/125512.rs b/tests/crashes/125512.rs
new file mode 100644
index 00000000000..1672b24a114
--- /dev/null
+++ b/tests/crashes/125512.rs
@@ -0,0 +1,10 @@
+//@ known-bug: rust-lang/rust#125512
+//@ edition:2021
+#![feature(object_safe_for_dispatch)]
+trait B {
+    fn f(a: A) -> A;
+}
+trait A {
+    fn concrete(b: B) -> B;
+}
+fn main() {}
diff --git a/tests/crashes/125553.rs b/tests/crashes/125553.rs
new file mode 100644
index 00000000000..142c06775bb
--- /dev/null
+++ b/tests/crashes/125553.rs
@@ -0,0 +1,15 @@
+//@ known-bug: rust-lang/rust#125553
+//@ edition:2021
+
+#[derive(Copy, Clone)]
+struct Foo((u32, u32));
+
+fn main() {
+    type T = impl Copy(Copy, Clone)
+    let foo: T = Foo((1u32, 1u32));
+    let x = move || {
+        let derive = move || {
+        let Foo((a, b)) = foo;
+    };
+    };
+}
diff --git a/tests/crashes/125556.rs b/tests/crashes/125556.rs
new file mode 100644
index 00000000000..f2e2a991b11
--- /dev/null
+++ b/tests/crashes/125556.rs
@@ -0,0 +1,14 @@
+//@ known-bug: rust-lang/rust#125556
+//@ compile-flags: -Znext-solver=coherence
+
+#![feature(generic_const_exprs)]
+
+pub struct A<const z: [usize; x]> {}
+
+impl A<2> {
+    pub const fn B() {}
+}
+
+impl A<2> {
+    pub const fn B() {}
+}
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");
+}
diff --git a/tests/run-make/rustdoc-verify-output-files/Makefile b/tests/run-make/rustdoc-verify-output-files/Makefile
deleted file mode 100644
index 76f233ab445..00000000000
--- a/tests/run-make/rustdoc-verify-output-files/Makefile
+++ /dev/null
@@ -1,32 +0,0 @@
-include ../tools.mk
-
-OUTPUT_DIR := "$(TMPDIR)/rustdoc"
-TMP_OUTPUT_DIR := "$(TMPDIR)/tmp-rustdoc"
-
-all:
-	# Generate html docs
-	$(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --out-dir $(OUTPUT_DIR)
-
-	# Copy first output for to check if it's exactly same after second compilation
-	cp -R $(OUTPUT_DIR) $(TMP_OUTPUT_DIR)
-
-	# Generate html docs once again on same output
-	$(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --out-dir $(OUTPUT_DIR)
-
-	# Check if everything exactly same
-	$(DIFF) -r $(OUTPUT_DIR) $(TMP_OUTPUT_DIR)
-
-	# Generate json doc on the same output
-	$(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --out-dir $(OUTPUT_DIR) -Z unstable-options --output-format json
-
-	# Check if expected json file is generated
-	[ -e $(OUTPUT_DIR)/foobar.json ]
-
-	# Copy first json output to check if it's exactly same after second compilation
-	cp -R $(OUTPUT_DIR)/foobar.json $(TMP_OUTPUT_DIR)/foobar.json
-
-	# Generate json doc on the same output
-	$(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --out-dir $(OUTPUT_DIR) -Z unstable-options --output-format json
-
-	# Check if all docs(including both json and html formats) are still the same after multiple compilations
-	$(DIFF) -r $(OUTPUT_DIR) $(TMP_OUTPUT_DIR)
diff --git a/tests/run-make/rustdoc-verify-output-files/rmake.rs b/tests/run-make/rustdoc-verify-output-files/rmake.rs
new file mode 100644
index 00000000000..212e7eaba2d
--- /dev/null
+++ b/tests/run-make/rustdoc-verify-output-files/rmake.rs
@@ -0,0 +1,49 @@
+use std::fs::copy;
+use std::path::{Path, PathBuf};
+
+use run_make_support::{copy_dir_all, recursive_diff, rustdoc, tmp_dir};
+
+#[derive(PartialEq)]
+enum JsonOutput {
+    Yes,
+    No,
+}
+
+fn generate_docs(out_dir: &Path, json_output: JsonOutput) {
+    let mut rustdoc = rustdoc();
+    rustdoc.input("src/lib.rs").crate_name("foobar").crate_type("lib").out_dir(&out_dir);
+    if json_output == JsonOutput::Yes {
+        rustdoc.arg("-Zunstable-options").output_format("json");
+    }
+    rustdoc.run();
+}
+
+fn main() {
+    let out_dir = tmp_dir().join("rustdoc");
+    let tmp_out_dir = tmp_dir().join("tmp-rustdoc");
+
+    // Generate HTML docs.
+    generate_docs(&out_dir, JsonOutput::No);
+
+    // Copy first output for to check if it's exactly same after second compilation.
+    copy_dir_all(&out_dir, &tmp_out_dir);
+
+    // Generate html docs once again on same output.
+    generate_docs(&out_dir, JsonOutput::No);
+
+    // Generate json doc on the same output.
+    generate_docs(&out_dir, JsonOutput::Yes);
+
+    // Check if expected json file is generated.
+    assert!(out_dir.join("foobar.json").is_file());
+
+    // Copy first json output to check if it's exactly same after second compilation.
+    copy(out_dir.join("foobar.json"), tmp_out_dir.join("foobar.json")).unwrap();
+
+    // Generate json doc on the same output.
+    generate_docs(&out_dir, JsonOutput::Yes);
+
+    // Check if all docs(including both json and html formats) are still the same after multiple
+    // compilations.
+    recursive_diff(&out_dir, &tmp_out_dir);
+}
diff --git a/tests/rustdoc/const-display.rs b/tests/rustdoc/const-display.rs
index c8967f426f0..959a00102b7 100644
--- a/tests/rustdoc/const-display.rs
+++ b/tests/rustdoc/const-display.rs
@@ -24,6 +24,12 @@ pub const unsafe fn foo_unsafe() -> u32 { 42 }
 #[unstable(feature = "humans", issue = "none")]
 pub const fn foo2() -> u32 { 42 }
 
+// @has 'foo/fn.foo3.html' '//pre' 'pub const fn foo3() -> u32'
+// @!hasraw - '//span[@class="since"]'
+#[unstable(feature = "humans", issue = "none")]
+#[rustc_const_unstable(feature = "humans", issue = "none")]
+pub const fn foo3() -> u32 { 42 }
+
 // @has 'foo/fn.bar2.html' '//pre' 'pub const fn bar2() -> u32'
 // @has - //span '1.0.0 (const: 1.0.0)'
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/tests/ui/const-generics/generic_const_exprs/ice-125520-layout-mismatch-mulwithoverflow.rs b/tests/ui/const-generics/generic_const_exprs/ice-125520-layout-mismatch-mulwithoverflow.rs
new file mode 100644
index 00000000000..cd2dc3f4fe8
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/ice-125520-layout-mismatch-mulwithoverflow.rs
@@ -0,0 +1,27 @@
+// issue: rust-lang/rust#125520
+#![feature(generic_const_exprs)]
+//~^ WARN the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
+
+struct Outer<const A: i64, const B: i64>();
+impl<const A: usize, const B: usize> Outer<A, B>
+//~^ ERROR the constant `A` is not of type `i64`
+//~| ERROR the constant `B` is not of type `i64`
+//~| ERROR mismatched types
+//~| ERROR mismatched types
+where
+    [(); A + (B * 2)]:,
+{
+    fn i() -> Self {
+    //~^ ERROR the constant `A` is not of type `i64`
+    //~| ERROR the constant `B` is not of type `i64`
+        Self
+        //~^ ERROR mismatched types
+        //~| ERROR the constant `A` is not of type `i64`
+        //~| ERROR the constant `B` is not of type `i64`
+    }
+}
+
+fn main() {
+    Outer::<1, 1>::o();
+    //~^ ERROR no function or associated item named `o` found for struct `Outer` in the current scope
+}
diff --git a/tests/ui/const-generics/generic_const_exprs/ice-125520-layout-mismatch-mulwithoverflow.stderr b/tests/ui/const-generics/generic_const_exprs/ice-125520-layout-mismatch-mulwithoverflow.stderr
new file mode 100644
index 00000000000..2dbd69fd3bc
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/ice-125520-layout-mismatch-mulwithoverflow.stderr
@@ -0,0 +1,125 @@
+warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:2:12
+   |
+LL | #![feature(generic_const_exprs)]
+   |            ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: the constant `A` is not of type `i64`
+  --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:6:38
+   |
+LL | impl<const A: usize, const B: usize> Outer<A, B>
+   |                                      ^^^^^^^^^^^ expected `i64`, found `usize`
+   |
+note: required by a bound in `Outer`
+  --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:5:14
+   |
+LL | struct Outer<const A: i64, const B: i64>();
+   |              ^^^^^^^^^^^^ required by this bound in `Outer`
+
+error: the constant `B` is not of type `i64`
+  --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:6:38
+   |
+LL | impl<const A: usize, const B: usize> Outer<A, B>
+   |                                      ^^^^^^^^^^^ expected `i64`, found `usize`
+   |
+note: required by a bound in `Outer`
+  --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:5:28
+   |
+LL | struct Outer<const A: i64, const B: i64>();
+   |                            ^^^^^^^^^^^^ required by this bound in `Outer`
+
+error: the constant `A` is not of type `i64`
+  --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:14:15
+   |
+LL |     fn i() -> Self {
+   |               ^^^^ expected `i64`, found `usize`
+   |
+note: required by a bound in `Outer`
+  --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:5:14
+   |
+LL | struct Outer<const A: i64, const B: i64>();
+   |              ^^^^^^^^^^^^ required by this bound in `Outer`
+
+error: the constant `B` is not of type `i64`
+  --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:14:15
+   |
+LL |     fn i() -> Self {
+   |               ^^^^ expected `i64`, found `usize`
+   |
+note: required by a bound in `Outer`
+  --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:5:28
+   |
+LL | struct Outer<const A: i64, const B: i64>();
+   |                            ^^^^^^^^^^^^ required by this bound in `Outer`
+
+error[E0308]: mismatched types
+  --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:17:9
+   |
+LL | struct Outer<const A: i64, const B: i64>();
+   | ---------------------------------------- `Outer` defines a struct constructor here, which should be called
+...
+LL |     fn i() -> Self {
+   |               ---- expected `Outer<A, B>` because of return type
+...
+LL |         Self
+   |         ^^^^ expected `Outer<A, B>`, found struct constructor
+   |
+   = note:          expected struct `Outer<A, B>`
+           found struct constructor `fn() -> Outer<A, B> {Outer::<A, B>}`
+help: use parentheses to construct this tuple struct
+   |
+LL |         Self()
+   |             ++
+
+error: the constant `A` is not of type `i64`
+  --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:17:9
+   |
+LL |         Self
+   |         ^^^^ expected `i64`, found `usize`
+   |
+note: required by a bound in `Outer`
+  --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:5:14
+   |
+LL | struct Outer<const A: i64, const B: i64>();
+   |              ^^^^^^^^^^^^ required by this bound in `Outer`
+
+error: the constant `B` is not of type `i64`
+  --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:17:9
+   |
+LL |         Self
+   |         ^^^^ expected `i64`, found `usize`
+   |
+note: required by a bound in `Outer`
+  --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:5:28
+   |
+LL | struct Outer<const A: i64, const B: i64>();
+   |                            ^^^^^^^^^^^^ required by this bound in `Outer`
+
+error[E0599]: no function or associated item named `o` found for struct `Outer` in the current scope
+  --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:25:20
+   |
+LL | struct Outer<const A: i64, const B: i64>();
+   | ---------------------------------------- function or associated item `o` not found for this struct
+...
+LL |     Outer::<1, 1>::o();
+   |                    ^ function or associated item not found in `Outer<1, 1>`
+
+error[E0308]: mismatched types
+  --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:6:44
+   |
+LL | impl<const A: usize, const B: usize> Outer<A, B>
+   |                                            ^ expected `i64`, found `usize`
+
+error[E0308]: mismatched types
+  --> $DIR/ice-125520-layout-mismatch-mulwithoverflow.rs:6:47
+   |
+LL | impl<const A: usize, const B: usize> Outer<A, B>
+   |                                               ^ expected `i64`, found `usize`
+
+error: aborting due to 10 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0308, E0599.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/const-generics/issues/issue-105821.rs b/tests/ui/const-generics/issues/issue-105821.rs
index 282cbe9249d..e55da461605 100644
--- a/tests/ui/const-generics/issues/issue-105821.rs
+++ b/tests/ui/const-generics/issues/issue-105821.rs
@@ -1,5 +1,5 @@
 //@ failure-status: 101
-//@ known-bug: unknown
+//@ known-bug: rust-lang/rust#125451
 //@ normalize-stderr-test "note: .*\n\n" -> ""
 //@ normalize-stderr-test "thread 'rustc' panicked.*\n.*\n" -> ""
 //@ normalize-stderr-test "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: "
diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-5-ambig.rs b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-5-ambig.rs
new file mode 100644
index 00000000000..beda719ac20
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-5-ambig.rs
@@ -0,0 +1,28 @@
+//@ revisions: old next
+//@[next] compile-flags: -Znext-solver
+//@ check-pass
+
+// The new trait solver does not return region constraints if the goal
+// is still ambiguous. This causes the following test to fail with ambiguity,
+// even though `(): LeakCheckFailure<'!a, V>` would return `'!a: 'static`
+// which would have caused a leak check failure.
+
+trait Ambig {}
+impl Ambig for u32 {}
+impl Ambig for u16 {}
+
+trait Id<T> {}
+impl Id<u32> for u32 {}
+impl Id<u16> for u16 {}
+
+
+trait LeakCheckFailure<'a, V: ?Sized> {}
+impl<V: ?Sized + Ambig> LeakCheckFailure<'static, V> for () {}
+
+trait Trait<U, V> {}
+impl<V> Trait<u32, V> for () where for<'a> (): LeakCheckFailure<'a, V> {}
+impl<V> Trait<u16, V> for () {}
+fn impls_trait<T: Trait<U, V>, U: Id<V>, V>() {}
+fn main() {
+    impls_trait::<(), _, _>()
+}
diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.next.stderr b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.next.stderr
new file mode 100644
index 00000000000..a12e3312230
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.next.stderr
@@ -0,0 +1,22 @@
+error[E0283]: type annotations needed
+  --> $DIR/leak-check-in-selection-6-ambig-unify.rs:30:5
+   |
+LL |     impls_trait::<(), _, _>()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_trait`
+   |
+note: multiple `impl`s satisfying `(): Trait<_, _>` found
+  --> $DIR/leak-check-in-selection-6-ambig-unify.rs:26:1
+   |
+LL | impl<V> Trait<u32, V> for () where for<'b> (): LeakCheckFailure<'static, 'b, V> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl<V> Trait<u16, V> for () {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `impls_trait`
+  --> $DIR/leak-check-in-selection-6-ambig-unify.rs:28:19
+   |
+LL | fn impls_trait<T: Trait<U, V>, U: Id<V>, V>() {}
+   |                   ^^^^^^^^^^^ required by this bound in `impls_trait`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.old.stderr b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.old.stderr
new file mode 100644
index 00000000000..a12e3312230
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.old.stderr
@@ -0,0 +1,22 @@
+error[E0283]: type annotations needed
+  --> $DIR/leak-check-in-selection-6-ambig-unify.rs:30:5
+   |
+LL |     impls_trait::<(), _, _>()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_trait`
+   |
+note: multiple `impl`s satisfying `(): Trait<_, _>` found
+  --> $DIR/leak-check-in-selection-6-ambig-unify.rs:26:1
+   |
+LL | impl<V> Trait<u32, V> for () where for<'b> (): LeakCheckFailure<'static, 'b, V> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl<V> Trait<u16, V> for () {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `impls_trait`
+  --> $DIR/leak-check-in-selection-6-ambig-unify.rs:28:19
+   |
+LL | fn impls_trait<T: Trait<U, V>, U: Id<V>, V>() {}
+   |                   ^^^^^^^^^^^ required by this bound in `impls_trait`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.rs b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.rs
new file mode 100644
index 00000000000..592d581695e
--- /dev/null
+++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.rs
@@ -0,0 +1,32 @@
+//@ revisions: old next
+//@[next] compile-flags: -Znext-solver
+
+// The new trait solver does not return region constraints if the goal
+// is still ambiguous. This should cause the following test to fail with
+// ambiguity as even if  `(): LeakCheckFailure<'static, '!b, V>` unifies
+// `'!b` with `'static`, we erase all region constraints.
+//
+// However, we do still unify the var_value for `'b` with `'static`,
+// causing us to return this requirement via the `var_values` even if
+// we don't return any region constraints. This is a bit inconsistent
+// but isn't something we should really worry about imo.
+trait Ambig {}
+impl Ambig for u32 {}
+impl Ambig for u16 {}
+
+trait Id<T> {}
+impl Id<u32> for u32 {}
+impl Id<u16> for u16 {}
+
+
+trait LeakCheckFailure<'a, 'b, V: ?Sized> {}
+impl<'a, 'b: 'a, V: ?Sized + Ambig> LeakCheckFailure<'a, 'b, V> for () {}
+
+trait Trait<U, V> {}
+impl<V> Trait<u32, V> for () where for<'b> (): LeakCheckFailure<'static, 'b, V> {}
+impl<V> Trait<u16, V> for () {}
+fn impls_trait<T: Trait<U, V>, U: Id<V>, V>() {}
+fn main() {
+    impls_trait::<(), _, _>()
+    //~^ ERROR type annotations needed
+}
diff --git a/tests/ui/traits/next-solver/normalize/ambig-goal-infer-in-type-oulives.rs b/tests/ui/traits/next-solver/normalize/ambig-goal-infer-in-type-oulives.rs
new file mode 100644
index 00000000000..18dc34f7cc4
--- /dev/null
+++ b/tests/ui/traits/next-solver/normalize/ambig-goal-infer-in-type-oulives.rs
@@ -0,0 +1,29 @@
+//@ check-pass
+//@ compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicitly enabled)
+
+// Regression test for an ICE when trying to bootstrap rustc
+// with #125343. An ambiguous goal returned a `TypeOutlives`
+// constraint referencing an inference variable. This inference
+// variable was created inside of the goal, causing it to be
+// unconstrained in the caller. This then caused an ICE in MIR
+// borrowck.
+
+struct Foo<T>(T);
+trait Extend<T> {
+    fn extend<I: IntoIterator<Item = T>>(iter: I);
+}
+
+impl<T> Extend<T> for Foo<T> {
+    fn extend<I: IntoIterator<Item = T>>(_: I) {
+        todo!()
+    }
+}
+
+impl<'a, T: 'a + Copy> Extend<&'a T> for Foo<T> {
+    fn extend<I: IntoIterator<Item = &'a T>>(iter: I) {
+        <Self as Extend<T>>::extend(iter.into_iter().copied())
+    }
+}
+
+fn main() {}