about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs18
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs16
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/mod.rs5
-rw-r--r--compiler/rustc_mir/Cargo.toml1
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/bound_region_errors.rs341
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs2
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs22
-rw-r--r--compiler/rustc_mir/src/borrow_check/nll.rs2
-rw-r--r--compiler/rustc_mir/src/borrow_check/region_infer/mod.rs21
-rw-r--r--compiler/rustc_mir/src/borrow_check/type_check/canonical.rs158
-rw-r--r--compiler/rustc_mir/src/borrow_check/type_check/free_region_relations.rs11
-rw-r--r--compiler/rustc_mir/src/borrow_check/type_check/input_output.rs2
-rw-r--r--compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs6
-rw-r--r--compiler/rustc_mir/src/borrow_check/type_check/mod.rs153
-rw-r--r--compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs63
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs27
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs39
-rw-r--r--compiler/rustc_traits/src/lib.rs2
-rw-r--r--compiler/rustc_traits/src/type_op.rs26
20 files changed, 701 insertions, 216 deletions
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index b628381d5aa..3d48d4c2fca 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -1180,16 +1180,26 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     //         |   |
                     //         |   elided as they were the same
                     //         not elided, they were different, but irrelevant
+                    //
+                    // For bound lifetimes, keep the names of the lifetimes,
+                    // even if they are the same so that it's clear what's happening
+                    // if we have something like
+                    //
+                    // for<'r, 's> fn(Inv<'r>, Inv<'s>)
+                    // for<'r> fn(Inv<'r>, Inv<'r>)
                     let lifetimes = sub1.regions().zip(sub2.regions());
                     for (i, lifetimes) in lifetimes.enumerate() {
                         let l1 = lifetime_display(lifetimes.0);
                         let l2 = lifetime_display(lifetimes.1);
-                        if lifetimes.0 == lifetimes.1 {
-                            values.0.push_normal("'_");
-                            values.1.push_normal("'_");
-                        } else {
+                        if lifetimes.0 != lifetimes.1 {
                             values.0.push_highlighted(l1);
                             values.1.push_highlighted(l2);
+                        } else if lifetimes.0.is_late_bound() {
+                            values.0.push_normal(l1);
+                            values.1.push_normal(l2);
+                        } else {
+                            values.0.push_normal("'_");
+                            values.1.push_normal("'_");
                         }
                         self.push_comma(&mut values.0, &mut values.1, len, i);
                     }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 10217a5f574..9b9ded5c6ba 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -1,4 +1,5 @@
 pub use self::freshen::TypeFreshener;
+pub use self::lexical_region_resolve::RegionResolutionError;
 pub use self::LateBoundRegionConversionTime::*;
 pub use self::RegionVariableOrigin::*;
 pub use self::SubregionOrigin::*;
@@ -1110,7 +1111,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     /// etc) this is the root universe U0. For inference variables or
     /// placeholders, however, it will return the universe which which
     /// they are associated.
-    fn universe_of_region(&self, r: ty::Region<'tcx>) -> ty::UniverseIndex {
+    pub fn universe_of_region(&self, r: ty::Region<'tcx>) -> ty::UniverseIndex {
         self.inner.borrow_mut().unwrap_region_constraints().universe(r)
     }
 
@@ -1288,6 +1289,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         op(inner.unwrap_region_constraints().data())
     }
 
+    pub fn region_var_origin(&self, vid: ty::RegionVid) -> RegionVariableOrigin {
+        let mut inner = self.inner.borrow_mut();
+        let inner = &mut *inner;
+        inner
+            .region_constraint_storage
+            .as_mut()
+            .expect("regions already resolved")
+            .with_log(&mut inner.undo_log)
+            .var_origin(vid)
+    }
+
     /// Takes ownership of the list of variable regions. This implies
     /// that all the region constraints have already been taken, and
     /// hence that `resolve_regions_and_report_errors` can never be
@@ -1505,7 +1517,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         self.inner.borrow_mut().projection_cache().clear();
     }
 
-    fn universe(&self) -> ty::UniverseIndex {
+    pub fn universe(&self) -> ty::UniverseIndex {
         self.universe.get()
     }
 
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index 7f4c33c5792..5adbfd469a4 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -445,6 +445,11 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
         self.var_infos[vid].universe
     }
 
+    /// Returns the origin for the given variable.
+    pub fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin {
+        self.var_infos[vid].origin
+    }
+
     fn add_constraint(&mut self, constraint: Constraint<'tcx>, origin: SubregionOrigin<'tcx>) {
         // cannot add constraints once regions are resolved
         debug!("RegionConstraintCollector: add_constraint({:?})", constraint);
diff --git a/compiler/rustc_mir/Cargo.toml b/compiler/rustc_mir/Cargo.toml
index 7656cf38cc1..3049fb3b383 100644
--- a/compiler/rustc_mir/Cargo.toml
+++ b/compiler/rustc_mir/Cargo.toml
@@ -27,6 +27,7 @@ rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
 rustc_target = { path = "../rustc_target" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
+rustc_traits = { path = "../rustc_traits" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_span = { path = "../rustc_span" }
 rustc_apfloat = { path = "../rustc_apfloat" }
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/bound_region_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/bound_region_errors.rs
new file mode 100644
index 00000000000..d0284dd0302
--- /dev/null
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/bound_region_errors.rs
@@ -0,0 +1,341 @@
+use rustc_errors::DiagnosticBuilder;
+use rustc_infer::infer::canonical::Canonical;
+use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError;
+use rustc_infer::infer::region_constraints::Constraint;
+use rustc_infer::infer::{InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt as _};
+use rustc_infer::traits::{Normalized, ObligationCause, TraitEngine, TraitEngineExt};
+use rustc_middle::ty::error::TypeError;
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc_span::Span;
+use rustc_trait_selection::traits::query::type_op;
+use rustc_trait_selection::traits::{SelectionContext, TraitEngineExt as _};
+use rustc_traits::type_op_prove_predicate_with_span;
+
+use std::fmt;
+use std::rc::Rc;
+
+use crate::borrow_check::region_infer::values::RegionElement;
+use crate::borrow_check::MirBorrowckCtxt;
+
+#[derive(Clone)]
+crate struct UniverseInfo<'tcx>(UniverseInfoInner<'tcx>);
+
+/// What operation a universe was created for.
+#[derive(Clone)]
+enum UniverseInfoInner<'tcx> {
+    /// Relating two types which have binders.
+    RelateTys { expected: Ty<'tcx>, found: Ty<'tcx> },
+    /// Created from performing a `TypeOp`.
+    TypeOp(Rc<dyn TypeOpInfo<'tcx> + 'tcx>),
+    /// Any other reason.
+    Other,
+}
+
+impl UniverseInfo<'tcx> {
+    crate fn other() -> UniverseInfo<'tcx> {
+        UniverseInfo(UniverseInfoInner::Other)
+    }
+
+    crate fn relate(expected: Ty<'tcx>, found: Ty<'tcx>) -> UniverseInfo<'tcx> {
+        UniverseInfo(UniverseInfoInner::RelateTys { expected, found })
+    }
+
+    crate fn report_error(
+        &self,
+        mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
+        placeholder: ty::PlaceholderRegion,
+        error_element: RegionElement,
+        span: Span,
+    ) {
+        match self.0 {
+            UniverseInfoInner::RelateTys { expected, found } => {
+                let body_id = mbcx.infcx.tcx.hir().local_def_id_to_hir_id(mbcx.mir_def_id());
+                let err = mbcx.infcx.report_mismatched_types(
+                    &ObligationCause::misc(span, body_id),
+                    expected,
+                    found,
+                    TypeError::RegionsPlaceholderMismatch,
+                );
+                err.buffer(&mut mbcx.errors_buffer);
+            }
+            UniverseInfoInner::TypeOp(ref type_op_info) => {
+                type_op_info.report_error(mbcx, placeholder, error_element, span);
+            }
+            UniverseInfoInner::Other => {
+                // FIXME: This error message isn't great, but it doesn't show
+                // up in the existing UI tests. Consider investigating this
+                // some more.
+                mbcx.infcx
+                    .tcx
+                    .sess
+                    .struct_span_err(span, "higher-ranked subtype error")
+                    .buffer(&mut mbcx.errors_buffer);
+            }
+        }
+    }
+}
+
+crate trait ToUniverseInfo<'tcx> {
+    fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx>;
+}
+
+impl<'tcx> ToUniverseInfo<'tcx>
+    for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>
+{
+    fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
+        UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(PredicateQuery {
+            canonical_query: self,
+            base_universe,
+        })))
+    }
+}
+
+impl<'tcx, T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx> ToUniverseInfo<'tcx>
+    for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>
+{
+    fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
+        UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(NormalizeQuery {
+            canonical_query: self,
+            base_universe,
+        })))
+    }
+}
+
+impl<'tcx> ToUniverseInfo<'tcx>
+    for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>
+{
+    fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
+        // Ascribe user type isn't usually called on types that have different
+        // bound regions.
+        UniverseInfo::other()
+    }
+}
+
+impl<'tcx, F, G> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::CustomTypeOp<F, G>> {
+    fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
+        // We can't rerun custom type ops.
+        UniverseInfo::other()
+    }
+}
+
+#[allow(unused_lifetimes)]
+trait TypeOpInfo<'tcx> {
+    /// Returns an error to be reported if rerunning the type op fails to
+    /// recover the error's cause.
+    fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;
+
+    fn base_universe(&self) -> ty::UniverseIndex;
+
+    fn nice_error(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        span: Span,
+        placeholder_region: ty::Region<'tcx>,
+        error_region: Option<ty::Region<'tcx>>,
+    ) -> Option<DiagnosticBuilder<'tcx>>;
+
+    fn report_error(
+        &self,
+        mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
+        placeholder: ty::PlaceholderRegion,
+        error_element: RegionElement,
+        span: Span,
+    ) {
+        let tcx = mbcx.infcx.tcx;
+        let base_universe = self.base_universe();
+
+        let adjusted_universe = if let Some(adjusted) =
+            placeholder.universe.as_u32().checked_sub(base_universe.as_u32())
+        {
+            adjusted
+        } else {
+            self.fallback_error(tcx, span).buffer(&mut mbcx.errors_buffer);
+            return;
+        };
+
+        let placeholder_region = tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
+            name: placeholder.name,
+            universe: adjusted_universe.into(),
+        }));
+
+        let error_region =
+            if let RegionElement::PlaceholderRegion(error_placeholder) = error_element {
+                let adjusted_universe =
+                    error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32());
+                adjusted_universe.map(|adjusted| {
+                    tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
+                        name: error_placeholder.name,
+                        universe: adjusted.into(),
+                    }))
+                })
+            } else {
+                None
+            };
+
+        debug!(?placeholder_region);
+
+        let nice_error = self.nice_error(tcx, span, placeholder_region, error_region);
+
+        if let Some(nice_error) = nice_error {
+            nice_error.buffer(&mut mbcx.errors_buffer);
+        } else {
+            self.fallback_error(tcx, span).buffer(&mut mbcx.errors_buffer);
+        }
+    }
+}
+
+struct PredicateQuery<'tcx> {
+    canonical_query:
+        Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>,
+    base_universe: ty::UniverseIndex,
+}
+
+impl TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
+    fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+        let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
+        err.note(&format!("could not prove {}", self.canonical_query.value.value.predicate));
+        err
+    }
+
+    fn base_universe(&self) -> ty::UniverseIndex {
+        self.base_universe
+    }
+
+    fn nice_error(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        span: Span,
+        placeholder_region: ty::Region<'tcx>,
+        error_region: Option<ty::Region<'tcx>>,
+    ) -> Option<DiagnosticBuilder<'tcx>> {
+        tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| {
+            let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
+            type_op_prove_predicate_with_span(infcx, &mut *fulfill_cx, key, Some(span));
+            try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
+        })
+    }
+}
+
+struct NormalizeQuery<'tcx, T> {
+    canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>,
+    base_universe: ty::UniverseIndex,
+}
+
+impl<T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T>
+where
+    T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx,
+{
+    fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+        let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
+        err.note(&format!("could not normalize `{}`", self.canonical_query.value.value.value));
+        err
+    }
+
+    fn base_universe(&self) -> ty::UniverseIndex {
+        self.base_universe
+    }
+
+    fn nice_error(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        span: Span,
+        placeholder_region: ty::Region<'tcx>,
+        error_region: Option<ty::Region<'tcx>>,
+    ) -> Option<DiagnosticBuilder<'tcx>> {
+        tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| {
+            let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
+
+            let mut selcx = SelectionContext::new(infcx);
+
+            // FIXME(lqd): Unify and de-duplicate the following with the actual
+            // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
+            // `ObligationCause`. The normalization results are currently different between
+            // `AtExt::normalize` used in the query and `normalize` called below: the former fails
+            // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check
+            // after #85499 lands to see if its fixes have erased this difference.
+            let (param_env, value) = key.into_parts();
+            let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize(
+                &mut selcx,
+                param_env,
+                ObligationCause::dummy_with_span(span),
+                value.value,
+            );
+            fulfill_cx.register_predicate_obligations(infcx, obligations);
+
+            try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
+        })
+    }
+}
+
+fn try_extract_error_from_fulfill_cx<'tcx>(
+    mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>,
+    infcx: &InferCtxt<'_, 'tcx>,
+    placeholder_region: ty::Region<'tcx>,
+    error_region: Option<ty::Region<'tcx>>,
+) -> Option<DiagnosticBuilder<'tcx>> {
+    let tcx = infcx.tcx;
+
+    // We generally shouldn't have errors here because the query was
+    // already run, but there's no point using `delay_span_bug`
+    // when we're going to emit an error here anyway.
+    let _errors = fulfill_cx.select_all_or_error(infcx).err().unwrap_or_else(Vec::new);
+
+    let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| {
+        debug!(?region_constraints);
+        region_constraints.constraints.iter().find_map(|(constraint, cause)| {
+            match *constraint {
+                Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => {
+                    Some((sub, cause.clone()))
+                }
+                // FIXME: Should this check the universe of the var?
+                Constraint::VarSubReg(vid, sup) if sup == placeholder_region => {
+                    Some((tcx.mk_region(ty::ReVar(vid)), cause.clone()))
+                }
+                _ => None,
+            }
+        })
+    })?;
+
+    debug!(?sub_region, ?cause);
+    let nice_error = match (error_region, sub_region) {
+        (Some(error_region), &ty::ReVar(vid)) => NiceRegionError::new(
+            infcx,
+            RegionResolutionError::SubSupConflict(
+                vid,
+                infcx.region_var_origin(vid),
+                cause.clone(),
+                error_region,
+                cause.clone(),
+                placeholder_region,
+            ),
+        ),
+        (Some(error_region), _) => NiceRegionError::new(
+            infcx,
+            RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region),
+        ),
+        // Note universe here is wrong...
+        (None, &ty::ReVar(vid)) => NiceRegionError::new(
+            infcx,
+            RegionResolutionError::UpperBoundUniverseConflict(
+                vid,
+                infcx.region_var_origin(vid),
+                infcx.universe_of_region(sub_region),
+                cause.clone(),
+                placeholder_region,
+            ),
+        ),
+        (None, _) => NiceRegionError::new(
+            infcx,
+            RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region),
+        ),
+    };
+    nice_error.try_report_from_nll().or_else(|| {
+        if let SubregionOrigin::Subtype(trace) = cause {
+            Some(
+                infcx.report_and_explain_type_error(*trace, &TypeError::RegionsPlaceholderMismatch),
+            )
+        } else {
+            None
+        }
+    })
+}
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
index 1bb8c7ebe5a..55c6410ed32 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
@@ -28,12 +28,14 @@ mod outlives_suggestion;
 mod region_name;
 mod var_name;
 
+mod bound_region_errors;
 mod conflict_errors;
 mod explain_borrow;
 mod move_errors;
 mod mutability_errors;
 mod region_errors;
 
+crate use bound_region_errors::{ToUniverseInfo, UniverseInfo};
 crate use mutability_errors::AccessKind;
 crate use outlives_suggestion::OutlivesSuggestionBuilder;
 crate use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs
index 1460c2378d1..fe9df41db45 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs
@@ -75,8 +75,8 @@ crate enum RegionErrorKind<'tcx> {
         longer_fr: RegionVid,
         /// The region element that erroneously must be outlived by `longer_fr`.
         error_element: RegionElement,
-        /// The origin of the placeholder region.
-        fr_origin: NllRegionVariableOrigin,
+        /// The placeholder region.
+        placeholder: ty::PlaceholderRegion,
     },
 
     /// Any other lifetime error.
@@ -210,25 +210,23 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
                 RegionErrorKind::BoundUniversalRegionError {
                     longer_fr,
-                    fr_origin,
+                    placeholder,
                     error_element,
                 } => {
-                    let error_region = self.regioncx.region_from_element(longer_fr, error_element);
+                    let error_vid = self.regioncx.region_from_element(longer_fr, &error_element);
 
                     // Find the code to blame for the fact that `longer_fr` outlives `error_fr`.
                     let (_, span) = self.regioncx.find_outlives_blame_span(
                         &self.body,
                         longer_fr,
-                        fr_origin,
-                        error_region,
+                        NllRegionVariableOrigin::Placeholder(placeholder),
+                        error_vid,
                     );
 
-                    // FIXME: improve this error message
-                    self.infcx
-                        .tcx
-                        .sess
-                        .struct_span_err(span, "higher-ranked subtype error")
-                        .buffer(&mut self.errors_buffer);
+                    let universe = placeholder.universe;
+                    let universe_info = self.regioncx.universe_info(universe);
+
+                    universe_info.report_error(self, placeholder, error_element, span);
                 }
 
                 RegionErrorKind::RegionError { fr_origin, longer_fr, shorter_fr, is_reported } => {
diff --git a/compiler/rustc_mir/src/borrow_check/nll.rs b/compiler/rustc_mir/src/borrow_check/nll.rs
index b74b1eb4952..66ca94d3b41 100644
--- a/compiler/rustc_mir/src/borrow_check/nll.rs
+++ b/compiler/rustc_mir/src/borrow_check/nll.rs
@@ -241,6 +241,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
         outlives_constraints,
         member_constraints,
         closure_bounds_mapping,
+        universe_causes,
         type_tests,
     } = constraints;
     let placeholder_indices = Rc::new(placeholder_indices);
@@ -262,6 +263,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
         outlives_constraints,
         member_constraints,
         closure_bounds_mapping,
+        universe_causes,
         type_tests,
         liveness_constraints,
         elements,
diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
index c40e6bf1ec3..a96cdbc13f3 100644
--- a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
@@ -21,7 +21,7 @@ use crate::borrow_check::{
     constraints::{
         graph::NormalConstraintGraph, ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet,
     },
-    diagnostics::{RegionErrorKind, RegionErrors},
+    diagnostics::{RegionErrorKind, RegionErrors, UniverseInfo},
     member_constraints::{MemberConstraintSet, NllMemberConstraintIndex},
     nll::{PoloniusOutput, ToRegionVid},
     region_infer::reverse_sccs::ReverseSccGraph,
@@ -84,6 +84,9 @@ pub struct RegionInferenceContext<'tcx> {
     closure_bounds_mapping:
         FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>,
 
+    /// Map universe indexes to information on why we created it.
+    universe_causes: IndexVec<ty::UniverseIndex, UniverseInfo<'tcx>>,
+
     /// Contains the minimum universe of any variable within the same
     /// SCC. We will ensure that no SCC contains values that are not
     /// visible from this index.
@@ -253,6 +256,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             Location,
             FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>,
         >,
+        universe_causes: IndexVec<ty::UniverseIndex, UniverseInfo<'tcx>>,
         type_tests: Vec<TypeTest<'tcx>>,
         liveness_constraints: LivenessValues<RegionVid>,
         elements: &Rc<RegionValueElements>,
@@ -293,6 +297,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             member_constraints,
             member_constraints_applied: Vec::new(),
             closure_bounds_mapping,
+            universe_causes,
             scc_universes,
             scc_representatives,
             scc_values,
@@ -1632,7 +1637,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         errors_buffer.push(RegionErrorKind::BoundUniversalRegionError {
             longer_fr,
             error_element,
-            fr_origin: NllRegionVariableOrigin::Placeholder(placeholder),
+            placeholder,
         });
     }
 
@@ -1918,8 +1923,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     }
 
     /// Get the region outlived by `longer_fr` and live at `element`.
-    crate fn region_from_element(&self, longer_fr: RegionVid, element: RegionElement) -> RegionVid {
-        match element {
+    crate fn region_from_element(
+        &self,
+        longer_fr: RegionVid,
+        element: &RegionElement,
+    ) -> RegionVid {
+        match *element {
             RegionElement::Location(l) => self.find_sub_region_live_at(longer_fr, l),
             RegionElement::RootUniversalRegion(r) => r,
             RegionElement::PlaceholderRegion(error_placeholder) => self
@@ -2138,6 +2147,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
         categorized_path.remove(0)
     }
+
+    crate fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
+        self.universe_causes[universe].clone()
+    }
 }
 
 impl<'tcx> RegionDefinition<'tcx> {
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/canonical.rs b/compiler/rustc_mir/src/borrow_check/type_check/canonical.rs
new file mode 100644
index 00000000000..9fafcfafe67
--- /dev/null
+++ b/compiler/rustc_mir/src/borrow_check/type_check/canonical.rs
@@ -0,0 +1,158 @@
+use std::fmt;
+
+use rustc_hir as hir;
+use rustc_infer::infer::canonical::Canonical;
+use rustc_infer::traits::query::NoSolution;
+use rustc_middle::mir::ConstraintCategory;
+use rustc_middle::ty::{self, ToPredicate, TypeFoldable};
+use rustc_span::Span;
+use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
+use rustc_trait_selection::traits::query::Fallible;
+
+use crate::borrow_check::diagnostics::{ToUniverseInfo, UniverseInfo};
+
+use super::{Locations, NormalizeLocation, TypeChecker};
+
+impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
+    /// Given some operation `op` that manipulates types, proves
+    /// predicates, or otherwise uses the inference context, executes
+    /// `op` and then executes all the further obligations that `op`
+    /// returns. This will yield a set of outlives constraints amongst
+    /// regions which are extracted and stored as having occurred at
+    /// `locations`.
+    ///
+    /// **Any `rustc_infer::infer` operations that might generate region
+    /// constraints should occur within this method so that those
+    /// constraints can be properly localized!**
+    pub(super) fn fully_perform_op<R, Op>(
+        &mut self,
+        locations: Locations,
+        category: ConstraintCategory,
+        op: Op,
+    ) -> Fallible<R>
+    where
+        Op: type_op::TypeOp<'tcx, Output = R>,
+        Canonical<'tcx, Op>: ToUniverseInfo<'tcx>,
+    {
+        let old_universe = self.infcx.universe();
+
+        let TypeOpOutput { output, constraints, canonicalized_query } =
+            op.fully_perform(self.infcx)?;
+
+        if let Some(data) = &constraints {
+            self.push_region_constraints(locations, category, data);
+        }
+
+        let universe = self.infcx.universe();
+
+        if old_universe != universe {
+            let universe_info = match canonicalized_query {
+                Some(canonicalized_query) => canonicalized_query.to_universe_info(old_universe),
+                None => UniverseInfo::other(),
+            };
+            for u in old_universe..universe {
+                let info_universe =
+                    self.borrowck_context.constraints.universe_causes.push(universe_info.clone());
+                assert_eq!(u.as_u32() + 1, info_universe.as_u32());
+            }
+        }
+
+        Ok(output)
+    }
+
+    pub(super) fn instantiate_canonical_with_fresh_inference_vars<T>(
+        &mut self,
+        span: Span,
+        canonical: &Canonical<'tcx, T>,
+    ) -> T
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        let (instantiated, _) =
+            self.infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
+
+        for _ in 0..canonical.max_universe.as_u32() {
+            let info = UniverseInfo::other();
+            self.borrowck_context.constraints.universe_causes.push(info);
+        }
+
+        instantiated
+    }
+
+    pub(super) fn prove_trait_ref(
+        &mut self,
+        trait_ref: ty::TraitRef<'tcx>,
+        locations: Locations,
+        category: ConstraintCategory,
+    ) {
+        self.prove_predicates(
+            Some(ty::PredicateKind::Trait(ty::TraitPredicate {
+                trait_ref,
+                constness: hir::Constness::NotConst,
+            })),
+            locations,
+            category,
+        );
+    }
+
+    pub(super) fn normalize_and_prove_instantiated_predicates(
+        &mut self,
+        instantiated_predicates: ty::InstantiatedPredicates<'tcx>,
+        locations: Locations,
+    ) {
+        for predicate in instantiated_predicates.predicates {
+            let predicate = self.normalize(predicate, locations);
+            self.prove_predicate(predicate, locations, ConstraintCategory::Boring);
+        }
+    }
+
+    pub(super) fn prove_predicates(
+        &mut self,
+        predicates: impl IntoIterator<Item = impl ToPredicate<'tcx>>,
+        locations: Locations,
+        category: ConstraintCategory,
+    ) {
+        for predicate in predicates {
+            let predicate = predicate.to_predicate(self.tcx());
+            debug!("prove_predicates(predicate={:?}, locations={:?})", predicate, locations,);
+
+            self.prove_predicate(predicate, locations, category);
+        }
+    }
+
+    pub(super) fn prove_predicate(
+        &mut self,
+        predicate: ty::Predicate<'tcx>,
+        locations: Locations,
+        category: ConstraintCategory,
+    ) {
+        debug!("prove_predicate(predicate={:?}, location={:?})", predicate, locations,);
+
+        let param_env = self.param_env;
+        self.fully_perform_op(
+            locations,
+            category,
+            param_env.and(type_op::prove_predicate::ProvePredicate::new(predicate)),
+        )
+        .unwrap_or_else(|NoSolution| {
+            span_mirbug!(self, NoSolution, "could not prove {:?}", predicate);
+        })
+    }
+
+    pub(super) fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
+    where
+        T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
+    {
+        debug!("normalize(value={:?}, location={:?})", value, location);
+        let param_env = self.param_env;
+        self.fully_perform_op(
+            location.to_locations(),
+            ConstraintCategory::Boring,
+            param_env.and(type_op::normalize::Normalize::new(value)),
+        )
+        .unwrap_or_else(|NoSolution| {
+            span_mirbug!(self, NoSolution, "failed to normalize `{:?}`", value);
+            value
+        })
+    }
+}
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/free_region_relations.rs b/compiler/rustc_mir/src/borrow_check/type_check/free_region_relations.rs
index beee3181256..012d67255d1 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/free_region_relations.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/free_region_relations.rs
@@ -11,6 +11,7 @@ use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
 use rustc_span::DUMMY_SP;
 use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
 use std::rc::Rc;
+use type_op::TypeOpOutput;
 
 use crate::borrow_check::{
     nll::ToRegionVid,
@@ -255,7 +256,7 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
         let constraint_sets: Vec<_> = unnormalized_input_output_tys
             .flat_map(|ty| {
                 debug!("build: input_or_output={:?}", ty);
-                let (ty, constraints1) = self
+                let TypeOpOutput { output: ty, constraints: constraints1, .. } = self
                     .param_env
                     .and(type_op::normalize::Normalize::new(ty))
                     .fully_perform(self.infcx)
@@ -264,7 +265,11 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
                             .tcx
                             .sess
                             .delay_span_bug(DUMMY_SP, &format!("failed to normalize {:?}", ty));
-                        (self.infcx.tcx.ty_error(), None)
+                        TypeOpOutput {
+                            output: self.infcx.tcx.ty_error(),
+                            constraints: None,
+                            canonicalized_query: None,
+                        }
                     });
                 let constraints2 = self.add_implied_bounds(ty);
                 normalized_inputs_and_output.push(ty);
@@ -317,7 +322,7 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
     /// from this local.
     fn add_implied_bounds(&mut self, ty: Ty<'tcx>) -> Option<Rc<QueryRegionConstraints<'tcx>>> {
         debug!("add_implied_bounds(ty={:?})", ty);
-        let (bounds, constraints) = self
+        let TypeOpOutput { output: bounds, constraints, .. } = self
             .param_env
             .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
             .fully_perform(self.infcx)
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs b/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs
index 37e0643228a..f8989a7d9df 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs
@@ -44,7 +44,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     // Instantiate the canonicalized variables from
                     // user-provided signature (e.g., the `_` in the code
                     // above) with fresh variables.
-                    let (poly_sig, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(
+                    let poly_sig = self.instantiate_canonical_with_fresh_inference_vars(
                         body.span,
                         &user_provided_poly_sig,
                     );
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs b/compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs
index f04736e04a0..e411f1dc108 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs
@@ -5,7 +5,7 @@ use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location};
 use rustc_middle::ty::{Ty, TypeFoldable};
 use rustc_trait_selection::traits::query::dropck_outlives::DropckOutlivesResult;
 use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives;
-use rustc_trait_selection::traits::query::type_op::TypeOp;
+use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
 use std::rc::Rc;
 
 use crate::dataflow::impls::MaybeInitializedPlaces;
@@ -519,9 +519,9 @@ impl LivenessContext<'_, '_, '_, 'tcx> {
         debug!("compute_drop_data(dropped_ty={:?})", dropped_ty,);
 
         let param_env = typeck.param_env;
-        let (dropck_result, region_constraint_data) =
+        let TypeOpOutput { output, constraints, .. } =
             param_env.and(DropckOutlives::new(dropped_ty)).fully_perform(typeck.infcx).unwrap();
 
-        DropData { dropck_result, region_constraint_data }
+        DropData { dropck_result: output, region_constraint_data: constraints }
     }
 }
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
index 801318e01d7..d05e0135dfe 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
@@ -38,7 +38,7 @@ use rustc_trait_selection::opaque_types::{GenerateMemberConstraints, InferCtxtEx
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::type_op;
 use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
-use rustc_trait_selection::traits::query::{Fallible, NoSolution};
+use rustc_trait_selection::traits::query::Fallible;
 use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligations};
 
 use crate::dataflow::impls::MaybeInitializedPlaces;
@@ -51,6 +51,7 @@ use crate::transform::{
 use crate::borrow_check::{
     borrow_set::BorrowSet,
     constraints::{OutlivesConstraint, OutlivesConstraintSet},
+    diagnostics::UniverseInfo,
     facts::AllFacts,
     location::LocationTable,
     member_constraints::MemberConstraintSet,
@@ -89,6 +90,7 @@ macro_rules! span_mirbug_and_err {
     })
 }
 
+mod canonical;
 mod constraint_conversion;
 pub mod free_region_relations;
 mod input_output;
@@ -142,6 +144,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
         member_constraints: MemberConstraintSet::default(),
         closure_bounds_mapping: Default::default(),
         type_tests: Vec::default(),
+        universe_causes: IndexVec::from_elem_n(UniverseInfo::other(), 1),
     };
 
     let CreateResult {
@@ -156,6 +159,11 @@ pub(crate) fn type_check<'mir, 'tcx>(
         &mut constraints,
     );
 
+    for _ in ty::UniverseIndex::ROOT..infcx.universe() {
+        let info = UniverseInfo::other();
+        constraints.universe_causes.push(info);
+    }
+
     let mut borrowck_context = BorrowCheckContext {
         universal_regions,
         location_table,
@@ -376,8 +384,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
                                      ty,
                                      san_ty| {
                         if let Err(terr) = verifier.cx.eq_types(
-                            san_ty,
                             ty,
+                            san_ty,
                             location.to_locations(),
                             ConstraintCategory::Boring,
                         ) {
@@ -425,8 +433,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
                 let literal_ty = constant.literal.ty().builtin_deref(true).unwrap().ty;
 
                 if let Err(terr) = self.cx.eq_types(
-                    normalized_ty,
                     literal_ty,
+                    normalized_ty,
                     locations,
                     ConstraintCategory::Boring,
                 ) {
@@ -542,7 +550,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
                     return PlaceTy::from_ty(self.tcx().ty_error());
                 }
             }
-            place_ty = self.sanitize_projection(place_ty, elem, place, location)
+            place_ty = self.sanitize_projection(place_ty, elem, place, location);
         }
 
         if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
@@ -916,6 +924,8 @@ crate struct MirTypeckRegionConstraints<'tcx> {
     crate closure_bounds_mapping:
         FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>,
 
+    crate universe_causes: IndexVec<ty::UniverseIndex, UniverseInfo<'tcx>>,
+
     crate type_tests: Vec<TypeTest<'tcx>>,
 }
 
@@ -1043,8 +1053,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         );
         for user_annotation in self.user_type_annotations {
             let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
-            let (annotation, _) =
-                self.infcx.instantiate_canonical_with_fresh_inference_vars(span, user_ty);
+            let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty);
             match annotation {
                 UserType::Ty(mut ty) => {
                     ty = self.normalize(ty, Locations::All(span));
@@ -1097,31 +1106,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         }
     }
 
-    /// Given some operation `op` that manipulates types, proves
-    /// predicates, or otherwise uses the inference context, executes
-    /// `op` and then executes all the further obligations that `op`
-    /// returns. This will yield a set of outlives constraints amongst
-    /// regions which are extracted and stored as having occurred at
-    /// `locations`.
-    ///
-    /// **Any `rustc_infer::infer` operations that might generate region
-    /// constraints should occur within this method so that those
-    /// constraints can be properly localized!**
-    fn fully_perform_op<R>(
-        &mut self,
-        locations: Locations,
-        category: ConstraintCategory,
-        op: impl type_op::TypeOp<'tcx, Output = R>,
-    ) -> Fallible<R> {
-        let (r, opt_data) = op.fully_perform(self.infcx)?;
-
-        if let Some(data) = &opt_data {
-            self.push_region_constraints(locations, category, data);
-        }
-
-        Ok(r)
-    }
-
     fn push_region_constraints(
         &mut self,
         locations: Locations,
@@ -1161,7 +1145,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             b,
             locations,
             category,
-            Some(self.borrowck_context),
+            self.borrowck_context,
         )
     }
 
@@ -1173,17 +1157,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         locations: Locations,
         category: ConstraintCategory,
     ) -> Fallible<()> {
-        self.relate_types(sub, ty::Variance::Covariant, sup, locations, category)
+        // Use this order of parameters because the sup type is usually the
+        // "expected" type in diagnostics.
+        self.relate_types(sup, ty::Variance::Contravariant, sub, locations, category)
     }
 
     fn eq_types(
         &mut self,
-        a: Ty<'tcx>,
-        b: Ty<'tcx>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
         locations: Locations,
         category: ConstraintCategory,
     ) -> Fallible<()> {
-        self.relate_types(a, ty::Variance::Invariant, b, locations, category)
+        self.relate_types(expected, ty::Variance::Invariant, found, locations, category)
     }
 
     fn relate_type_and_user_type(
@@ -1222,7 +1208,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         );
 
         let ty = curr_projected_ty.ty;
-        self.relate_types(a, v, ty, locations, category)?;
+        self.relate_types(ty, v.xform(ty::Variance::Contravariant), a, locations, category)?;
 
         Ok(())
     }
@@ -2053,8 +2039,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         let ty_fn_ptr_from = tcx.mk_fn_ptr(fn_sig);
 
                         if let Err(terr) = self.eq_types(
-                            ty_fn_ptr_from,
                             ty,
+                            ty_fn_ptr_from,
                             location.to_locations(),
                             ConstraintCategory::Cast,
                         ) {
@@ -2077,8 +2063,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         let ty_fn_ptr_from = tcx.mk_fn_ptr(tcx.signature_unclosure(sig, *unsafety));
 
                         if let Err(terr) = self.eq_types(
-                            ty_fn_ptr_from,
                             ty,
+                            ty_fn_ptr_from,
                             location.to_locations(),
                             ConstraintCategory::Cast,
                         ) {
@@ -2106,8 +2092,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         let ty_fn_ptr_from = tcx.safe_to_unsafe_fn_ty(fn_sig);
 
                         if let Err(terr) = self.eq_types(
-                            ty_fn_ptr_from,
                             ty,
+                            ty_fn_ptr_from,
                             location.to_locations(),
                             ConstraintCategory::Cast,
                         ) {
@@ -2294,20 +2280,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                             kind: TypeVariableOriginKind::MiscVariable,
                             span: body.source_info(location).span,
                         });
-                        self.relate_types(
-                            common_ty,
-                            ty::Variance::Contravariant,
+                        self.sub_types(
                             ty_left,
+                            common_ty,
                             location.to_locations(),
                             ConstraintCategory::Boring,
                         )
                         .unwrap_or_else(|err| {
                             bug!("Could not equate type variable with {:?}: {:?}", ty_left, err)
                         });
-                        if let Err(terr) = self.relate_types(
-                            common_ty,
-                            ty::Variance::Contravariant,
+                        if let Err(terr) = self.sub_types(
                             ty_right,
+                            common_ty,
                             location.to_locations(),
                             ConstraintCategory::Boring,
                         ) {
@@ -2682,66 +2666,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         tcx.predicates_of(def_id).instantiate(tcx, substs)
     }
 
-    fn prove_trait_ref(
-        &mut self,
-        trait_ref: ty::TraitRef<'tcx>,
-        locations: Locations,
-        category: ConstraintCategory,
-    ) {
-        self.prove_predicates(
-            Some(ty::PredicateKind::Trait(ty::TraitPredicate {
-                trait_ref,
-                constness: hir::Constness::NotConst,
-            })),
-            locations,
-            category,
-        );
-    }
-
-    fn normalize_and_prove_instantiated_predicates(
-        &mut self,
-        instantiated_predicates: ty::InstantiatedPredicates<'tcx>,
-        locations: Locations,
-    ) {
-        for predicate in instantiated_predicates.predicates {
-            let predicate = self.normalize(predicate, locations);
-            self.prove_predicate(predicate, locations, ConstraintCategory::Boring);
-        }
-    }
-
-    fn prove_predicates(
-        &mut self,
-        predicates: impl IntoIterator<Item = impl ToPredicate<'tcx>>,
-        locations: Locations,
-        category: ConstraintCategory,
-    ) {
-        for predicate in predicates {
-            let predicate = predicate.to_predicate(self.tcx());
-            debug!("prove_predicates(predicate={:?}, locations={:?})", predicate, locations,);
-
-            self.prove_predicate(predicate, locations, category);
-        }
-    }
-
-    fn prove_predicate(
-        &mut self,
-        predicate: ty::Predicate<'tcx>,
-        locations: Locations,
-        category: ConstraintCategory,
-    ) {
-        debug!("prove_predicate(predicate={:?}, location={:?})", predicate, locations,);
-
-        let param_env = self.param_env;
-        self.fully_perform_op(
-            locations,
-            category,
-            param_env.and(type_op::prove_predicate::ProvePredicate::new(predicate)),
-        )
-        .unwrap_or_else(|NoSolution| {
-            span_mirbug!(self, NoSolution, "could not prove {:?}", predicate);
-        })
-    }
-
     fn typeck_mir(&mut self, body: &Body<'tcx>) {
         self.last_span = body.span;
         debug!("run_on_mir: {:?}", body.span);
@@ -2764,23 +2688,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             self.check_iscleanup(&body, block_data);
         }
     }
-
-    fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
-    where
-        T: type_op::normalize::Normalizable<'tcx> + Copy + 'tcx,
-    {
-        debug!("normalize(value={:?}, location={:?})", value, location);
-        let param_env = self.param_env;
-        self.fully_perform_op(
-            location.to_locations(),
-            ConstraintCategory::Boring,
-            param_env.and(type_op::normalize::Normalize::new(value)),
-        )
-        .unwrap_or_else(|NoSolution| {
-            span_mirbug!(self, NoSolution, "failed to normalize `{:?}`", value);
-            value
-        })
-    }
 }
 
 trait NormalizeLocation: fmt::Debug + Copy {
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs b/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs
index f97252a117a..971c4daa6b3 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs
@@ -6,6 +6,7 @@ use rustc_middle::ty::{self, Const, Ty};
 use rustc_trait_selection::traits::query::Fallible;
 
 use crate::borrow_check::constraints::OutlivesConstraint;
+use crate::borrow_check::diagnostics::UniverseInfo;
 use crate::borrow_check::type_check::{BorrowCheckContext, Locations};
 
 /// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`:
@@ -24,12 +25,19 @@ pub(super) fn relate_types<'tcx>(
     b: Ty<'tcx>,
     locations: Locations,
     category: ConstraintCategory,
-    borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>,
+    borrowck_context: &mut BorrowCheckContext<'_, 'tcx>,
 ) -> Fallible<()> {
     debug!("relate_types(a={:?}, v={:?}, b={:?}, locations={:?})", a, v, b, locations);
     TypeRelating::new(
         infcx,
-        NllTypeRelatingDelegate::new(infcx, borrowck_context, param_env, locations, category),
+        NllTypeRelatingDelegate::new(
+            infcx,
+            borrowck_context,
+            param_env,
+            locations,
+            category,
+            UniverseInfo::relate(a, b),
+        ),
         v,
     )
     .relate(a, b)?;
@@ -38,7 +46,7 @@ pub(super) fn relate_types<'tcx>(
 
 struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
     infcx: &'me InferCtxt<'me, 'tcx>,
-    borrowck_context: Option<&'me mut BorrowCheckContext<'bccx, 'tcx>>,
+    borrowck_context: &'me mut BorrowCheckContext<'bccx, 'tcx>,
 
     param_env: ty::ParamEnv<'tcx>,
 
@@ -47,17 +55,22 @@ struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
 
     /// What category do we assign the resulting `'a: 'b` relationships?
     category: ConstraintCategory,
+
+    /// Information so that error reporting knows what types we are relating
+    /// when reporting a bound region error.
+    universe_info: UniverseInfo<'tcx>,
 }
 
 impl NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
     fn new(
         infcx: &'me InferCtxt<'me, 'tcx>,
-        borrowck_context: Option<&'me mut BorrowCheckContext<'bccx, 'tcx>>,
+        borrowck_context: &'me mut BorrowCheckContext<'bccx, 'tcx>,
         param_env: ty::ParamEnv<'tcx>,
         locations: Locations,
         category: ConstraintCategory,
+        universe_info: UniverseInfo<'tcx>,
     ) -> Self {
-        Self { infcx, borrowck_context, param_env, locations, category }
+        Self { infcx, borrowck_context, param_env, locations, category, universe_info }
     }
 }
 
@@ -67,24 +80,20 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
     }
 
     fn create_next_universe(&mut self) -> ty::UniverseIndex {
-        self.infcx.create_next_universe()
+        let info_universe =
+            self.borrowck_context.constraints.universe_causes.push(self.universe_info.clone());
+        let universe = self.infcx.create_next_universe();
+        assert_eq!(info_universe, universe);
+        universe
     }
 
     fn next_existential_region_var(&mut self, from_forall: bool) -> ty::Region<'tcx> {
-        if self.borrowck_context.is_some() {
-            let origin = NllRegionVariableOrigin::Existential { from_forall };
-            self.infcx.next_nll_region_var(origin)
-        } else {
-            self.infcx.tcx.lifetimes.re_erased
-        }
+        let origin = NllRegionVariableOrigin::Existential { from_forall };
+        self.infcx.next_nll_region_var(origin)
     }
 
     fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> {
-        if let Some(borrowck_context) = &mut self.borrowck_context {
-            borrowck_context.constraints.placeholder_region(self.infcx, placeholder)
-        } else {
-            self.infcx.tcx.lifetimes.re_erased
-        }
+        self.borrowck_context.constraints.placeholder_region(self.infcx, placeholder)
     }
 
     fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
@@ -100,17 +109,15 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
         sub: ty::Region<'tcx>,
         info: ty::VarianceDiagInfo<'tcx>,
     ) {
-        if let Some(borrowck_context) = &mut self.borrowck_context {
-            let sub = borrowck_context.universal_regions.to_region_vid(sub);
-            let sup = borrowck_context.universal_regions.to_region_vid(sup);
-            borrowck_context.constraints.outlives_constraints.push(OutlivesConstraint {
-                sup,
-                sub,
-                locations: self.locations,
-                category: self.category,
-                variance_info: info,
-            });
-        }
+        let sub = self.borrowck_context.universal_regions.to_region_vid(sub);
+        let sup = self.borrowck_context.universal_regions.to_region_vid(sup);
+        self.borrowck_context.constraints.outlives_constraints.push(OutlivesConstraint {
+            sup,
+            sub,
+            locations: self.locations,
+            category: self.category,
+            variance_info: info,
+        });
     }
 
     // We don't have to worry about the equality of consts during borrow checking
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
index 4f5476ca5d0..b5398f8a435 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
@@ -1,13 +1,13 @@
-use crate::infer::{InferCtxt, InferOk};
-use crate::traits::query::Fallible;
-use std::fmt;
-
 use crate::infer::canonical::query_response;
-use crate::infer::canonical::QueryRegionConstraints;
+use crate::infer::{InferCtxt, InferOk};
 use crate::traits::engine::TraitEngineExt as _;
+use crate::traits::query::type_op::TypeOpOutput;
+use crate::traits::query::Fallible;
 use crate::traits::{ObligationCause, TraitEngine};
 use rustc_infer::traits::TraitEngineExt as _;
 use rustc_span::source_map::DUMMY_SP;
+
+use std::fmt;
 use std::rc::Rc;
 
 pub struct CustomTypeOp<F, G> {
@@ -35,10 +35,7 @@ where
     /// Processes the operation and all resulting obligations,
     /// returning the final result along with any region constraints
     /// (they will be given over to the NLL region solver).
-    fn fully_perform(
-        self,
-        infcx: &InferCtxt<'_, 'tcx>,
-    ) -> Fallible<(Self::Output, Option<Rc<QueryRegionConstraints<'tcx>>>)> {
+    fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
         if cfg!(debug_assertions) {
             info!("fully_perform({:?})", self);
         }
@@ -58,10 +55,10 @@ where
 
 /// Executes `op` and then scrapes out all the "old style" region
 /// constraints that result, creating query-region-constraints.
-fn scrape_region_constraints<'tcx, R>(
+fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
     infcx: &InferCtxt<'_, 'tcx>,
     op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>,
-) -> Fallible<(R, Option<Rc<QueryRegionConstraints<'tcx>>>)> {
+) -> Fallible<TypeOpOutput<'tcx, Op>> {
     let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
     let dummy_body_id = ObligationCause::dummy().body_id;
 
@@ -101,8 +98,12 @@ fn scrape_region_constraints<'tcx, R>(
     );
 
     if region_constraints.is_empty() {
-        Ok((value, None))
+        Ok(TypeOpOutput { output: value, constraints: None, canonicalized_query: None })
     } else {
-        Ok((value, Some(Rc::new(region_constraints))))
+        Ok(TypeOpOutput {
+            output: value,
+            constraints: Some(Rc::new(region_constraints)),
+            canonicalized_query: None,
+        })
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
index b351af44e94..3863dd61cef 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
@@ -3,7 +3,7 @@ use crate::traits::query::outlives_bounds::OutlivesBound;
 use crate::traits::query::Fallible;
 use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt};
 
-#[derive(Clone, Debug, HashStable, TypeFoldable, Lift)]
+#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, Lift)]
 pub struct ImpliedOutlivesBounds<'tcx> {
     pub ty: Ty<'tcx>,
 }
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
index fbff86618ad..12ca3faeb37 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
@@ -4,6 +4,7 @@ use crate::infer::canonical::{
 use crate::infer::{InferCtxt, InferOk};
 use crate::traits::query::Fallible;
 use crate::traits::ObligationCause;
+use rustc_infer::infer::canonical::Canonical;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
 use std::fmt;
@@ -30,10 +31,18 @@ pub trait TypeOp<'tcx>: Sized + fmt::Debug {
     /// Processes the operation and all resulting obligations,
     /// returning the final result along with any region constraints
     /// (they will be given over to the NLL region solver).
-    fn fully_perform(
-        self,
-        infcx: &InferCtxt<'_, 'tcx>,
-    ) -> Fallible<(Self::Output, Option<Rc<QueryRegionConstraints<'tcx>>>)>;
+    fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>>;
+}
+
+/// The output from performing a type op
+pub struct TypeOpOutput<'tcx, Op: TypeOp<'tcx>> {
+    /// The output from the type op.
+    pub output: Op::Output,
+    /// Any region constraints from performing the type op.
+    pub constraints: Option<Rc<QueryRegionConstraints<'tcx>>>,
+    /// The canonicalized form of the query.
+    /// This for error reporting to be able to rerun the query.
+    pub canonicalized_query: Option<Canonical<'tcx, Op>>,
 }
 
 /// "Query type ops" are type ops that are implemented using a
@@ -45,7 +54,7 @@ pub trait TypeOp<'tcx>: Sized + fmt::Debug {
 /// which produces the resulting query region constraints.
 ///
 /// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
-pub trait QueryTypeOp<'tcx>: fmt::Debug + Sized + TypeFoldable<'tcx> + 'tcx {
+pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<'tcx> + 'tcx {
     type QueryResponse: TypeFoldable<'tcx>;
 
     /// Give query the option for a simple fast path that never
@@ -71,9 +80,9 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Sized + TypeFoldable<'tcx> + 'tcx {
         query_key: ParamEnvAnd<'tcx, Self>,
         infcx: &InferCtxt<'_, 'tcx>,
         output_query_region_constraints: &mut QueryRegionConstraints<'tcx>,
-    ) -> Fallible<Self::QueryResponse> {
+    ) -> Fallible<(Self::QueryResponse, Option<Canonical<'tcx, ParamEnvAnd<'tcx, Self>>>)> {
         if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) {
-            return Ok(result);
+            return Ok((result, None));
         }
 
         // FIXME(#33684) -- We need to use
@@ -101,14 +110,14 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Sized + TypeFoldable<'tcx> + 'tcx {
         // create obligations. In that case, we have to go
         // fulfill them. We do this via a (recursive) query.
         for obligation in obligations {
-            let () = ProvePredicate::fully_perform_into(
+            let ((), _) = ProvePredicate::fully_perform_into(
                 obligation.param_env.and(ProvePredicate::new(obligation.predicate)),
                 infcx,
                 output_query_region_constraints,
             )?;
         }
 
-        Ok(value)
+        Ok((value, Some(canonical_self)))
     }
 }
 
@@ -118,18 +127,16 @@ where
 {
     type Output = Q::QueryResponse;
 
-    fn fully_perform(
-        self,
-        infcx: &InferCtxt<'_, 'tcx>,
-    ) -> Fallible<(Self::Output, Option<Rc<QueryRegionConstraints<'tcx>>>)> {
+    fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
         let mut region_constraints = QueryRegionConstraints::default();
-        let r = Q::fully_perform_into(self, infcx, &mut region_constraints)?;
+        let (output, canonicalized_query) =
+            Q::fully_perform_into(self, infcx, &mut region_constraints)?;
 
         // Promote the final query-region-constraints into a
         // (optional) ref-counted vector:
-        let opt_qrc =
+        let region_constraints =
             if region_constraints.is_empty() { None } else { Some(Rc::new(region_constraints)) };
 
-        Ok((r, opt_qrc))
+        Ok(TypeOpOutput { output, constraints: region_constraints, canonicalized_query })
     }
 }
diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs
index d0b05beb4e6..8dd7c5bdfae 100644
--- a/compiler/rustc_traits/src/lib.rs
+++ b/compiler/rustc_traits/src/lib.rs
@@ -19,6 +19,8 @@ mod normalize_erasing_regions;
 mod normalize_projection_ty;
 mod type_op;
 
+pub use type_op::type_op_prove_predicate_with_span;
+
 use rustc_middle::ty::query::Providers;
 
 pub fn provide(p: &mut Providers) {
diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs
index bd0acb0e53b..c2e0a998785 100644
--- a/compiler/rustc_traits/src/type_op.rs
+++ b/compiler/rustc_traits/src/type_op.rs
@@ -8,7 +8,7 @@ use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::{GenericArg, Subst, UserSelfTy, UserSubsts};
 use rustc_middle::ty::{self, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable, Variance};
 use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Predicate, ToPredicate};
-use rustc_span::DUMMY_SP;
+use rustc_span::{Span, DUMMY_SP};
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::query::normalize::AtExt;
@@ -236,11 +236,25 @@ fn type_op_prove_predicate<'tcx>(
     canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, ProvePredicate<'tcx>>>,
 ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> {
     tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| {
-        let (param_env, ProvePredicate { predicate }) = key.into_parts();
-        fulfill_cx.register_predicate_obligation(
-            infcx,
-            Obligation::new(ObligationCause::dummy(), param_env, predicate),
-        );
+        type_op_prove_predicate_with_span(infcx, fulfill_cx, key, None);
         Ok(())
     })
 }
+
+/// The core of the `type_op_prove_predicate` query: for diagnostics purposes in NLL HRTB errors,
+/// this query can be re-run to better track the span of the obligation cause, and improve the error
+/// message. Do not call directly unless you're in that very specific context.
+pub fn type_op_prove_predicate_with_span<'a, 'tcx: 'a>(
+    infcx: &'a InferCtxt<'a, 'tcx>,
+    fulfill_cx: &'a mut dyn TraitEngine<'tcx>,
+    key: ParamEnvAnd<'tcx, ProvePredicate<'tcx>>,
+    span: Option<Span>,
+) {
+    let cause = if let Some(span) = span {
+        ObligationCause::dummy_with_span(span)
+    } else {
+        ObligationCause::dummy()
+    };
+    let (param_env, ProvePredicate { predicate }) = key.into_parts();
+    fulfill_cx.register_predicate_obligation(infcx, Obligation::new(cause, param_env, predicate));
+}