about summary refs log tree commit diff
path: root/compiler/rustc_borrowck/src
diff options
context:
space:
mode:
authorThe Miri Conjob Bot <miri@cron.bot>2024-02-22 05:02:05 +0000
committerThe Miri Conjob Bot <miri@cron.bot>2024-02-22 05:02:05 +0000
commit76a596c48d1b8ed3805e623e003c73edaf00c5fc (patch)
treed455bd062e68808928fdbdd46ff10e38d5c4575e /compiler/rustc_borrowck/src
parentf5ec4cb37561743efd869d61e457ae39938c1680 (diff)
parentc5f69bdd5173a948e0131f934fa7c4cbf5e0b55f (diff)
Merge from rustc
Diffstat (limited to 'compiler/rustc_borrowck/src')
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs35
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs8
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs12
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs17
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs17
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs6
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs27
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs10
-rw-r--r--compiler/rustc_borrowck/src/lib.rs2
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs4
-rw-r--r--compiler/rustc_borrowck/src/type_check/canonical.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/constraint_conversion.rs4
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs19
-rw-r--r--compiler/rustc_borrowck/src/type_check/input_output.rs3
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs18
-rw-r--r--compiler/rustc_borrowck/src/type_check/relate_tys.rs485
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs4
17 files changed, 557 insertions, 116 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 2b0c0e939f5..e1509da913a 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -6,9 +6,7 @@
 use either::Either;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxIndexSet;
-use rustc_errors::{
-    codes::*, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan,
-};
+use rustc_errors::{codes::*, struct_span_code_err, Applicability, DiagnosticBuilder, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
@@ -635,7 +633,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
     fn suggest_assign_value(
         &self,
-        err: &mut Diagnostic,
+        err: &mut DiagnosticBuilder<'_>,
         moved_place: PlaceRef<'tcx>,
         sugg_span: Span,
     ) {
@@ -674,7 +672,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
     fn suggest_borrow_fn_like(
         &self,
-        err: &mut Diagnostic,
+        err: &mut DiagnosticBuilder<'_>,
         ty: Ty<'tcx>,
         move_sites: &[MoveSite],
         value_name: &str,
@@ -742,7 +740,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
     fn suggest_cloning(
         &self,
-        err: &mut Diagnostic,
+        err: &mut DiagnosticBuilder<'_>,
         ty: Ty<'tcx>,
         expr: &hir::Expr<'_>,
         span: Span,
@@ -778,7 +776,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         }
     }
 
-    fn suggest_adding_copy_bounds(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: Span) {
+    fn suggest_adding_copy_bounds(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        ty: Ty<'tcx>,
+        span: Span,
+    ) {
         let tcx = self.infcx.tcx;
         let generics = tcx.generics_of(self.mir_def_id());
 
@@ -1225,7 +1228,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     #[instrument(level = "debug", skip(self, err))]
     fn suggest_using_local_if_applicable(
         &self,
-        err: &mut Diagnostic,
+        err: &mut DiagnosticBuilder<'_>,
         location: Location,
         issued_borrow: &BorrowData<'tcx>,
         explanation: BorrowExplanation<'tcx>,
@@ -1321,7 +1324,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
     fn suggest_slice_method_if_applicable(
         &self,
-        err: &mut Diagnostic,
+        err: &mut DiagnosticBuilder<'_>,
         place: Place<'tcx>,
         borrowed_place: Place<'tcx>,
     ) {
@@ -1430,7 +1433,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     /// ```
     pub(crate) fn explain_iterator_advancement_in_for_loop_if_applicable(
         &self,
-        err: &mut Diagnostic,
+        err: &mut DiagnosticBuilder<'_>,
         span: Span,
         issued_spans: &UseSpans<'tcx>,
     ) {
@@ -1617,7 +1620,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     /// ```
     fn suggest_using_closure_argument_instead_of_capture(
         &self,
-        err: &mut Diagnostic,
+        err: &mut DiagnosticBuilder<'_>,
         borrowed_place: Place<'tcx>,
         issued_spans: &UseSpans<'tcx>,
     ) {
@@ -1751,7 +1754,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
     fn suggest_binding_for_closure_capture_self(
         &self,
-        err: &mut Diagnostic,
+        err: &mut DiagnosticBuilder<'_>,
         issued_spans: &UseSpans<'tcx>,
     ) {
         let UseSpans::ClosureUse { capture_kind_span, .. } = issued_spans else { return };
@@ -2997,7 +3000,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         self.buffer_error(err);
     }
 
-    fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut Diagnostic) {
+    fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut DiagnosticBuilder<'_>) {
         let tcx = self.infcx.tcx;
         if let (
             Some(Terminator {
@@ -3532,7 +3535,11 @@ enum AnnotatedBorrowFnSignature<'tcx> {
 impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
     /// Annotate the provided diagnostic with information about borrow from the fn signature that
     /// helps explain.
-    pub(crate) fn emit(&self, cx: &mut MirBorrowckCtxt<'_, 'tcx>, diag: &mut Diagnostic) -> String {
+    pub(crate) fn emit(
+        &self,
+        cx: &mut MirBorrowckCtxt<'_, 'tcx>,
+        diag: &mut DiagnosticBuilder<'_>,
+    ) -> String {
         match self {
             &AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span } => {
                 diag.span_label(
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 483ecee850b..f7b59ec5fe0 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -3,7 +3,7 @@
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::untranslatable_diagnostic)]
 
-use rustc_errors::{Applicability, Diagnostic};
+use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::intravisit::Visitor;
 use rustc_index::IndexSlice;
@@ -65,7 +65,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
         tcx: TyCtxt<'tcx>,
         body: &Body<'tcx>,
         local_names: &IndexSlice<Local, Option<Symbol>>,
-        err: &mut Diagnostic,
+        err: &mut DiagnosticBuilder<'_>,
         borrow_desc: &str,
         borrow_span: Option<Span>,
         multiple_borrow_span: Option<(Span, Span)>,
@@ -306,7 +306,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
     fn add_object_lifetime_default_note(
         &self,
         tcx: TyCtxt<'tcx>,
-        err: &mut Diagnostic,
+        err: &mut DiagnosticBuilder<'_>,
         unsize_ty: Ty<'tcx>,
     ) {
         if let ty::Adt(def, args) = unsize_ty.kind() {
@@ -359,7 +359,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
 
     fn add_lifetime_bound_suggestion_to_diagnostic(
         &self,
-        err: &mut Diagnostic,
+        err: &mut DiagnosticBuilder<'_>,
         category: &ConstraintCategory<'tcx>,
         span: Span,
         region_name: &RegionName,
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 4ca854c857d..db0d69b6eaa 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -5,7 +5,7 @@ use crate::session_diagnostics::{
     CaptureVarKind, CaptureVarPathUseCause, OnClosureNote,
 };
 use itertools::Itertools;
-use rustc_errors::{Applicability, Diagnostic};
+use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, Namespace};
 use rustc_hir::CoroutineKind;
@@ -80,7 +80,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         &self,
         location: Location,
         place: PlaceRef<'tcx>,
-        diag: &mut Diagnostic,
+        diag: &mut DiagnosticBuilder<'_>,
     ) -> bool {
         debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place);
         let mut target = place.local_or_deref_local();
@@ -588,7 +588,7 @@ impl UseSpans<'_> {
     pub(super) fn args_subdiag(
         self,
         dcx: &rustc_errors::DiagCtxt,
-        err: &mut Diagnostic,
+        err: &mut DiagnosticBuilder<'_>,
         f: impl FnOnce(Span) -> CaptureArgLabel,
     ) {
         if let UseSpans::ClosureUse { args_span, .. } = self {
@@ -601,7 +601,7 @@ impl UseSpans<'_> {
     pub(super) fn var_path_only_subdiag(
         self,
         dcx: &rustc_errors::DiagCtxt,
-        err: &mut Diagnostic,
+        err: &mut DiagnosticBuilder<'_>,
         action: crate::InitializationRequiringAction,
     ) {
         use crate::InitializationRequiringAction::*;
@@ -638,7 +638,7 @@ impl UseSpans<'_> {
     pub(super) fn var_subdiag(
         self,
         dcx: &rustc_errors::DiagCtxt,
-        err: &mut Diagnostic,
+        err: &mut DiagnosticBuilder<'_>,
         kind: Option<rustc_middle::mir::BorrowKind>,
         f: impl FnOnce(hir::ClosureKind, Span) -> CaptureVarCause,
     ) {
@@ -1010,7 +1010,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
     fn explain_captures(
         &mut self,
-        err: &mut Diagnostic,
+        err: &mut DiagnosticBuilder<'_>,
         span: Span,
         move_span: Span,
         move_spans: UseSpans<'tcx>,
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index dad20690d02..3478a73254a 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -1,7 +1,7 @@
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::untranslatable_diagnostic)]
 
-use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder};
+use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty};
 use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex};
@@ -437,7 +437,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         err
     }
 
-    fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diagnostic, span: Span) {
+    fn add_move_hints(
+        &self,
+        error: GroupedMoveError<'tcx>,
+        err: &mut DiagnosticBuilder<'_>,
+        span: Span,
+    ) {
         match error {
             GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => {
                 self.add_borrow_suggestions(err, span);
@@ -500,7 +505,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         }
     }
 
-    fn add_borrow_suggestions(&self, err: &mut Diagnostic, span: Span) {
+    fn add_borrow_suggestions(&self, err: &mut DiagnosticBuilder<'_>, span: Span) {
         match self.infcx.tcx.sess.source_map().span_to_snippet(span) {
             Ok(snippet) if snippet.starts_with('*') => {
                 err.span_suggestion_verbose(
@@ -521,7 +526,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         }
     }
 
-    fn add_move_error_suggestions(&self, err: &mut Diagnostic, binds_to: &[Local]) {
+    fn add_move_error_suggestions(&self, err: &mut DiagnosticBuilder<'_>, binds_to: &[Local]) {
         let mut suggestions: Vec<(Span, String, String)> = Vec::new();
         for local in binds_to {
             let bind_to = &self.body.local_decls[*local];
@@ -573,7 +578,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         }
     }
 
-    fn add_move_error_details(&self, err: &mut Diagnostic, binds_to: &[Local]) {
+    fn add_move_error_details(&self, err: &mut DiagnosticBuilder<'_>, binds_to: &[Local]) {
         for (j, local) in binds_to.iter().enumerate() {
             let bind_to = &self.body.local_decls[*local];
             let binding_span = bind_to.source_info.span;
@@ -610,7 +615,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
     /// expansion of a packed struct.
     /// Such errors happen because derive macro expansions shy away from taking
     /// references to the struct's fields since doing so would be undefined behaviour
-    fn add_note_for_packed_struct_derive(&self, err: &mut Diagnostic, local: Local) {
+    fn add_note_for_packed_struct_derive(&self, err: &mut DiagnosticBuilder<'_>, local: Local) {
         let local_place: PlaceRef<'tcx> = local.into();
         let local_ty = local_place.ty(self.body.local_decls(), self.infcx.tcx).ty.peel_refs();
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 514e9c39eb4..b8257ba0adc 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -2,7 +2,7 @@
 #![allow(rustc::untranslatable_diagnostic)]
 
 use hir::ExprKind;
-use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder};
+use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::Node;
@@ -540,7 +540,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         }
     }
 
-    fn suggest_map_index_mut_alternatives(&self, ty: Ty<'tcx>, err: &mut Diagnostic, span: Span) {
+    fn suggest_map_index_mut_alternatives(
+        &self,
+        ty: Ty<'tcx>,
+        err: &mut DiagnosticBuilder<'tcx>,
+        span: Span,
+    ) {
         let Some(adt) = ty.ty_adt_def() else { return };
         let did = adt.did();
         if self.infcx.tcx.is_diagnostic_item(sym::HashMap, did)
@@ -548,7 +553,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         {
             struct V<'a, 'tcx> {
                 assign_span: Span,
-                err: &'a mut Diagnostic,
+                err: &'a mut DiagnosticBuilder<'tcx>,
                 ty: Ty<'tcx>,
                 suggested: bool,
             }
@@ -790,7 +795,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         tcx: TyCtxt<'_>,
         closure_local_def_id: hir::def_id::LocalDefId,
         the_place_err: PlaceRef<'tcx>,
-        err: &mut Diagnostic,
+        err: &mut DiagnosticBuilder<'_>,
     ) {
         let tables = tcx.typeck(closure_local_def_id);
         if let Some((span, closure_kind_origin)) = tcx.closure_kind_origin(closure_local_def_id) {
@@ -852,7 +857,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
     // Attempt to search similar mutable associated items for suggestion.
     // In the future, attempt in all path but initially for RHS of for_loop
-    fn suggest_similar_mut_method_for_for_loop(&self, err: &mut Diagnostic, span: Span) {
+    fn suggest_similar_mut_method_for_for_loop(&self, err: &mut DiagnosticBuilder<'_>, span: Span) {
         use hir::{
             BorrowKind, Expr,
             ExprKind::{AddrOf, Block, Call, MethodCall},
@@ -936,7 +941,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
     }
 
     /// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected.
-    fn expected_fn_found_fn_mut_call(&self, err: &mut Diagnostic, sp: Span, act: &str) {
+    fn expected_fn_found_fn_mut_call(&self, err: &mut DiagnosticBuilder<'_>, sp: Span, act: &str) {
         err.span_label(sp, format!("cannot {act}"));
 
         let hir = self.infcx.tcx.hir();
diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
index 93e28a5f3f3..b2c7a98142e 100644
--- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
@@ -5,7 +5,7 @@
 #![allow(rustc::untranslatable_diagnostic)]
 
 use rustc_data_structures::fx::FxIndexSet;
-use rustc_errors::Diagnostic;
+use rustc_errors::DiagnosticBuilder;
 use rustc_middle::ty::RegionVid;
 use smallvec::SmallVec;
 use std::collections::BTreeMap;
@@ -158,13 +158,13 @@ impl OutlivesSuggestionBuilder {
         self.constraints_to_add.entry(fr).or_default().push(outlived_fr);
     }
 
-    /// Emit an intermediate note on the given `Diagnostic` if the involved regions are
+    /// Emit an intermediate note on the given `DiagnosticBuilder` if the involved regions are
     /// suggestable.
     pub(crate) fn intermediate_suggestion(
         &mut self,
         mbcx: &MirBorrowckCtxt<'_, '_>,
         errci: &ErrorConstraintInfo<'_>,
-        diag: &mut Diagnostic,
+        diag: &mut DiagnosticBuilder<'_>,
     ) {
         // Emit an intermediate note.
         let fr_name = self.region_vid_to_name(mbcx, errci.fr);
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index e8effd5c163..50d22881c3e 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -1,7 +1,7 @@
 //! Error reporting machinery for lifetime errors.
 
 use rustc_data_structures::fx::FxIndexSet;
-use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, MultiSpan};
+use rustc_errors::{Applicability, DiagnosticBuilder, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::Res::Def;
 use rustc_hir::def_id::DefId;
@@ -251,6 +251,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
         hrtb_bounds.iter().for_each(|bound| {
             let Trait(PolyTraitRef { trait_ref, span: trait_span, .. }, _) = bound else { return; };
+            // FIXME: make this translatable
+            #[allow(rustc::diagnostic_outside_of_impl)]
+            #[allow(rustc::untranslatable_diagnostic)]
             diag.span_note(
                 *trait_span,
                 "due to current limitations in the borrow checker, this implies a `'static` lifetime"
@@ -421,6 +424,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
     /// ```
     ///
     /// Here we would be invoked with `fr = 'a` and `outlived_fr = 'b`.
+    // FIXME: make this translatable
+    #[allow(rustc::diagnostic_outside_of_impl)]
+    #[allow(rustc::untranslatable_diagnostic)]
     pub(crate) fn report_region_error(
         &mut self,
         fr: RegionVid,
@@ -685,12 +691,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             borrowck_errors::borrowed_data_escapes_closure(self.infcx.tcx, *span, escapes_from);
 
         if let Some((Some(outlived_fr_name), outlived_fr_span)) = outlived_fr_name_and_span {
+            // FIXME: make this translatable
+            #[allow(rustc::diagnostic_outside_of_impl)]
+            #[allow(rustc::untranslatable_diagnostic)]
             diag.span_label(
                 outlived_fr_span,
                 format!("`{outlived_fr_name}` declared here, outside of the {escapes_from} body",),
             );
         }
 
+        // FIXME: make this translatable
+        #[allow(rustc::diagnostic_outside_of_impl)]
+        #[allow(rustc::untranslatable_diagnostic)]
         if let Some((Some(fr_name), fr_span)) = fr_name_and_span {
             diag.span_label(
                 fr_span,
@@ -714,6 +726,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 let outlived_fr_region_name = self.give_region_a_name(errci.outlived_fr).unwrap();
                 outlived_fr_region_name.highlight_region_name(&mut diag);
 
+                // FIXME: make this translatable
+                #[allow(rustc::diagnostic_outside_of_impl)]
+                #[allow(rustc::untranslatable_diagnostic)]
                 diag.span_label(
                     *span,
                     format!(
@@ -808,7 +823,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
     /// ```
     fn add_static_impl_trait_suggestion(
         &self,
-        diag: &mut Diagnostic,
+        diag: &mut DiagnosticBuilder<'_>,
         fr: RegionVid,
         // We need to pass `fr_name` - computing it again will label it twice.
         fr_name: RegionName,
@@ -897,7 +912,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
     fn maybe_suggest_constrain_dyn_trait_impl(
         &self,
-        diag: &mut Diagnostic,
+        diag: &mut DiagnosticBuilder<'_>,
         f: Region<'tcx>,
         o: Region<'tcx>,
         category: &ConstraintCategory<'tcx>,
@@ -959,7 +974,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
     #[instrument(skip(self, err), level = "debug")]
     fn suggest_constrain_dyn_trait_in_impl(
         &self,
-        err: &mut Diagnostic,
+        err: &mut DiagnosticBuilder<'_>,
         found_dids: &FxIndexSet<DefId>,
         ident: Ident,
         self_ty: &hir::Ty<'_>,
@@ -994,7 +1009,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
     fn suggest_adding_lifetime_params(
         &self,
-        diag: &mut Diagnostic,
+        diag: &mut DiagnosticBuilder<'_>,
         sub: RegionVid,
         sup: RegionVid,
     ) {
@@ -1023,7 +1038,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         suggest_adding_lifetime_params(self.infcx.tcx, sub, ty_sup, ty_sub, diag);
     }
 
-    fn suggest_move_on_borrowing_closure(&self, diag: &mut Diagnostic) {
+    fn suggest_move_on_borrowing_closure(&self, diag: &mut DiagnosticBuilder<'_>) {
         let map = self.infcx.tcx.hir();
         let body_id = map.body_owned_by(self.mir_def_id());
         let expr = &map.body(body_id).value.peel_blocks();
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index e008d230656..e228bef1139 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -5,7 +5,7 @@ use std::fmt::{self, Display};
 use std::iter;
 
 use rustc_data_structures::fx::IndexEntry;
-use rustc_errors::Diagnostic;
+use rustc_errors::DiagnosticBuilder;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_middle::ty::print::RegionHighlightMode;
@@ -106,7 +106,7 @@ impl RegionName {
         }
     }
 
-    pub(crate) fn highlight_region_name(&self, diag: &mut Diagnostic) {
+    pub(crate) fn highlight_region_name(&self, diag: &mut DiagnosticBuilder<'_>) {
         match &self.source {
             RegionNameSource::NamedLateParamRegion(span)
             | RegionNameSource::NamedEarlyParamRegion(span) => {
@@ -626,9 +626,9 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                     | GenericArgKind::Const(_),
                     _,
                 ) => {
-                    // HIR lowering sometimes doesn't catch this in erroneous
-                    // programs, so we need to use span_delayed_bug here. See #82126.
-                    self.dcx().span_delayed_bug(
+                    // This was previously a `span_delayed_bug` and could be
+                    // reached by the test for #82126, but no longer.
+                    self.dcx().span_bug(
                         hir_arg.span(),
                         format!("unmatched arg and hir arg: found {kind:?} vs {hir_arg:?}"),
                     );
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 6c2a511538d..dbaa9e5bcfa 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -2497,6 +2497,8 @@ mod diags {
             }
             for (_, (mut diag, count)) in std::mem::take(&mut self.diags.buffered_mut_errors) {
                 if count > 10 {
+                    #[allow(rustc::diagnostic_outside_of_impl)]
+                    #[allow(rustc::untranslatable_diagnostic)]
                     diag.note(format!("...and {} other attempted mutable borrows", count - 10));
                 }
                 self.diags.buffered_diags.push(BufferedDiag::Error(diag));
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 34d60fc8f6e..ce2c0dbaff7 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -5,7 +5,7 @@ use rustc_data_structures::binary_search_util;
 use rustc_data_structures::frozen::Frozen;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::graph::scc::Sccs;
-use rustc_errors::Diagnostic;
+use rustc_errors::DiagnosticBuilder;
 use rustc_hir::def_id::CRATE_DEF_ID;
 use rustc_index::{IndexSlice, IndexVec};
 use rustc_infer::infer::outlives::test_type_match;
@@ -592,7 +592,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     }
 
     /// Adds annotations for `#[rustc_regions]`; see `UniversalRegions::annotate`.
-    pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic) {
+    pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut DiagnosticBuilder<'_, ()>) {
         self.universal_regions.annotate(tcx, err)
     }
 
diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index fc600af1b76..e5ebf97cfc4 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -100,7 +100,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         locations: Locations,
     ) {
         for (predicate, span) in instantiated_predicates {
-            debug!(?predicate);
+            debug!(?span, ?predicate);
             let category = ConstraintCategory::Predicate(span);
             let predicate = self.normalize_with_category(predicate, locations, category);
             self.prove_predicate(predicate, locations, category);
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index c97e3170166..de75a9857f8 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -8,7 +8,7 @@ use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, Const
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::Span;
 use rustc_trait_selection::solve::deeply_normalize;
 use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
 use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
@@ -183,7 +183,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
 
                         // we don't actually use this for anything, but
                         // the `TypeOutlives` code needs an origin.
-                        let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
+                        let origin = infer::RelateParamBound(self.span, t1, None);
 
                         TypeOutlives::new(
                             &mut *self,
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index 2e0caf44819..897918fb0a4 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -10,7 +10,7 @@ use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::traits::query::OutlivesBound;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt};
-use rustc_span::{ErrorGuaranteed, DUMMY_SP};
+use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::solve::deeply_normalize;
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
 use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
@@ -269,7 +269,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
             debug!("build: input_or_output={:?}", ty);
             // We add implied bounds from both the unnormalized and normalized ty.
             // See issue #87748
-            let constraints_unnorm = self.add_implied_bounds(ty);
+            let constraints_unnorm = self.add_implied_bounds(ty, span);
             if let Some(c) = constraints_unnorm {
                 constraints.push(c)
             }
@@ -299,7 +299,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
             // ```
             // Both &Self::Bar and &() are WF
             if ty != norm_ty {
-                let constraints_norm = self.add_implied_bounds(norm_ty);
+                let constraints_norm = self.add_implied_bounds(norm_ty, span);
                 if let Some(c) = constraints_norm {
                     constraints.push(c)
                 }
@@ -316,6 +316,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
                     .and(type_op::normalize::Normalize::new(ty))
                     .fully_perform(self.infcx, span)
                 else {
+                    // Note: this path is currently not reached in any test, so
+                    // any example that triggers this would be worth minimizing
+                    // and converting into a test.
                     tcx.dcx().span_delayed_bug(span, format!("failed to normalize {ty:?}"));
                     continue;
                 };
@@ -323,7 +326,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
 
                 // We currently add implied bounds from the normalized ty only.
                 // This is more conservative and matches wfcheck behavior.
-                let c = self.add_implied_bounds(norm_ty);
+                let c = self.add_implied_bounds(norm_ty, span);
                 constraints.extend(c);
             }
         }
@@ -361,11 +364,15 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
     /// the same time, compute and add any implied bounds that come
     /// from this local.
     #[instrument(level = "debug", skip(self))]
-    fn add_implied_bounds(&mut self, ty: Ty<'tcx>) -> Option<&'tcx QueryRegionConstraints<'tcx>> {
+    fn add_implied_bounds(
+        &mut self,
+        ty: Ty<'tcx>,
+        span: Span,
+    ) -> Option<&'tcx QueryRegionConstraints<'tcx>> {
         let TypeOpOutput { output: bounds, constraints, .. } = self
             .param_env
             .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
-            .fully_perform(self.infcx, DUMMY_SP)
+            .fully_perform(self.infcx, span)
             .map_err(|_: ErrorGuaranteed| debug!("failed to compute implied bounds {:?}", ty))
             .ok()?;
         debug!(?bounds, ?constraints);
diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index af5b635ae66..8af78b08f69 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -154,8 +154,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             if argument_index + 1 >= body.local_decls.len() {
                 self.tcx()
                     .dcx()
-                    .span_delayed_bug(body.span, "found more normalized_input_ty than local_decls");
-                break;
+                    .span_bug(body.span, "found more normalized_input_ty than local_decls");
             }
 
             // In MIR, argument N is stored in local N+1.
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 64469727d0d..81193902f9b 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -37,7 +37,7 @@ use rustc_mir_dataflow::points::DenseLocationMap;
 use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::sym;
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::Span;
 use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
 use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints;
 use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
@@ -220,14 +220,13 @@ pub(crate) fn type_check<'mir, 'tcx>(
                     "opaque_type_map",
                 ),
             );
-            let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type);
+            let hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type);
             trace!("finalized opaque type {:?} to {:#?}", opaque_type_key, hidden_type.ty.kind());
             if hidden_type.has_non_region_infer() {
-                let reported = infcx.dcx().span_delayed_bug(
+                infcx.dcx().span_bug(
                     decl.hidden_type.span,
                     format!("could not resolve {:#?}", hidden_type.ty.kind()),
                 );
-                hidden_type.ty = Ty::new_error(infcx.tcx, reported);
             }
 
             (opaque_type_key, hidden_type)
@@ -1014,7 +1013,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     ) -> Self {
         let mut checker = Self {
             infcx,
-            last_span: DUMMY_SP,
+            last_span: body.span,
             body,
             user_type_annotations: &body.user_type_annotations,
             param_env,
@@ -1089,10 +1088,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         );
 
         if result.is_err() {
-            self.infcx.dcx().span_delayed_bug(
-                self.body.span,
-                "failed re-defining predefined opaques in mir typeck",
-            );
+            self.infcx
+                .dcx()
+                .span_bug(self.body.span, "failed re-defining predefined opaques in mir typeck");
         }
     }
 
@@ -2766,7 +2764,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 self.param_env,
                 self.known_type_outlives_obligations,
                 locations,
-                DUMMY_SP,                   // irrelevant; will be overridden.
+                self.body.span,             // irrelevant; will be overridden.
                 ConstraintCategory::Boring, // same as above.
                 self.borrowck_context.constraints,
             )
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index ee0bd13109b..dd355c3525c 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -1,11 +1,14 @@
+use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::ErrorGuaranteed;
-use rustc_infer::infer::nll_relate::{TypeRelating, TypeRelatingDelegate};
-use rustc_infer::infer::NllRegionVariableOrigin;
-use rustc_infer::traits::PredicateObligations;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::{NllRegionVariableOrigin, ObligationEmittingRelation};
+use rustc_infer::traits::{Obligation, PredicateObligations};
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::traits::query::NoSolution;
-use rustc_middle::ty::relate::TypeRelation;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::traits::ObligationCause;
+use rustc_middle::ty::fold::FnMutDelegate;
+use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
 use rustc_span::symbol::sym;
 use rustc_span::{Span, Symbol};
 
@@ -32,12 +35,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         locations: Locations,
         category: ConstraintCategory<'tcx>,
     ) -> Result<(), NoSolution> {
-        TypeRelating::new(
-            self.infcx,
-            NllTypeRelatingDelegate::new(self, locations, category, UniverseInfo::relate(a, b)),
-            v,
-        )
-        .relate(a, b)?;
+        NllTypeRelating::new(self, locations, category, UniverseInfo::relate(a, b), v)
+            .relate(a, b)?;
         Ok(())
     }
 
@@ -49,9 +48,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         locations: Locations,
         category: ConstraintCategory<'tcx>,
     ) -> Result<(), NoSolution> {
-        TypeRelating::new(
-            self.infcx,
-            NllTypeRelatingDelegate::new(self, locations, category, UniverseInfo::other()),
+        NllTypeRelating::new(
+            self,
+            locations,
+            category,
+            UniverseInfo::other(),
             ty::Variance::Invariant,
         )
         .relate(a, b)?;
@@ -59,7 +60,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     }
 }
 
-struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
+pub struct NllTypeRelating<'me, 'bccx, 'tcx> {
     type_checker: &'me mut TypeChecker<'bccx, 'tcx>,
 
     /// Where (and why) is this relation taking place?
@@ -71,26 +72,177 @@ struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
     /// Information so that error reporting knows what types we are relating
     /// when reporting a bound region error.
     universe_info: UniverseInfo<'tcx>,
+
+    /// How are we relating `a` and `b`?
+    ///
+    /// - Covariant means `a <: b`.
+    /// - Contravariant means `b <: a`.
+    /// - Invariant means `a == b`.
+    /// - Bivariant means that it doesn't matter.
+    ambient_variance: ty::Variance,
+
+    ambient_variance_info: ty::VarianceDiagInfo<'tcx>,
 }
 
-impl<'me, 'bccx, 'tcx> NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
-    fn new(
+impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> {
+    pub fn new(
         type_checker: &'me mut TypeChecker<'bccx, 'tcx>,
         locations: Locations,
         category: ConstraintCategory<'tcx>,
         universe_info: UniverseInfo<'tcx>,
+        ambient_variance: ty::Variance,
     ) -> Self {
-        Self { type_checker, locations, category, universe_info }
+        Self {
+            type_checker,
+            locations,
+            category,
+            universe_info,
+            ambient_variance,
+            ambient_variance_info: ty::VarianceDiagInfo::default(),
+        }
     }
-}
 
-impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
-    fn span(&self) -> Span {
-        self.locations.span(self.type_checker.body)
+    fn ambient_covariance(&self) -> bool {
+        match self.ambient_variance {
+            ty::Variance::Covariant | ty::Variance::Invariant => true,
+            ty::Variance::Contravariant | ty::Variance::Bivariant => false,
+        }
     }
 
-    fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        self.type_checker.param_env
+    fn ambient_contravariance(&self) -> bool {
+        match self.ambient_variance {
+            ty::Variance::Contravariant | ty::Variance::Invariant => true,
+            ty::Variance::Covariant | ty::Variance::Bivariant => false,
+        }
+    }
+
+    fn relate_opaques(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
+        let infcx = self.type_checker.infcx;
+        debug_assert!(!infcx.next_trait_solver());
+        let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
+        // `handle_opaque_type` cannot handle subtyping, so to support subtyping
+        // we instead eagerly generalize here. This is a bit of a mess but will go
+        // away once we're using the new solver.
+        let mut enable_subtyping = |ty, ty_is_expected| {
+            let ty_vid = infcx.next_ty_var_id_in_universe(
+                TypeVariableOrigin {
+                    kind: TypeVariableOriginKind::MiscVariable,
+                    span: self.span(),
+                },
+                ty::UniverseIndex::ROOT,
+            );
+
+            let variance = if ty_is_expected {
+                self.ambient_variance
+            } else {
+                self.ambient_variance.xform(ty::Contravariant)
+            };
+
+            self.type_checker.infcx.instantiate_ty_var(
+                self,
+                ty_is_expected,
+                ty_vid,
+                variance,
+                ty,
+            )?;
+            Ok(infcx.resolve_vars_if_possible(Ty::new_infer(infcx.tcx, ty::TyVar(ty_vid))))
+        };
+
+        let (a, b) = match (a.kind(), b.kind()) {
+            (&ty::Alias(ty::Opaque, ..), _) => (a, enable_subtyping(b, false)?),
+            (_, &ty::Alias(ty::Opaque, ..)) => (enable_subtyping(a, true)?, b),
+            _ => unreachable!(
+                "expected at least one opaque type in `relate_opaques`, got {a} and {b}."
+            ),
+        };
+        let cause = ObligationCause::dummy_with_span(self.span());
+        let obligations =
+            infcx.handle_opaque_type(a, b, true, &cause, self.param_env())?.obligations;
+        self.register_obligations(obligations);
+        Ok(())
+    }
+
+    fn enter_forall<T, U>(
+        &mut self,
+        binder: ty::Binder<'tcx, T>,
+        f: impl FnOnce(&mut Self, T) -> U,
+    ) -> U
+    where
+        T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy,
+    {
+        let value = if let Some(inner) = binder.no_bound_vars() {
+            inner
+        } else {
+            let infcx = self.type_checker.infcx;
+            let mut lazy_universe = None;
+            let delegate = FnMutDelegate {
+                regions: &mut |br: ty::BoundRegion| {
+                    // The first time this closure is called, create a
+                    // new universe for the placeholders we will make
+                    // from here out.
+                    let universe = lazy_universe.unwrap_or_else(|| {
+                        let universe = self.create_next_universe();
+                        lazy_universe = Some(universe);
+                        universe
+                    });
+
+                    let placeholder = ty::PlaceholderRegion { universe, bound: br };
+                    debug!(?placeholder);
+                    let placeholder_reg = self.next_placeholder_region(placeholder);
+                    debug!(?placeholder_reg);
+
+                    placeholder_reg
+                },
+                types: &mut |_bound_ty: ty::BoundTy| {
+                    unreachable!("we only replace regions in nll_relate, not types")
+                },
+                consts: &mut |_bound_var: ty::BoundVar, _ty| {
+                    unreachable!("we only replace regions in nll_relate, not consts")
+                },
+            };
+
+            infcx.tcx.replace_bound_vars_uncached(binder, delegate)
+        };
+
+        debug!(?value);
+        f(self, value)
+    }
+
+    #[instrument(skip(self), level = "debug")]
+    fn instantiate_binder_with_existentials<T>(&mut self, binder: ty::Binder<'tcx, T>) -> T
+    where
+        T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy,
+    {
+        if let Some(inner) = binder.no_bound_vars() {
+            return inner;
+        }
+
+        let infcx = self.type_checker.infcx;
+        let mut reg_map = FxHashMap::default();
+        let delegate = FnMutDelegate {
+            regions: &mut |br: ty::BoundRegion| {
+                if let Some(ex_reg_var) = reg_map.get(&br) {
+                    return *ex_reg_var;
+                } else {
+                    let ex_reg_var = self.next_existential_region_var(true, br.kind.get_name());
+                    debug!(?ex_reg_var);
+                    reg_map.insert(br, ex_reg_var);
+
+                    ex_reg_var
+                }
+            },
+            types: &mut |_bound_ty: ty::BoundTy| {
+                unreachable!("we only replace regions in nll_relate, not types")
+            },
+            consts: &mut |_bound_var: ty::BoundVar, _ty| {
+                unreachable!("we only replace regions in nll_relate, not consts")
+            },
+        };
+
+        let replaced = infcx.tcx.replace_bound_vars_uncached(binder, delegate);
+        debug!(?replaced);
+
+        replaced
     }
 
     fn create_next_universe(&mut self) -> ty::UniverseIndex {
@@ -143,22 +295,6 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
         reg
     }
 
-    #[instrument(skip(self), level = "debug")]
-    fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
-        let reg = self.type_checker.infcx.next_nll_region_var_in_universe(
-            NllRegionVariableOrigin::Existential { from_forall: false },
-            universe,
-        );
-
-        if cfg!(debug_assertions) {
-            let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut();
-            let prev = var_to_origin.insert(reg.as_var(), RegionCtxt::Existential(None));
-            assert_eq!(prev, None);
-        }
-
-        reg
-    }
-
     fn push_outlives(
         &mut self,
         sup: ty::Region<'tcx>,
@@ -179,11 +315,250 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
             },
         );
     }
+}
+
+impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.type_checker.infcx.tcx
+    }
+
+    fn tag(&self) -> &'static str {
+        "nll::subtype"
+    }
 
-    fn forbid_inference_vars() -> bool {
+    fn a_is_expected(&self) -> bool {
         true
     }
 
+    #[instrument(skip(self, info), level = "trace", ret)]
+    fn relate_with_variance<T: Relate<'tcx>>(
+        &mut self,
+        variance: ty::Variance,
+        info: ty::VarianceDiagInfo<'tcx>,
+        a: T,
+        b: T,
+    ) -> RelateResult<'tcx, T> {
+        let old_ambient_variance = self.ambient_variance;
+        self.ambient_variance = self.ambient_variance.xform(variance);
+        self.ambient_variance_info = self.ambient_variance_info.xform(info);
+
+        debug!(?self.ambient_variance);
+        // In a bivariant context this always succeeds.
+        let r =
+            if self.ambient_variance == ty::Variance::Bivariant { a } else { self.relate(a, b)? };
+
+        self.ambient_variance = old_ambient_variance;
+
+        Ok(r)
+    }
+
+    #[instrument(skip(self), level = "debug")]
+    fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+        let infcx = self.type_checker.infcx;
+
+        let a = self.type_checker.infcx.shallow_resolve(a);
+        assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b);
+
+        if a == b {
+            return Ok(a);
+        }
+
+        match (a.kind(), b.kind()) {
+            (_, &ty::Infer(ty::TyVar(_))) => {
+                span_bug!(
+                    self.span(),
+                    "should not be relating type variables on the right in MIR typeck"
+                );
+            }
+
+            (&ty::Infer(ty::TyVar(a_vid)), _) => {
+                infcx.instantiate_ty_var(self, true, a_vid, self.ambient_variance, b)?
+            }
+
+            (
+                &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
+                &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
+            ) if a_def_id == b_def_id || infcx.next_trait_solver() => {
+                infcx.super_combine_tys(self, a, b).map(|_| ()).or_else(|err| {
+                    // This behavior is only there for the old solver, the new solver
+                    // shouldn't ever fail. Instead, it unconditionally emits an
+                    // alias-relate goal.
+                    assert!(!self.type_checker.infcx.next_trait_solver());
+                    self.tcx().dcx().span_delayed_bug(
+                        self.span(),
+                        "failure to relate an opaque to itself should result in an error later on",
+                    );
+                    if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) }
+                })?;
+            }
+            (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
+            | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
+                if def_id.is_local() && !self.type_checker.infcx.next_trait_solver() =>
+            {
+                self.relate_opaques(a, b)?;
+            }
+
+            _ => {
+                debug!(?a, ?b, ?self.ambient_variance);
+
+                // Will also handle unification of `IntVar` and `FloatVar`.
+                self.type_checker.infcx.super_combine_tys(self, a, b)?;
+            }
+        }
+
+        Ok(a)
+    }
+
+    #[instrument(skip(self), level = "trace")]
+    fn regions(
+        &mut self,
+        a: ty::Region<'tcx>,
+        b: ty::Region<'tcx>,
+    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
+        debug!(?self.ambient_variance);
+
+        if self.ambient_covariance() {
+            // Covariant: &'a u8 <: &'b u8. Hence, `'a: 'b`.
+            self.push_outlives(a, b, self.ambient_variance_info);
+        }
+
+        if self.ambient_contravariance() {
+            // Contravariant: &'b u8 <: &'a u8. Hence, `'b: 'a`.
+            self.push_outlives(b, a, self.ambient_variance_info);
+        }
+
+        Ok(a)
+    }
+
+    fn consts(
+        &mut self,
+        a: ty::Const<'tcx>,
+        b: ty::Const<'tcx>,
+    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
+        let a = self.type_checker.infcx.shallow_resolve(a);
+        assert!(!a.has_non_region_infer(), "unexpected inference var {:?}", a);
+        assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b);
+
+        self.type_checker.infcx.super_combine_consts(self, a, b)
+    }
+
+    #[instrument(skip(self), level = "trace")]
+    fn binders<T>(
+        &mut self,
+        a: ty::Binder<'tcx, T>,
+        b: ty::Binder<'tcx, T>,
+    ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
+    where
+        T: Relate<'tcx>,
+    {
+        // We want that
+        //
+        // ```
+        // for<'a> fn(&'a u32) -> &'a u32 <:
+        //   fn(&'b u32) -> &'b u32
+        // ```
+        //
+        // but not
+        //
+        // ```
+        // fn(&'a u32) -> &'a u32 <:
+        //   for<'b> fn(&'b u32) -> &'b u32
+        // ```
+        //
+        // We therefore proceed as follows:
+        //
+        // - Instantiate binders on `b` universally, yielding a universe U1.
+        // - Instantiate binders on `a` existentially in U1.
+
+        debug!(?self.ambient_variance);
+
+        if let (Some(a), Some(b)) = (a.no_bound_vars(), b.no_bound_vars()) {
+            // Fast path for the common case.
+            self.relate(a, b)?;
+            return Ok(ty::Binder::dummy(a));
+        }
+
+        if self.ambient_covariance() {
+            // Covariance, so we want `for<..> A <: for<..> B` --
+            // therefore we compare any instantiation of A (i.e., A
+            // instantiated with existentials) against every
+            // instantiation of B (i.e., B instantiated with
+            // universals).
+
+            // Reset the ambient variance to covariant. This is needed
+            // to correctly handle cases like
+            //
+            //     for<'a> fn(&'a u32, &'a u32) == for<'b, 'c> fn(&'b u32, &'c u32)
+            //
+            // Somewhat surprisingly, these two types are actually
+            // **equal**, even though the one on the right looks more
+            // polymorphic. The reason is due to subtyping. To see it,
+            // consider that each function can call the other:
+            //
+            // - The left function can call the right with `'b` and
+            //   `'c` both equal to `'a`
+            //
+            // - The right function can call the left with `'a` set to
+            //   `{P}`, where P is the point in the CFG where the call
+            //   itself occurs. Note that `'b` and `'c` must both
+            //   include P. At the point, the call works because of
+            //   subtyping (i.e., `&'b u32 <: &{P} u32`).
+            let variance = std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant);
+
+            // Note: the order here is important. Create the placeholders first, otherwise
+            // we assign the wrong universe to the existential!
+            self.enter_forall(b, |this, b| {
+                let a = this.instantiate_binder_with_existentials(a);
+                this.relate(a, b)
+            })?;
+
+            self.ambient_variance = variance;
+        }
+
+        if self.ambient_contravariance() {
+            // Contravariance, so we want `for<..> A :> for<..> B`
+            // -- therefore we compare every instantiation of A (i.e.,
+            // A instantiated with universals) against any
+            // instantiation of B (i.e., B instantiated with
+            // existentials). Opposite of above.
+
+            // Reset ambient variance to contravariance. See the
+            // covariant case above for an explanation.
+            let variance =
+                std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant);
+
+            self.enter_forall(a, |this, a| {
+                let b = this.instantiate_binder_with_existentials(b);
+                this.relate(a, b)
+            })?;
+
+            self.ambient_variance = variance;
+        }
+
+        Ok(a)
+    }
+}
+
+impl<'bccx, 'tcx> ObligationEmittingRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
+    fn span(&self) -> Span {
+        self.locations.span(self.type_checker.body)
+    }
+
+    fn param_env(&self) -> ty::ParamEnv<'tcx> {
+        self.type_checker.param_env
+    }
+
+    fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>) {
+        self.register_obligations(
+            obligations
+                .into_iter()
+                .map(|to_pred| {
+                    Obligation::new(self.tcx(), ObligationCause::dummy(), self.param_env(), to_pred)
+                })
+                .collect(),
+        );
+    }
+
     fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
         let _: Result<_, ErrorGuaranteed> = self.type_checker.fully_perform_op(
             self.locations,
@@ -196,4 +571,32 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
             },
         );
     }
+
+    fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
+        unreachable!("manually overridden to handle ty::Variance::Contravariant ambient variance")
+    }
+
+    fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
+        self.register_predicates([ty::Binder::dummy(match self.ambient_variance {
+            ty::Variance::Covariant => ty::PredicateKind::AliasRelate(
+                a.into(),
+                b.into(),
+                ty::AliasRelationDirection::Subtype,
+            ),
+            // a :> b is b <: a
+            ty::Variance::Contravariant => ty::PredicateKind::AliasRelate(
+                b.into(),
+                a.into(),
+                ty::AliasRelationDirection::Subtype,
+            ),
+            ty::Variance::Invariant => ty::PredicateKind::AliasRelate(
+                a.into(),
+                b.into(),
+                ty::AliasRelationDirection::Equate,
+            ),
+            ty::Variance::Bivariant => {
+                unreachable!("cannot defer an alias-relate goal with Bivariant variance (yet?)")
+            }
+        })]);
+    }
 }
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index a69f5335f71..e7439481034 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -16,7 +16,7 @@
 #![allow(rustc::untranslatable_diagnostic)]
 
 use rustc_data_structures::fx::FxIndexMap;
-use rustc_errors::Diagnostic;
+use rustc_errors::DiagnosticBuilder;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::BodyOwnerKind;
@@ -343,7 +343,7 @@ impl<'tcx> UniversalRegions<'tcx> {
     /// that this region imposes on others. The methods in this file
     /// handle the part about dumping the inference context internal
     /// state.
-    pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic) {
+    pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut DiagnosticBuilder<'_, ()>) {
         match self.defining_ty {
             DefiningTy::Closure(def_id, args) => {
                 let v = with_no_trimmed_paths!(