about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthew Jasper <mjjasper1@gmail.com>2021-06-07 20:25:19 +0100
committerRémy Rakic <remy.rakic+github@gmail.com>2021-08-15 09:11:01 +0200
commitd563a63788b143c84c9b40b68e940f436dd58e79 (patch)
treea9128644268240f064ca75293aec64ba24e298c9
parent0c388b0261d7ac33089e5b10ab215653154a5293 (diff)
downloadrust-d563a63788b143c84c9b40b68e940f436dd58e79.tar.gz
rust-d563a63788b143c84c9b40b68e940f436dd58e79.zip
Report nicer errors for HRTB NLL errors from queries
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs13
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/mod.rs5
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/bound_region_errors.rs252
-rw-r--r--src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr8
-rw-r--r--src/test/ui/generator/auto-trait-regions.nll.stderr14
-rw-r--r--src/test/ui/generator/resume-arg-late-bound.nll.stderr8
-rw-r--r--src/test/ui/higher-rank-trait-bounds/issue-59311.rs2
-rw-r--r--src/test/ui/higher-rank-trait-bounds/issue-59311.stderr4
-rw-r--r--src/test/ui/hrtb/hrtb-conflate-regions.nll.stderr14
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.nll.stderr7
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.nll.stderr7
-rw-r--r--src/test/ui/hrtb/hrtb-just-for-static.nll.stderr7
-rw-r--r--src/test/ui/hrtb/hrtb-perfect-forwarding.nll.stderr7
-rw-r--r--src/test/ui/hrtb/issue-46989.nll.stderr7
-rw-r--r--src/test/ui/issues/issue-40000.nll.stderr15
-rw-r--r--src/test/ui/issues/issue-54302-cases.nll.stderr28
-rw-r--r--src/test/ui/issues/issue-55731.nll.stderr7
-rw-r--r--src/test/ui/issues/issue-57843.nll.stderr7
-rw-r--r--src/test/ui/lifetimes/issue-79187-2.nll.stderr34
-rw-r--r--src/test/ui/lifetimes/issue-79187.nll.stderr20
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-object.nll.stderr15
-rw-r--r--src/test/ui/mismatched_types/closure-mismatch.nll.stderr20
-rw-r--r--src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs4
-rw-r--r--src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr14
-rw-r--r--src/test/ui/nll/relate_tys/trait-hrtb.rs2
-rw-r--r--src/test/ui/nll/relate_tys/trait-hrtb.stderr8
-rw-r--r--src/test/ui/rfc1623.nll.stderr31
-rw-r--r--src/test/ui/unboxed-closures/issue-30906.nll.stderr7
-rw-r--r--src/test/ui/where-clauses/where-for-self-2.nll.stderr7
29 files changed, 473 insertions, 101 deletions
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 8c7a792eaa2..9b9ded5c6ba 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -1111,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)
     }
 
@@ -1289,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
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/src/borrow_check/diagnostics/bound_region_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/bound_region_errors.rs
index 5db20acf941..8400bcf12d7 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/bound_region_errors.rs
@@ -1,9 +1,14 @@
+use rustc_errors::DiagnosticBuilder;
 use rustc_infer::infer::canonical::Canonical;
-use rustc_infer::traits::ObligationCause;
+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, Obligation, ObligationCause, TraitEngine, TraitEngineExt};
 use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::{self, Ty, TypeFoldable};
+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 std::fmt;
 use std::rc::Rc;
@@ -37,11 +42,10 @@ impl UniverseInfo<'tcx> {
     crate fn report_error(
         &self,
         mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
-        _placeholder: ty::PlaceholderRegion,
-        _error_element: RegionElement,
+        placeholder: ty::PlaceholderRegion,
+        error_element: RegionElement,
         span: Span,
     ) {
-        // FIXME: improve this error message
         match self.0 {
             UniverseInfoInner::RelateTys { expected, found } => {
                 let body_id = mbcx.infcx.tcx.hir().local_def_id_to_hir_id(mbcx.mir_def_id());
@@ -53,7 +57,13 @@ impl UniverseInfo<'tcx> {
                 );
                 err.buffer(&mut mbcx.errors_buffer);
             }
-            UniverseInfoInner::TypeOp(_) | UniverseInfoInner::Other => {
+            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
@@ -73,8 +83,8 @@ impl<'tcx> ToUniverseInfo<'tcx>
 {
     fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
         UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(PredicateQuery {
-            _canonical_query: self,
-            _base_universe: base_universe,
+            canonical_query: self,
+            base_universe,
         })))
     }
 }
@@ -84,8 +94,8 @@ impl<'tcx, T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx> ToUniverseInfo<'t
 {
     fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
         UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(NormalizeQuery {
-            _canonical_query: self,
-            _base_universe: base_universe,
+            canonical_query: self,
+            base_universe,
         })))
     }
 }
@@ -109,23 +119,229 @@ impl<'tcx, F, G> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::Custo
 
 #[allow(unused_lifetimes)]
 trait TypeOpInfo<'tcx> {
-    // TODO: Methods for rerunning type op and reporting an error
+    /// Returns an rrror 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_query:
         Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>,
-    _base_universe: ty::UniverseIndex,
+    base_universe: ty::UniverseIndex,
 }
 
-impl TypeOpInfo<'tcx> for PredicateQuery<'tcx> {}
+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 = TraitEngine::new(tcx);
+
+            let (param_env, prove_predicate) = key.into_parts();
+            fulfill_cx.register_predicate_obligation(
+                infcx,
+                Obligation::new(
+                    ObligationCause::dummy_with_span(span),
+                    param_env,
+                    prove_predicate.predicate,
+                ),
+            );
+
+            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,
+    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
+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 = TraitEngine::new(tcx);
+
+            let mut selcx = SelectionContext::new(infcx);
+            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 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 region_obligations = infcx.take_registered_region_obligations();
+    debug!(?region_obligations);
+
+    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/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr b/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr
index 2e03986a9ed..59e27cd2e7d 100644
--- a/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr
+++ b/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr
@@ -1,8 +1,12 @@
-error: higher-ranked subtype error
+error[E0308]: mismatched types
   --> $DIR/higher-ranked-projection.rs:25:5
    |
 LL |     foo(());
-   |     ^^^^^^^
+   |     ^^^^^^^ one type is more general than the other
+   |
+   = note:   expected type `&'a ()`
+           found reference `&()`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/generator/auto-trait-regions.nll.stderr b/src/test/ui/generator/auto-trait-regions.nll.stderr
index 794369a8dc0..76970fb7872 100644
--- a/src/test/ui/generator/auto-trait-regions.nll.stderr
+++ b/src/test/ui/generator/auto-trait-regions.nll.stderr
@@ -24,17 +24,23 @@ LL |         assert_foo(a);
    |
    = note: consider using a `let` binding to create a longer lived value
 
-error: higher-ranked subtype error
+error: implementation of `Foo` is not general enough
   --> $DIR/auto-trait-regions.rs:31:5
    |
 LL |     assert_foo(gen);
-   |     ^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+   |
+   = note: `&'0 OnlyFooIfStaticRef` must implement `Foo`, for any lifetime `'0`...
+   = note: ...but `Foo` is actually implemented for the type `&'static OnlyFooIfStaticRef`
 
-error: higher-ranked subtype error
+error: implementation of `Foo` is not general enough
   --> $DIR/auto-trait-regions.rs:50:5
    |
 LL |     assert_foo(gen);
-   |     ^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+   |
+   = note: `Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Foo` is actually implemented for the type `A<'_, '2>`, for some specific lifetime `'2`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/generator/resume-arg-late-bound.nll.stderr b/src/test/ui/generator/resume-arg-late-bound.nll.stderr
index 7d712191924..25bc6afc550 100644
--- a/src/test/ui/generator/resume-arg-late-bound.nll.stderr
+++ b/src/test/ui/generator/resume-arg-late-bound.nll.stderr
@@ -1,8 +1,12 @@
-error: higher-ranked subtype error
+error[E0308]: mismatched types
   --> $DIR/resume-arg-late-bound.rs:15:5
    |
 LL |     test(gen);
-   |     ^^^^^^^^^
+   |     ^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected type `for<'a> Generator<&'a mut bool>`
+              found type `Generator<&mut bool>`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/higher-rank-trait-bounds/issue-59311.rs b/src/test/ui/higher-rank-trait-bounds/issue-59311.rs
index 1e1241c7f83..d617571753c 100644
--- a/src/test/ui/higher-rank-trait-bounds/issue-59311.rs
+++ b/src/test/ui/higher-rank-trait-bounds/issue-59311.rs
@@ -14,7 +14,7 @@ pub fn crash<V>(v: &V)
 where
     for<'a> &'a V: T + 'static,
 {
-    v.t(|| {}); //~ ERROR: higher-ranked subtype error
+    v.t(|| {}); //~ ERROR: higher-ranked lifetime error
 }
 
 fn main() {}
diff --git a/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr b/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr
index ca632629267..c16c8206153 100644
--- a/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr
+++ b/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr
@@ -1,8 +1,10 @@
-error: higher-ranked subtype error
+error: higher-ranked lifetime error
   --> $DIR/issue-59311.rs:17:9
    |
 LL |     v.t(|| {});
    |         ^^^^^
+   |
+   = note: could not prove for<'a> &'a V: 'static
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/hrtb/hrtb-conflate-regions.nll.stderr b/src/test/ui/hrtb/hrtb-conflate-regions.nll.stderr
index f290a93326f..46f5308dd87 100644
--- a/src/test/ui/hrtb/hrtb-conflate-regions.nll.stderr
+++ b/src/test/ui/hrtb/hrtb-conflate-regions.nll.stderr
@@ -1,14 +1,20 @@
-error: higher-ranked subtype error
+error: implementation of `Foo` is not general enough
   --> $DIR/hrtb-conflate-regions.rs:27:10
    |
 LL | fn b() { want_foo2::<SomeStruct>(); }
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+   |
+   = note: `SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but it actually implements `Foo<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
 
-error: higher-ranked subtype error
+error: implementation of `Foo` is not general enough
   --> $DIR/hrtb-conflate-regions.rs:27:10
    |
 LL | fn b() { want_foo2::<SomeStruct>(); }
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+   |
+   = note: `SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but it actually implements `Foo<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.nll.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.nll.stderr
index a4c3ffd1f6c..364b613fc77 100644
--- a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.nll.stderr
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.nll.stderr
@@ -1,8 +1,11 @@
-error: higher-ranked subtype error
+error: implementation of `Trait` is not general enough
   --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:5
    |
 LL |     foo::<()>();
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^^^^ implementation of `Trait` is not general enough
+   |
+   = note: `()` must implement `Trait<for<'b> fn(&'b u32)>`
+   = note: ...but it actually implements `Trait<fn(&'0 u32)>`, for some specific lifetime `'0`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.nll.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.nll.stderr
index e2a399b2faa..cb2ce8a4116 100644
--- a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.nll.stderr
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.nll.stderr
@@ -1,8 +1,11 @@
-error: higher-ranked subtype error
+error: implementation of `Trait` is not general enough
   --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5
    |
 LL |     foo::<()>();
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^^^^ implementation of `Trait` is not general enough
+   |
+   = note: `()` must implement `Trait<for<'b> fn(Cell<&'b u32>)>`
+   = note: ...but it actually implements `Trait<fn(Cell<&'0 u32>)>`, for some specific lifetime `'0`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/hrtb/hrtb-just-for-static.nll.stderr b/src/test/ui/hrtb/hrtb-just-for-static.nll.stderr
index 8901a1b4681..a812282def9 100644
--- a/src/test/ui/hrtb/hrtb-just-for-static.nll.stderr
+++ b/src/test/ui/hrtb/hrtb-just-for-static.nll.stderr
@@ -1,8 +1,11 @@
-error: higher-ranked subtype error
+error: implementation of `Foo` is not general enough
   --> $DIR/hrtb-just-for-static.rs:24:5
    |
 LL |     want_hrtb::<StaticInt>()
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+   |
+   = note: `StaticInt` must implement `Foo<&'0 isize>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Foo<&'static isize>`
 
 error: lifetime may not live long enough
   --> $DIR/hrtb-just-for-static.rs:30:5
diff --git a/src/test/ui/hrtb/hrtb-perfect-forwarding.nll.stderr b/src/test/ui/hrtb/hrtb-perfect-forwarding.nll.stderr
index c3dd7949575..aefe3cdfd64 100644
--- a/src/test/ui/hrtb/hrtb-perfect-forwarding.nll.stderr
+++ b/src/test/ui/hrtb/hrtb-perfect-forwarding.nll.stderr
@@ -57,11 +57,14 @@ LL |     foo_hrtb_bar_not(&mut t);
    |
    = help: consider replacing `'b` with `'static`
 
-error: higher-ranked subtype error
+error: implementation of `Bar` is not general enough
   --> $DIR/hrtb-perfect-forwarding.rs:43:5
    |
 LL |     foo_hrtb_bar_not(&mut t);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough
+   |
+   = note: `T` must implement `Bar<&'0 isize>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Bar<&'1 isize>`, for some specific lifetime `'1`
 
 warning: function cannot return without recursing
   --> $DIR/hrtb-perfect-forwarding.rs:48:1
diff --git a/src/test/ui/hrtb/issue-46989.nll.stderr b/src/test/ui/hrtb/issue-46989.nll.stderr
index 6c127b92d97..309e1a676ed 100644
--- a/src/test/ui/hrtb/issue-46989.nll.stderr
+++ b/src/test/ui/hrtb/issue-46989.nll.stderr
@@ -1,8 +1,11 @@
-error: higher-ranked subtype error
+error: implementation of `Foo` is not general enough
   --> $DIR/issue-46989.rs:38:5
    |
 LL |     assert_foo::<fn(&i32)>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+   |
+   = note: `Foo` would have to be implemented for the type `for<'r> fn(&'r i32)`
+   = note: ...but `Foo` is actually implemented for the type `fn(&'0 i32)`, for some specific lifetime `'0`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-40000.nll.stderr b/src/test/ui/issues/issue-40000.nll.stderr
index 4e2bde06a52..e6f0b5fbfba 100644
--- a/src/test/ui/issues/issue-40000.nll.stderr
+++ b/src/test/ui/issues/issue-40000.nll.stderr
@@ -1,14 +1,21 @@
-error: higher-ranked subtype error
+error[E0308]: mismatched types
   --> $DIR/issue-40000.rs:6:9
    |
 LL |     foo(bar);
-   |         ^^^
+   |         ^^^ one type is more general than the other
+   |
+   = note: expected trait object `dyn for<'r> Fn(&'r i32)`
+              found trait object `dyn Fn(&i32)`
 
-error: higher-ranked subtype error
+error[E0308]: mismatched types
   --> $DIR/issue-40000.rs:6:9
    |
 LL |     foo(bar);
-   |         ^^^
+   |         ^^^ one type is more general than the other
+   |
+   = note: expected trait object `dyn for<'r> Fn(&'r i32)`
+              found trait object `dyn Fn(&i32)`
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/issues/issue-54302-cases.nll.stderr b/src/test/ui/issues/issue-54302-cases.nll.stderr
index 7463a3f286f..6e8b69c4bee 100644
--- a/src/test/ui/issues/issue-54302-cases.nll.stderr
+++ b/src/test/ui/issues/issue-54302-cases.nll.stderr
@@ -1,26 +1,38 @@
-error: higher-ranked subtype error
+error: implementation of `Foo` is not general enough
   --> $DIR/issue-54302-cases.rs:63:5
    |
 LL |     <u32 as RefFoo<u32>>::ref_foo(a)
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+   |
+   = note: `Foo<'static, u32>` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`...
+   = note: ...but `Foo<'_, u32>` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
 
-error: higher-ranked subtype error
+error: implementation of `Foo` is not general enough
   --> $DIR/issue-54302-cases.rs:69:5
    |
 LL |     <i32 as RefFoo<i32>>::ref_foo(a)
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+   |
+   = note: `Foo<'static, i32>` would have to be implemented for the type `&'0 i32`, for any lifetime `'0`...
+   = note: ...but `Foo<'_, i32>` is actually implemented for the type `&'1 i32`, for some specific lifetime `'1`
 
-error: higher-ranked subtype error
+error: implementation of `Foo` is not general enough
   --> $DIR/issue-54302-cases.rs:75:5
    |
 LL |     <u64 as RefFoo<u64>>::ref_foo(a)
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+   |
+   = note: `Foo<'static, u64>` would have to be implemented for the type `&'0 u64`, for any lifetime `'0`...
+   = note: ...but `Foo<'_, u64>` is actually implemented for the type `&'1 u64`, for some specific lifetime `'1`
 
-error: higher-ranked subtype error
+error: implementation of `Foo` is not general enough
   --> $DIR/issue-54302-cases.rs:81:5
    |
 LL |     <i64 as RefFoo<i64>>::ref_foo(a)
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+   |
+   = note: `Foo<'static, i64>` would have to be implemented for the type `&'0 i64`, for any lifetime `'0`...
+   = note: ...but `Foo<'_, i64>` is actually implemented for the type `&'1 i64`, for some specific lifetime `'1`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/issues/issue-55731.nll.stderr b/src/test/ui/issues/issue-55731.nll.stderr
index dd38bb62912..97fd6678c99 100644
--- a/src/test/ui/issues/issue-55731.nll.stderr
+++ b/src/test/ui/issues/issue-55731.nll.stderr
@@ -1,11 +1,14 @@
-error: higher-ranked subtype error
+error: implementation of `DistributedIteratorMulti` is not general enough
   --> $DIR/issue-55731.rs:48:5
    |
 LL | /     multi(Map {
 LL | |         i: Cloned(PhantomData),
 LL | |         f: X,
 LL | |     });
-   | |______^
+   | |______^ implementation of `DistributedIteratorMulti` is not general enough
+   |
+   = note: `DistributedIteratorMulti<&'0 ()>` would have to be implemented for the type `Cloned<&()>`, for any lifetime `'0`...
+   = note: ...but `DistributedIteratorMulti<&'1 ()>` is actually implemented for the type `Cloned<&'1 ()>`, for some specific lifetime `'1`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-57843.nll.stderr b/src/test/ui/issues/issue-57843.nll.stderr
index 70d16cc9a1d..2ab49ec61cf 100644
--- a/src/test/ui/issues/issue-57843.nll.stderr
+++ b/src/test/ui/issues/issue-57843.nll.stderr
@@ -1,8 +1,11 @@
-error: higher-ranked subtype error
+error: implementation of `FnOnce` is not general enough
   --> $DIR/issue-57843.rs:25:9
    |
 LL |     Foo(Box::new(|_| ()));
-   |         ^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
+   |
+   = note: closure with signature `fn(&'2 bool)` must implement `FnOnce<(&'1 bool,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 bool,)>`, for some specific lifetime `'2`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/lifetimes/issue-79187-2.nll.stderr b/src/test/ui/lifetimes/issue-79187-2.nll.stderr
index 4970c579e7b..907b43d6762 100644
--- a/src/test/ui/lifetimes/issue-79187-2.nll.stderr
+++ b/src/test/ui/lifetimes/issue-79187-2.nll.stderr
@@ -16,29 +16,47 @@ LL |     take_foo(|a: &i32| -> &i32 { a });
    |                  |        let's call the lifetime of this reference `'2`
    |                  let's call the lifetime of this reference `'1`
 
-error: higher-ranked subtype error
+error: implementation of `FnOnce` is not general enough
   --> $DIR/issue-79187-2.rs:8:5
    |
 LL |     take_foo(|a| a);
-   |     ^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
+   |
+   = note: closure with signature `fn(&'2 i32) -> &i32` must implement `FnOnce<(&'1 i32,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 i32,)>`, for some specific lifetime `'2`
 
-error: higher-ranked subtype error
+error[E0308]: mismatched types
   --> $DIR/issue-79187-2.rs:8:5
    |
 LL |     take_foo(|a| a);
-   |     ^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected type `for<'r> Fn<(&'r i32,)>`
+              found type `Fn<(&i32,)>`
+note: this closure does not fulfill the lifetime requirements
+  --> $DIR/issue-79187-2.rs:8:14
+   |
+LL |     take_foo(|a| a);
+   |              ^^^^^
 
-error: higher-ranked subtype error
+error[E0308]: mismatched types
   --> $DIR/issue-79187-2.rs:9:5
    |
 LL |     take_foo(|a: &i32| a);
-   |     ^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected reference `&i32`
+              found reference `&i32`
 
-error: higher-ranked subtype error
+error[E0308]: mismatched types
   --> $DIR/issue-79187-2.rs:10:5
    |
 LL |     take_foo(|a: &i32| -> &i32 { a });
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected reference `&i32`
+              found reference `&i32`
 
 error: aborting due to 6 previous errors
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/lifetimes/issue-79187.nll.stderr b/src/test/ui/lifetimes/issue-79187.nll.stderr
index aa8809dbc95..725b132e83a 100644
--- a/src/test/ui/lifetimes/issue-79187.nll.stderr
+++ b/src/test/ui/lifetimes/issue-79187.nll.stderr
@@ -1,14 +1,26 @@
-error: higher-ranked subtype error
+error[E0308]: mismatched types
   --> $DIR/issue-79187.rs:5:5
    |
 LL |     thing(f);
-   |     ^^^^^^^^
+   |     ^^^^^^^^ one type is more general than the other
+   |
+   = note: expected type `for<'r> FnOnce<(&'r u32,)>`
+              found type `FnOnce<(&u32,)>`
+note: this closure does not fulfill the lifetime requirements
+  --> $DIR/issue-79187.rs:4:13
+   |
+LL |     let f = |_| ();
+   |             ^^^^^^
 
-error: higher-ranked subtype error
+error: implementation of `FnOnce` is not general enough
   --> $DIR/issue-79187.rs:5:5
    |
 LL |     thing(f);
-   |     ^^^^^^^^
+   |     ^^^^^^^^ implementation of `FnOnce` is not general enough
+   |
+   = note: closure with signature `fn(&'2 u32)` must implement `FnOnce<(&'1 u32,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 u32,)>`, for some specific lifetime `'2`
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr b/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr
index 51bf96f3233..ad14d6b7521 100644
--- a/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr
+++ b/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr
@@ -1,14 +1,21 @@
-error: higher-ranked subtype error
+error[E0308]: mismatched types
   --> $DIR/old-lub-glb-object.rs:10:14
    |
 LL |         _ => y,
-   |              ^
+   |              ^ one type is more general than the other
+   |
+   = note: expected trait object `dyn for<'r, 's> Foo<&'r u8, &'s u8>`
+              found trait object `dyn for<'r> Foo<&'r u8, &'r u8>`
 
-error: higher-ranked subtype error
+error[E0308]: mismatched types
   --> $DIR/old-lub-glb-object.rs:10:14
    |
 LL |         _ => y,
-   |              ^
+   |              ^ one type is more general than the other
+   |
+   = note: expected trait object `dyn for<'r, 's> Foo<&'r u8, &'s u8>`
+              found trait object `dyn for<'r> Foo<&'r u8, &'r u8>`
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/mismatched_types/closure-mismatch.nll.stderr b/src/test/ui/mismatched_types/closure-mismatch.nll.stderr
index 745a61b866e..f29126e6afc 100644
--- a/src/test/ui/mismatched_types/closure-mismatch.nll.stderr
+++ b/src/test/ui/mismatched_types/closure-mismatch.nll.stderr
@@ -1,14 +1,26 @@
-error: higher-ranked subtype error
+error: implementation of `FnOnce` is not general enough
   --> $DIR/closure-mismatch.rs:8:5
    |
 LL |     baz(|_| ());
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^^^^ implementation of `FnOnce` is not general enough
+   |
+   = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2`
 
-error: higher-ranked subtype error
+error[E0308]: mismatched types
   --> $DIR/closure-mismatch.rs:8:5
    |
 LL |     baz(|_| ());
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected type `for<'r> Fn<(&'r (),)>`
+              found type `Fn<(&(),)>`
+note: this closure does not fulfill the lifetime requirements
+  --> $DIR/closure-mismatch.rs:8:9
+   |
+LL |     baz(|_| ());
+   |         ^^^^^^
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs b/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs
index 44dcd191d1b..37a01f28946 100644
--- a/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs
+++ b/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs
@@ -30,6 +30,6 @@ impl<T> Y for fn(T) {
 
 fn main() {
     let _x = <fn(&())>::make_f();
-    //~^ higher-ranked subtype error
-    //~| higher-ranked subtype error
+    //~^ ERROR implementation of `Y` is not general enough
+    //~| ERROR implementation of `Y` is not general enough
 }
diff --git a/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr b/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr
index 190b520c678..ed79c7df25e 100644
--- a/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr
+++ b/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr
@@ -1,14 +1,20 @@
-error: higher-ranked subtype error
+error: implementation of `Y` is not general enough
   --> $DIR/impl-fn-ignore-binder-via-bottom.rs:32:14
    |
 LL |     let _x = <fn(&())>::make_f();
-   |              ^^^^^^^^^^^^^^^^^^^
+   |              ^^^^^^^^^^^^^^^^^^^ implementation of `Y` is not general enough
+   |
+   = note: `Y` would have to be implemented for the type `for<'r> fn(&'r ())`
+   = note: ...but `Y` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0`
 
-error: higher-ranked subtype error
+error: implementation of `Y` is not general enough
   --> $DIR/impl-fn-ignore-binder-via-bottom.rs:32:14
    |
 LL |     let _x = <fn(&())>::make_f();
-   |              ^^^^^^^^^^^^^^^^^^^
+   |              ^^^^^^^^^^^^^^^^^^^ implementation of `Y` is not general enough
+   |
+   = note: `Y` would have to be implemented for the type `for<'r> fn(&'r ())`
+   = note: ...but `Y` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/nll/relate_tys/trait-hrtb.rs b/src/test/ui/nll/relate_tys/trait-hrtb.rs
index 80f31ca6b47..2e94fc5c12d 100644
--- a/src/test/ui/nll/relate_tys/trait-hrtb.rs
+++ b/src/test/ui/nll/relate_tys/trait-hrtb.rs
@@ -12,5 +12,5 @@ fn make_foo<'a>() -> Box<dyn Foo<'a>> {
 
 fn main() {
     let x: Box<dyn Foo<'static>> = make_foo();
-    let y: Box<dyn for<'a> Foo<'a>> = x; //~ ERROR higher-ranked subtype error
+    let y: Box<dyn for<'a> Foo<'a>> = x; //~ ERROR mismatched types [E0308]
 }
diff --git a/src/test/ui/nll/relate_tys/trait-hrtb.stderr b/src/test/ui/nll/relate_tys/trait-hrtb.stderr
index 4df2f352522..60a7f204446 100644
--- a/src/test/ui/nll/relate_tys/trait-hrtb.stderr
+++ b/src/test/ui/nll/relate_tys/trait-hrtb.stderr
@@ -1,8 +1,12 @@
-error: higher-ranked subtype error
+error[E0308]: mismatched types
   --> $DIR/trait-hrtb.rs:15:39
    |
 LL |     let y: Box<dyn for<'a> Foo<'a>> = x;
-   |                                       ^
+   |                                       ^ one type is more general than the other
+   |
+   = note: expected trait object `dyn for<'r> Foo<'r>`
+              found trait object `dyn Foo<'_>`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/rfc1623.nll.stderr b/src/test/ui/rfc1623.nll.stderr
index a3d94679434..cc247bbcb11 100644
--- a/src/test/ui/rfc1623.nll.stderr
+++ b/src/test/ui/rfc1623.nll.stderr
@@ -19,7 +19,7 @@ LL | struct SomeStruct<'x, 'y, 'z: 'x> {
    = note: required because it appears within the type `&SomeStruct`
    = note: shared static variables must have a type that implements `Sync`
 
-error: higher-ranked subtype error
+error[E0308]: mismatched types
   --> $DIR/rfc1623.rs:21:35
    |
 LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
@@ -29,9 +29,12 @@ LL | |     bar: &Bar { bools: &[true, true] },
 LL | |     f: &id,
 LL | |
 LL | | };
-   | |_^
+   | |_^ one type is more general than the other
+   |
+   = note: expected type `for<'r, 's> Fn<(&'r Foo<'s>,)>`
+              found type `Fn<(&Foo<'_>,)>`
 
-error: higher-ranked subtype error
+error[E0308]: mismatched types
   --> $DIR/rfc1623.rs:21:35
    |
 LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
@@ -41,9 +44,12 @@ LL | |     bar: &Bar { bools: &[true, true] },
 LL | |     f: &id,
 LL | |
 LL | | };
-   | |_^
+   | |_^ one type is more general than the other
+   |
+   = note: expected type `for<'r, 's> Fn<(&'r Foo<'s>,)>`
+              found type `Fn<(&Foo<'_>,)>`
 
-error: higher-ranked subtype error
+error: implementation of `FnOnce` is not general enough
   --> $DIR/rfc1623.rs:21:35
    |
 LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
@@ -53,9 +59,12 @@ LL | |     bar: &Bar { bools: &[true, true] },
 LL | |     f: &id,
 LL | |
 LL | | };
-   | |_^
+   | |_^ implementation of `FnOnce` is not general enough
+   |
+   = note: `fn(&'2 Foo<'_>) -> &'2 Foo<'_> {id::<&'2 Foo<'_>>}` must implement `FnOnce<(&'1 Foo<'_>,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 Foo<'_>,)>`, for some specific lifetime `'2`
 
-error: higher-ranked subtype error
+error: implementation of `FnOnce` is not general enough
   --> $DIR/rfc1623.rs:21:35
    |
 LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
@@ -65,8 +74,12 @@ LL | |     bar: &Bar { bools: &[true, true] },
 LL | |     f: &id,
 LL | |
 LL | | };
-   | |_^
+   | |_^ implementation of `FnOnce` is not general enough
+   |
+   = note: `fn(&Foo<'2>) -> &Foo<'2> {id::<&Foo<'2>>}` must implement `FnOnce<(&Foo<'1>,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&Foo<'2>,)>`, for some specific lifetime `'2`
 
 error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0277, E0308.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/unboxed-closures/issue-30906.nll.stderr b/src/test/ui/unboxed-closures/issue-30906.nll.stderr
index 2db392e8b8b..147a2097473 100644
--- a/src/test/ui/unboxed-closures/issue-30906.nll.stderr
+++ b/src/test/ui/unboxed-closures/issue-30906.nll.stderr
@@ -1,8 +1,11 @@
-error: higher-ranked subtype error
+error: implementation of `FnOnce` is not general enough
   --> $DIR/issue-30906.rs:18:5
    |
 LL |     test(Compose(f, |_| {}));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
+   |
+   = note: `fn(&'2 str) -> T` must implement `FnOnce<(&'1 str,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 str,)>`, for some specific lifetime `'2`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/where-clauses/where-for-self-2.nll.stderr b/src/test/ui/where-clauses/where-for-self-2.nll.stderr
index d0c476dc6ec..f65db78fc89 100644
--- a/src/test/ui/where-clauses/where-for-self-2.nll.stderr
+++ b/src/test/ui/where-clauses/where-for-self-2.nll.stderr
@@ -1,8 +1,11 @@
-error: higher-ranked subtype error
+error: implementation of `Bar` is not general enough
   --> $DIR/where-for-self-2.rs:23:5
    |
 LL |     foo(&X);
-   |     ^^^^^^^
+   |     ^^^^^^^ implementation of `Bar` is not general enough
+   |
+   = note: `&'0 u32` must implement `Bar`, for any lifetime `'0`...
+   = note: ...but `Bar` is actually implemented for the type `&'static u32`
 
 error: aborting due to previous error