about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/constraints/mod.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs14
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs14
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs222
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs8
-rw-r--r--compiler/rustc_borrowck/src/type_check/canonical.rs10
-rw-r--r--compiler/rustc_borrowck/src/type_check/constraint_conversion.rs4
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs45
-rw-r--r--compiler/rustc_borrowck/src/type_check/relate_tys.rs6
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs4
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs11
-rw-r--r--compiler/rustc_middle/src/mir/query.rs11
-rw-r--r--compiler/rustc_middle/src/ty/impls_ty.rs4
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant-nll.krisskross.stderr4
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant-nll.oneuse.stderr10
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant-nll.rs3
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant-nll.transmute.stderr2
-rw-r--r--src/test/ui/async-await/issues/issue-72312.nll.stderr13
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr15
-rw-r--r--src/test/ui/nll/user-annotations/adt-nullary-enums.stderr16
-rw-r--r--src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-nll.stderr50
23 files changed, 368 insertions, 104 deletions
diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs
index 6d5466c0c41..a504d0c9122 100644
--- a/compiler/rustc_borrowck/src/constraints/mod.rs
+++ b/compiler/rustc_borrowck/src/constraints/mod.rs
@@ -95,7 +95,7 @@ pub struct OutlivesConstraint<'tcx> {
     pub span: Span,
 
     /// What caused this constraint?
-    pub category: ConstraintCategory,
+    pub category: ConstraintCategory<'tcx>,
 
     /// Variance diagnostic information
     pub variance_info: VarianceDiagInfo<'tcx>,
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index da5f56704d4..191574d7a8f 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -788,7 +788,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         err: &mut Diagnostic,
         location: Location,
         issued_borrow: &BorrowData<'tcx>,
-        explanation: BorrowExplanation,
+        explanation: BorrowExplanation<'tcx>,
     ) {
         let used_in_call = matches!(
             explanation,
@@ -1088,7 +1088,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 BorrowExplanation::MustBeValidFor {
                     category:
                         category @ (ConstraintCategory::Return(_)
-                        | ConstraintCategory::CallArgument
+                        | ConstraintCategory::CallArgument(_)
                         | ConstraintCategory::OpaqueType),
                     from_closure: false,
                     ref region_name,
@@ -1147,7 +1147,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         borrow: &BorrowData<'tcx>,
         drop_span: Span,
         borrow_spans: UseSpans<'tcx>,
-        explanation: BorrowExplanation,
+        explanation: BorrowExplanation<'tcx>,
     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
         debug!(
             "report_local_value_does_not_live_long_enough(\
@@ -1352,7 +1352,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         drop_span: Span,
         borrow_spans: UseSpans<'tcx>,
         proper_span: Span,
-        explanation: BorrowExplanation,
+        explanation: BorrowExplanation<'tcx>,
     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
         debug!(
             "report_temporary_value_does_not_live_long_enough(\
@@ -1410,7 +1410,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         borrow: &BorrowData<'tcx>,
         borrow_span: Span,
         return_span: Span,
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
         opt_place_desc: Option<&String>,
     ) -> Option<DiagnosticBuilder<'cx, ErrorGuaranteed>> {
         let return_kind = match category {
@@ -1508,7 +1508,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         use_span: UseSpans<'tcx>,
         var_span: Span,
         fr_name: &RegionName,
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
         constraint_span: Span,
         captured_var: &str,
     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
@@ -1559,7 +1559,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 let msg = format!("{} is returned here", kind);
                 err.span_note(constraint_span, &msg);
             }
-            ConstraintCategory::CallArgument => {
+            ConstraintCategory::CallArgument(_) => {
                 fr_name.highlight_region_name(&mut err);
                 if matches!(use_span.generator_kind(), Some(GeneratorKind::Async(_))) {
                     err.note(
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 0b6be453b92..5d9e5907dff 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -24,7 +24,7 @@ use crate::{
 use super::{find_use, RegionName, UseSpans};
 
 #[derive(Debug)]
-pub(crate) enum BorrowExplanation {
+pub(crate) enum BorrowExplanation<'tcx> {
     UsedLater(LaterUseKind, Span, Option<Span>),
     UsedLaterInLoop(LaterUseKind, Span, Option<Span>),
     UsedLaterWhenDropped {
@@ -33,7 +33,7 @@ pub(crate) enum BorrowExplanation {
         should_note_order: bool,
     },
     MustBeValidFor {
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
         from_closure: bool,
         span: Span,
         region_name: RegionName,
@@ -51,11 +51,11 @@ pub(crate) enum LaterUseKind {
     Other,
 }
 
-impl BorrowExplanation {
+impl<'tcx> BorrowExplanation<'tcx> {
     pub(crate) fn is_explained(&self) -> bool {
         !matches!(self, BorrowExplanation::Unexplained)
     }
-    pub(crate) fn add_explanation_to_diagnostic<'tcx>(
+    pub(crate) fn add_explanation_to_diagnostic(
         &self,
         tcx: TyCtxt<'tcx>,
         body: &Body<'tcx>,
@@ -276,7 +276,7 @@ impl BorrowExplanation {
     pub(crate) fn add_lifetime_bound_suggestion_to_diagnostic(
         &self,
         err: &mut Diagnostic,
-        category: &ConstraintCategory,
+        category: &ConstraintCategory<'tcx>,
         span: Span,
         region_name: &RegionName,
     ) {
@@ -305,7 +305,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         &self,
         borrow_region: RegionVid,
         outlived_region: RegionVid,
-    ) -> (ConstraintCategory, bool, Span, Option<RegionName>) {
+    ) -> (ConstraintCategory<'tcx>, bool, Span, Option<RegionName>) {
         let BlameConstraint { category, from_closure, cause, variance_info: _ } =
             self.regioncx.best_blame_constraint(
                 &self.body,
@@ -337,7 +337,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         location: Location,
         borrow: &BorrowData<'tcx>,
         kind_place: Option<(WriteKind, Place<'tcx>)>,
-    ) -> BorrowExplanation {
+    ) -> BorrowExplanation<'tcx> {
         debug!(
             "explain_why_borrow_contains_point(location={:?}, borrow={:?}, kind_place={:?})",
             location, borrow, kind_place
diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
index 1688d1259fa..9d81330745f 100644
--- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
@@ -161,7 +161,7 @@ impl OutlivesSuggestionBuilder {
     pub(crate) fn intermediate_suggestion(
         &mut self,
         mbcx: &MirBorrowckCtxt<'_, '_>,
-        errci: &ErrorConstraintInfo,
+        errci: &ErrorConstraintInfo<'_>,
         diag: &mut Diagnostic,
     ) {
         // Emit an intermediate note.
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 6478a104815..35f805ce76e 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -1,10 +1,14 @@
 //! Error reporting machinery for lifetime errors.
 
-use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_data_structures::stable_set::FxHashSet;
+use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
+use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::{self as hir, Item, ItemKind, Node};
 use rustc_infer::infer::{
     error_reporting::nice_region_error::{
         self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params,
-        NiceRegionError,
+        HirTraitObjectVisitor, NiceRegionError, TraitObjectVisitor,
     },
     error_reporting::unexpected_hidden_region_diagnostic,
     NllRegionVariableOrigin, RelateParamBound,
@@ -12,8 +16,11 @@ use rustc_infer::infer::{
 use rustc_middle::hir::place::PlaceBase;
 use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
 use rustc_middle::ty::subst::InternalSubsts;
+use rustc_middle::ty::Region;
+use rustc_middle::ty::TypeVisitor;
 use rustc_middle::ty::{self, RegionVid, Ty};
 use rustc_span::symbol::sym;
+use rustc_span::symbol::Ident;
 use rustc_span::Span;
 
 use crate::borrowck_errors;
@@ -27,7 +34,7 @@ use crate::{
     MirBorrowckCtxt,
 };
 
-impl ConstraintDescription for ConstraintCategory {
+impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> {
     fn description(&self) -> &'static str {
         // Must end with a space. Allows for empty names to be provided.
         match self {
@@ -37,7 +44,7 @@ impl ConstraintDescription for ConstraintCategory {
             ConstraintCategory::UseAsConst => "using this value as a constant ",
             ConstraintCategory::UseAsStatic => "using this value as a static ",
             ConstraintCategory::Cast => "cast ",
-            ConstraintCategory::CallArgument => "argument ",
+            ConstraintCategory::CallArgument(_) => "argument ",
             ConstraintCategory::TypeAnnotation => "type annotation ",
             ConstraintCategory::ClosureBounds => "closure body ",
             ConstraintCategory::SizedBound => "proving this value is `Sized` ",
@@ -101,7 +108,7 @@ pub(crate) enum RegionErrorKind<'tcx> {
 
 /// Information about the various region constraints involved in a borrow checker error.
 #[derive(Clone, Debug)]
-pub struct ErrorConstraintInfo {
+pub struct ErrorConstraintInfo<'tcx> {
     // fr: outlived_fr
     pub(super) fr: RegionVid,
     pub(super) fr_is_local: bool,
@@ -109,7 +116,7 @@ pub struct ErrorConstraintInfo {
     pub(super) outlived_fr_is_local: bool,
 
     // Category and span for best blame constraint
-    pub(super) category: ConstraintCategory,
+    pub(super) category: ConstraintCategory<'tcx>,
     pub(super) span: Span,
 }
 
@@ -256,6 +263,70 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         outlives_suggestion.add_suggestion(self);
     }
 
+    fn get_impl_ident_and_self_ty_from_trait(
+        &self,
+        def_id: DefId,
+        trait_objects: &FxHashSet<DefId>,
+    ) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> {
+        let tcx = self.infcx.tcx;
+        match tcx.hir().get_if_local(def_id) {
+            Some(Node::ImplItem(impl_item)) => {
+                match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id())) {
+                    Some(Node::Item(Item {
+                        kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
+                        ..
+                    })) => Some((impl_item.ident, self_ty)),
+                    _ => None,
+                }
+            }
+            Some(Node::TraitItem(trait_item)) => {
+                let trait_did = tcx.hir().get_parent_item(trait_item.hir_id());
+                match tcx.hir().find_by_def_id(trait_did) {
+                    Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
+                        // The method being called is defined in the `trait`, but the `'static`
+                        // obligation comes from the `impl`. Find that `impl` so that we can point
+                        // at it in the suggestion.
+                        let trait_did = trait_did.to_def_id();
+                        match tcx
+                            .hir()
+                            .trait_impls(trait_did)
+                            .iter()
+                            .filter_map(|&impl_did| {
+                                match tcx.hir().get_if_local(impl_did.to_def_id()) {
+                                    Some(Node::Item(Item {
+                                        kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
+                                        ..
+                                    })) if trait_objects.iter().all(|did| {
+                                        // FIXME: we should check `self_ty` against the receiver
+                                        // type in the `UnifyReceiver` context, but for now, use
+                                        // this imperfect proxy. This will fail if there are
+                                        // multiple `impl`s for the same trait like
+                                        // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
+                                        // In that case, only the first one will get suggestions.
+                                        let mut traits = vec![];
+                                        let mut hir_v = HirTraitObjectVisitor(&mut traits, *did);
+                                        hir_v.visit_ty(self_ty);
+                                        !traits.is_empty()
+                                    }) =>
+                                    {
+                                        Some(self_ty)
+                                    }
+                                    _ => None,
+                                }
+                            })
+                            .next()
+                        {
+                            Some(self_ty) => Some((trait_item.ident, self_ty)),
+                            _ => None,
+                        }
+                    }
+                    _ => None,
+                }
+            }
+            _ => None,
+        }
+    }
+
     /// Report an error because the universal region `fr` was required to outlive
     /// `outlived_fr` but it is not known to do so. For example:
     ///
@@ -279,6 +350,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             });
 
         debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info);
+
         // Check if we can use one of the "nice region errors".
         if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
             let nice = NiceRegionError::new_from_span(self.infcx, cause.span, o, f);
@@ -312,7 +384,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 self.report_fnmut_error(&errci, kind)
             }
             (ConstraintCategory::Assignment, true, false)
-            | (ConstraintCategory::CallArgument, true, false) => {
+            | (ConstraintCategory::CallArgument(_), true, false) => {
                 let mut db = self.report_escaping_data_error(&errci);
 
                 outlives_suggestion.intermediate_suggestion(self, &errci, &mut db);
@@ -405,7 +477,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
     /// ```
     fn report_fnmut_error(
         &self,
-        errci: &ErrorConstraintInfo,
+        errci: &ErrorConstraintInfo<'tcx>,
         kind: ReturnConstraint,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let ErrorConstraintInfo { outlived_fr, span, .. } = errci;
@@ -486,7 +558,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
     /// ```
     fn report_escaping_data_error(
         &self,
-        errci: &ErrorConstraintInfo,
+        errci: &ErrorConstraintInfo<'tcx>,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let ErrorConstraintInfo { span, category, .. } = errci;
 
@@ -548,24 +620,28 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         // Only show an extra note if we can find an 'error region' for both of the region
         // variables. This avoids showing a noisy note that just mentions 'synthetic' regions
         // that don't help the user understand the error.
-        if self.to_error_region(errci.fr).is_some()
-            && self.to_error_region(errci.outlived_fr).is_some()
-        {
-            let fr_region_name = self.give_region_a_name(errci.fr).unwrap();
-            fr_region_name.highlight_region_name(&mut diag);
-            let outlived_fr_region_name = self.give_region_a_name(errci.outlived_fr).unwrap();
-            outlived_fr_region_name.highlight_region_name(&mut diag);
+        match (self.to_error_region(errci.fr), self.to_error_region(errci.outlived_fr)) {
+            (Some(f), Some(o)) => {
+                self.maybe_suggest_constrain_dyn_trait_impl(&mut diag, f, o, category);
 
-            diag.span_label(
-                *span,
-                format!(
-                    "{}requires that `{}` must outlive `{}`",
-                    category.description(),
-                    fr_region_name,
-                    outlived_fr_region_name,
-                ),
-            );
+                let fr_region_name = self.give_region_a_name(errci.fr).unwrap();
+                fr_region_name.highlight_region_name(&mut diag);
+                let outlived_fr_region_name = self.give_region_a_name(errci.outlived_fr).unwrap();
+                outlived_fr_region_name.highlight_region_name(&mut diag);
+
+                diag.span_label(
+                    *span,
+                    format!(
+                        "{}requires that `{}` must outlive `{}`",
+                        category.description(),
+                        fr_region_name,
+                        outlived_fr_region_name,
+                    ),
+                );
+            }
+            _ => {}
         }
+
         diag
     }
 
@@ -586,7 +662,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
     /// ```
     fn report_general_error(
         &self,
-        errci: &ErrorConstraintInfo,
+        errci: &ErrorConstraintInfo<'tcx>,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let ErrorConstraintInfo {
             fr,
@@ -699,6 +775,100 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         }
     }
 
+    fn maybe_suggest_constrain_dyn_trait_impl(
+        &self,
+        diag: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+        f: Region<'tcx>,
+        o: Region<'tcx>,
+        category: &ConstraintCategory<'tcx>,
+    ) {
+        if !o.is_static() {
+            return;
+        }
+
+        let tcx = self.infcx.tcx;
+
+        let instance = if let ConstraintCategory::CallArgument(Some(func_ty)) = category {
+            let (fn_did, substs) = match func_ty.kind() {
+                ty::FnDef(fn_did, substs) => (fn_did, substs),
+                _ => return,
+            };
+            debug!(?fn_did, ?substs);
+
+            // Only suggest this on function calls, not closures
+            let ty = tcx.type_of(fn_did);
+            debug!("ty: {:?}, ty.kind: {:?}", ty, ty.kind());
+            if let ty::Closure(_, _) = ty.kind() {
+                return;
+            }
+
+            if let Ok(Some(instance)) = ty::Instance::resolve(
+                tcx,
+                self.param_env,
+                *fn_did,
+                self.infcx.resolve_vars_if_possible(substs),
+            ) {
+                instance
+            } else {
+                return;
+            }
+        } else {
+            return;
+        };
+
+        let param = match find_param_with_region(tcx, f, o) {
+            Some(param) => param,
+            None => return,
+        };
+        debug!(?param);
+
+        let mut visitor = TraitObjectVisitor(FxHashSet::default());
+        visitor.visit_ty(param.param_ty);
+
+        let Some((ident, self_ty)) =
+            self.get_impl_ident_and_self_ty_from_trait(instance.def_id(), &visitor.0) else {return};
+
+        self.suggest_constrain_dyn_trait_in_impl(diag, &visitor.0, ident, self_ty);
+    }
+
+    #[instrument(skip(self, err), level = "debug")]
+    fn suggest_constrain_dyn_trait_in_impl(
+        &self,
+        err: &mut Diagnostic,
+        found_dids: &FxHashSet<DefId>,
+        ident: Ident,
+        self_ty: &hir::Ty<'_>,
+    ) -> bool {
+        debug!("err: {:#?}", err);
+        let mut suggested = false;
+        for found_did in found_dids {
+            let mut traits = vec![];
+            let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did);
+            hir_v.visit_ty(&self_ty);
+            debug!("trait spans found: {:?}", traits);
+            for span in &traits {
+                let mut multi_span: MultiSpan = vec![*span].into();
+                multi_span.push_span_label(
+                    *span,
+                    "this has an implicit `'static` lifetime requirement".to_string(),
+                );
+                multi_span.push_span_label(
+                    ident.span,
+                    "calling this method introduces the `impl`'s 'static` requirement".to_string(),
+                );
+                err.span_note(multi_span, "the used `impl` has a `'static` requirement");
+                err.span_suggestion_verbose(
+                    span.shrink_to_hi(),
+                    "consider relaxing the implicit `'static` requirement",
+                    " + '_".to_string(),
+                    Applicability::MaybeIncorrect,
+                );
+                suggested = true;
+            }
+        }
+        suggested
+    }
+
     fn suggest_adding_lifetime_params(
         &self,
         diag: &mut Diagnostic,
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index dc6337c54ed..2c460bcb72d 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -87,7 +87,7 @@ pub struct RegionInferenceContext<'tcx> {
 
     /// Map closure bounds to a `Span` that should be used for error reporting.
     closure_bounds_mapping:
-        FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>,
+        FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory<'tcx>, Span)>>,
 
     /// Map universe indexes to information on why we created it.
     universe_causes: FxHashMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
@@ -259,7 +259,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         member_constraints_in: MemberConstraintSet<'tcx, RegionVid>,
         closure_bounds_mapping: FxHashMap<
             Location,
-            FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>,
+            FxHashMap<(RegionVid, RegionVid), (ConstraintCategory<'tcx>, Span)>,
         >,
         universe_causes: FxHashMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
         type_tests: Vec<TypeTest<'tcx>>,
@@ -1772,7 +1772,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         fr1: RegionVid,
         fr1_origin: NllRegionVariableOrigin,
         fr2: RegionVid,
-    ) -> (ConstraintCategory, ObligationCause<'tcx>) {
+    ) -> (ConstraintCategory<'tcx>, ObligationCause<'tcx>) {
         let BlameConstraint { category, cause, .. } =
             self.best_blame_constraint(body, fr1, fr1_origin, |r| {
                 self.provides_universal_region(r, fr1, fr2)
@@ -2270,7 +2270,7 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx
 
 #[derive(Clone, Debug)]
 pub struct BlameConstraint<'tcx> {
-    pub category: ConstraintCategory,
+    pub category: ConstraintCategory<'tcx>,
     pub from_closure: bool,
     pub cause: ObligationCause<'tcx>,
     pub variance_info: ty::VarianceDiagInfo<'tcx>,
diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index 3856b7f4a4b..55c0bf05b48 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -28,7 +28,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     pub(super) fn fully_perform_op<R, Op>(
         &mut self,
         locations: Locations,
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
         op: Op,
     ) -> Fallible<R>
     where
@@ -83,11 +83,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         instantiated
     }
 
+    #[instrument(skip(self), level = "debug")]
     pub(super) fn prove_trait_ref(
         &mut self,
         trait_ref: ty::TraitRef<'tcx>,
         locations: Locations,
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
     ) {
         self.prove_predicates(
             Some(ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
@@ -113,6 +114,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             .into_iter()
             .zip(instantiated_predicates.spans.into_iter())
         {
+            debug!(?predicate);
             let predicate = self.normalize(predicate, locations);
             self.prove_predicate(predicate, locations, ConstraintCategory::Predicate(span));
         }
@@ -122,7 +124,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         &mut self,
         predicates: impl IntoIterator<Item = impl ToPredicate<'tcx>>,
         locations: Locations,
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
     ) {
         for predicate in predicates {
             let predicate = predicate.to_predicate(self.tcx());
@@ -137,7 +139,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         &mut self,
         predicate: ty::Predicate<'tcx>,
         locations: Locations,
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
     ) {
         let param_env = self.param_env;
         self.fully_perform_op(
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index f11a94d7ddd..3c9e3870aea 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -27,7 +27,7 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> {
     param_env: ty::ParamEnv<'tcx>,
     locations: Locations,
     span: Span,
-    category: ConstraintCategory,
+    category: ConstraintCategory<'tcx>,
     constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
 }
 
@@ -40,7 +40,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         locations: Locations,
         span: Span,
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
         constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
     ) -> Self {
         Self {
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 34bc87b20c7..4a2b2942008 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -162,6 +162,8 @@ pub(crate) fn type_check<'mir, 'tcx>(
         &mut constraints,
     );
 
+    debug!(?normalized_inputs_and_output);
+
     for u in ty::UniverseIndex::ROOT..infcx.universe() {
         let info = UniverseInfo::other();
         constraints.universe_causes.insert(u, info);
@@ -185,6 +187,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
         implicit_region_bound,
         &mut borrowck_context,
         |mut cx| {
+            debug!("inside extra closure of type_check_internal");
             cx.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output);
             liveness::generate(
                 &mut cx,
@@ -257,6 +260,7 @@ fn type_check_internal<'a, 'tcx, R>(
     borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
     extra: impl FnOnce(TypeChecker<'a, 'tcx>) -> R,
 ) -> R {
+    debug!("body: {:#?}", body);
     let mut checker = TypeChecker::new(
         infcx,
         body,
@@ -935,7 +939,7 @@ pub(crate) struct MirTypeckRegionConstraints<'tcx> {
     pub(crate) member_constraints: MemberConstraintSet<'tcx, RegionVid>,
 
     pub(crate) closure_bounds_mapping:
-        FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>,
+        FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory<'tcx>, Span)>>,
 
     pub(crate) universe_causes: FxHashMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
 
@@ -1125,7 +1129,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     fn push_region_constraints(
         &mut self,
         locations: Locations,
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
         data: &QueryRegionConstraints<'tcx>,
     ) {
         debug!("constraints generated: {:#?}", data);
@@ -1150,7 +1154,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         sub: Ty<'tcx>,
         sup: Ty<'tcx>,
         locations: Locations,
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
     ) -> Fallible<()> {
         // Use this order of parameters because the sup type is usually the
         // "expected" type in diagnostics.
@@ -1163,7 +1167,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         expected: Ty<'tcx>,
         found: Ty<'tcx>,
         locations: Locations,
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
     ) -> Fallible<()> {
         self.relate_types(expected, ty::Variance::Invariant, found, locations, category)
     }
@@ -1175,7 +1179,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         v: ty::Variance,
         user_ty: &UserTypeProjection,
         locations: Locations,
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
     ) -> Fallible<()> {
         let annotated_type = self.user_type_annotations[user_ty.base].inferred_ty;
         let mut curr_projected_ty = PlaceTy::from_ty(annotated_type);
@@ -1212,6 +1216,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     #[instrument(skip(self, body, location), level = "debug")]
     fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Location) {
         let tcx = self.tcx();
+        debug!("stmt kind: {:?}", stmt.kind);
         match stmt.kind {
             StatementKind::Assign(box (ref place, ref rv)) => {
                 // Assignments to temporaries are not "interesting";
@@ -1251,9 +1256,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 );
 
                 let place_ty = place.ty(body, tcx).ty;
+                debug!(?place_ty);
                 let place_ty = self.normalize(place_ty, location);
+                debug!("place_ty normalized: {:?}", place_ty);
                 let rv_ty = rv.ty(body, tcx);
+                debug!(?rv_ty);
                 let rv_ty = self.normalize(rv_ty, location);
+                debug!("normalized rv_ty: {:?}", rv_ty);
                 if let Err(terr) =
                     self.sub_types(rv_ty, place_ty, location.to_locations(), category)
                 {
@@ -1347,6 +1356,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         term_location: Location,
     ) {
         let tcx = self.tcx();
+        debug!("terminator kind: {:?}", term.kind);
         match term.kind {
             TerminatorKind::Goto { .. }
             | TerminatorKind::Resume
@@ -1404,7 +1414,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 // FIXME: check the values
             }
             TerminatorKind::Call {
-                ref func, ref args, destination, target, from_hir_call, ..
+                ref func,
+                ref args,
+                ref destination,
+                from_hir_call,
+                target,
+                ..
             } => {
                 self.check_operand(func, term_location);
                 for arg in args {
@@ -1412,7 +1427,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 }
 
                 let func_ty = func.ty(body, tcx);
-                debug!("check_terminator: call, func_ty={:?}", func_ty);
+                debug!("func_ty.kind: {:?}", func_ty.kind());
+
                 let sig = match func_ty.kind() {
                     ty::FnDef(..) | ty::FnPtr(_) => func_ty.fn_sig(tcx),
                     _ => {
@@ -1425,8 +1441,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     LateBoundRegionConversionTime::FnCall,
                     sig,
                 );
+                debug!(?sig);
                 let sig = self.normalize(sig, term_location);
-                self.check_call_dest(body, term, &sig, destination, target, term_location);
+                self.check_call_dest(body, term, &sig, *destination, target, term_location);
 
                 self.prove_predicates(
                     sig.inputs_and_output
@@ -1585,11 +1602,20 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic) {
             span_mirbug!(self, term, "call to {:?} with wrong # of args", sig);
         }
+
+        let func_ty = if let TerminatorKind::Call { func, .. } = &term.kind {
+            Some(func.ty(body, self.infcx.tcx))
+        } else {
+            None
+        };
+        debug!(?func_ty);
+
         for (n, (fn_arg, op_arg)) in iter::zip(sig.inputs(), args).enumerate() {
             let op_arg_ty = op_arg.ty(body, self.tcx());
+
             let op_arg_ty = self.normalize(op_arg_ty, term_location);
             let category = if from_hir_call {
-                ConstraintCategory::CallArgument
+                ConstraintCategory::CallArgument(func_ty)
             } else {
                 ConstraintCategory::Boring
             };
@@ -1841,6 +1867,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         }
     }
 
+    #[instrument(skip(self, body), level = "debug")]
     fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
         let tcx = self.tcx();
 
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index f98d2c3128c..c45850c6d84 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -28,7 +28,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         v: ty::Variance,
         b: Ty<'tcx>,
         locations: Locations,
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
     ) -> Fallible<()> {
         TypeRelating::new(
             self.infcx,
@@ -47,7 +47,7 @@ struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
     locations: Locations,
 
     /// What category do we assign the resulting `'a: 'b` relationships?
-    category: ConstraintCategory,
+    category: ConstraintCategory<'tcx>,
 
     /// Information so that error reporting knows what types we are relating
     /// when reporting a bound region error.
@@ -58,7 +58,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
     fn new(
         type_checker: &'me mut TypeChecker<'bccx, 'tcx>,
         locations: Locations,
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
         universe_info: UniverseInfo<'tcx>,
     ) -> Self {
         Self { type_checker, locations, category, universe_info }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
index 9948d15c431..53d9acf7d29 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
@@ -16,7 +16,7 @@ mod util;
 
 pub use different_lifetimes::suggest_adding_lifetime_params;
 pub use find_anon_type::find_anon_type;
-pub use static_impl_trait::suggest_new_region_bound;
+pub use static_impl_trait::{suggest_new_region_bound, HirTraitObjectVisitor, TraitObjectVisitor};
 pub use util::find_param_with_region;
 
 impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index a4c46d5cf0b..1081f888f7f 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -546,7 +546,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
 }
 
 /// Collect all the trait objects in a type that could have received an implicit `'static` lifetime.
-pub(super) struct TraitObjectVisitor(pub(super) FxHashSet<DefId>);
+pub struct TraitObjectVisitor(pub FxHashSet<DefId>);
 
 impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor {
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
@@ -563,7 +563,7 @@ impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor {
 }
 
 /// Collect all `hir::Ty<'_>` `Span`s for trait objects with an implicit lifetime.
-pub(super) struct HirTraitObjectVisitor<'a>(pub(super) &'a mut Vec<Span>, pub(super) DefId);
+pub struct HirTraitObjectVisitor<'a>(pub &'a mut Vec<Span>, pub DefId);
 
 impl<'a, 'tcx> Visitor<'tcx> for HirTraitObjectVisitor<'a> {
     fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
index 29b3807a514..96b57b6cd20 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
@@ -34,6 +34,7 @@ pub struct AnonymousParamInfo<'tcx> {
 // i32, which is the type of y but with the anonymous region replaced
 // with 'a, the corresponding bound region and is_first which is true if
 // the hir::Param is the first parameter in the function declaration.
+#[instrument(skip(tcx), level = "debug")]
 pub fn find_param_with_region<'tcx>(
     tcx: TyCtxt<'tcx>,
     anon_region: Region<'tcx>,
@@ -51,9 +52,19 @@ pub fn find_param_with_region<'tcx>(
     let hir_id = hir.local_def_id_to_hir_id(id.as_local()?);
     let body_id = hir.maybe_body_owned_by(hir_id)?;
     let body = hir.body(body_id);
+
+    // Don't perform this on closures
+    match hir.get(hir_id) {
+        hir::Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => {
+            return None;
+        }
+        _ => {}
+    }
+
     let owner_id = hir.body_owner(body_id);
     let fn_decl = hir.fn_decl_by_hir_id(owner_id).unwrap();
     let poly_fn_sig = tcx.fn_sig(id);
+
     let fn_sig = tcx.liberate_late_bound_regions(id, poly_fn_sig);
     body.params
         .iter()
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index 7f7b8bdfc14..01945b543b1 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -338,11 +338,12 @@ pub struct ClosureOutlivesRequirement<'tcx> {
     pub blame_span: Span,
 
     // ... due to this reason.
-    pub category: ConstraintCategory,
+    pub category: ConstraintCategory<'tcx>,
 }
 
 // Make sure this enum doesn't unintentionally grow
-rustc_data_structures::static_assert_size!(ConstraintCategory, 12);
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
 
 /// Outlives-constraints can be categorized to determine whether and why they
 /// are interesting (for error reporting). Order of variants indicates sort
@@ -351,7 +352,7 @@ rustc_data_structures::static_assert_size!(ConstraintCategory, 12);
 /// See also `rustc_const_eval::borrow_check::constraints`.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
 #[derive(TyEncodable, TyDecodable, HashStable)]
-pub enum ConstraintCategory {
+pub enum ConstraintCategory<'tcx> {
     Return(ReturnConstraint),
     Yield,
     UseAsConst,
@@ -363,7 +364,9 @@ pub enum ConstraintCategory {
     ///
     /// We try to get the category that the closure used when reporting this.
     ClosureBounds,
-    CallArgument,
+
+    /// Contains the function type if available.
+    CallArgument(Option<Ty<'tcx>>),
     CopyBound,
     SizedBound,
     Assignment,
diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs
index 65c9b1aed05..42e5a05d63b 100644
--- a/compiler/rustc_middle/src/ty/impls_ty.rs
+++ b/compiler/rustc_middle/src/ty/impls_ty.rs
@@ -135,8 +135,8 @@ impl<'a> HashStable<StableHashingContext<'a>> for ty::RegionKind {
             ty::RePlaceholder(p) => {
                 p.hash_stable(hcx, hasher);
             }
-            ty::ReVar(..) => {
-                bug!("StableHasher: unexpected region {:?}", *self)
+            ty::ReVar(reg) => {
+                reg.hash_stable(hcx, hasher);
             }
         }
     }
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant-nll.krisskross.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant-nll.krisskross.stderr
index 231e98cf841..09119ea2bb5 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant-nll.krisskross.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant-nll.krisskross.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/project-fn-ret-invariant-nll.rs:63:5
+  --> $DIR/project-fn-ret-invariant-nll.rs:64:5
    |
 LL | fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
    |              --  -- lifetime `'b` defined here
@@ -15,7 +15,7 @@ LL |     (a, b)
    = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
-  --> $DIR/project-fn-ret-invariant-nll.rs:63:5
+  --> $DIR/project-fn-ret-invariant-nll.rs:64:5
    |
 LL | fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
    |              --  -- lifetime `'b` defined here
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant-nll.oneuse.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant-nll.oneuse.stderr
index 1dbfff6a8cd..266f3b99f9f 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant-nll.oneuse.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant-nll.oneuse.stderr
@@ -15,19 +15,19 @@ LL |     let a = bar(f, x);
    = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
-  --> $DIR/project-fn-ret-invariant-nll.rs:47:13
+  --> $DIR/project-fn-ret-invariant-nll.rs:46:13
    |
 LL | fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
    |        --  -- lifetime `'b` defined here
    |        |
    |        lifetime `'a` defined here
-...
-LL |     let b = bar(f, y);
+LL |     let f = foo; // <-- No consistent type can be inferred for `f` here.
+LL |     let a = bar(f, x);
    |             ^^^^^^^^^ argument requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
-   = note: requirement occurs because of the type `Type<'_>`, which makes the generic argument `'_` invariant
-   = note: the struct `Type<'a>` is invariant over the parameter `'a`
+   = note: requirement occurs because of a function pointer to `foo`
+   = note: the function `foo` is invariant over the parameter `'a`
    = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 help: `'a` and `'b` must be the same: replace one with the other
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant-nll.rs b/src/test/ui/associated-types/cache/project-fn-ret-invariant-nll.rs
index 6cd5c6417a9..15bf38dabc0 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant-nll.rs
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant-nll.rs
@@ -44,7 +44,8 @@ fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
 fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
     let f = foo; // <-- No consistent type can be inferred for `f` here.
     let a = bar(f, x); //[oneuse]~ ERROR lifetime may not live long enough
-    let b = bar(f, y); //[oneuse]~ ERROR lifetime may not live long enough
+    //[oneuse]~^ ERROR lifetime may not live long enough
+    let b = bar(f, y);
     (a, b)
 }
 
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant-nll.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant-nll.transmute.stderr
index 352914f020c..56f08152999 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant-nll.transmute.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant-nll.transmute.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/project-fn-ret-invariant-nll.rs:56:5
+  --> $DIR/project-fn-ret-invariant-nll.rs:57:5
    |
 LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> {
    |        -- lifetime `'a` defined here
diff --git a/src/test/ui/async-await/issues/issue-72312.nll.stderr b/src/test/ui/async-await/issues/issue-72312.nll.stderr
index 53b2c931cce..02e47721e0c 100644
--- a/src/test/ui/async-await/issues/issue-72312.nll.stderr
+++ b/src/test/ui/async-await/issues/issue-72312.nll.stderr
@@ -1,5 +1,5 @@
 error[E0521]: borrowed data escapes outside of associated function
-  --> $DIR/issue-72312.rs:20:24
+  --> $DIR/issue-72312.rs:20:9
    |
 LL |       pub async fn start(&self) {
    |                          -----
@@ -7,18 +7,17 @@ LL |       pub async fn start(&self) {
    |                          `self` is a reference that is only valid in the associated function body
    |                          let's call the lifetime of this reference `'1`
 ...
-LL |           require_static(async move {
-   |  ________________________^
+LL | /         require_static(async move {
 LL | |
 LL | |
 LL | |
 LL | |
 LL | |             &self;
 LL | |         });
-   | |         ^
-   | |         |
-   | |_________`self` escapes the associated function body here
-   |           argument requires that `'1` must outlive `'static`
+   | |          ^
+   | |          |
+   | |__________`self` escapes the associated function body here
+   |            argument requires that `'1` must outlive `'static`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
index 30ef343b261..3ab55b370c2 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
@@ -72,14 +72,15 @@ LL | | }
 error[E0597]: `a` does not live long enough
   --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:30:26
    |
-LL |     let cell = Cell::new(&a);
-   |                ----------^^-
-   |                |         |
-   |                |         borrowed value does not live long enough
-   |                argument requires that `a` is borrowed for `'static`
+LL |       let cell = Cell::new(&a);
+   |                            ^^ borrowed value does not live long enough
 ...
-LL | }
-   | - `a` dropped here while still borrowed
+LL | /     foo(cell, |cell_a, cell_x| {
+LL | |         cell_x.set(cell_a.get()); // forces 'a: 'x, implies 'a = 'static -> borrow error
+LL | |     })
+   | |______- argument requires that `a` is borrowed for `'static`
+LL |   }
+   |   - `a` dropped here while still borrowed
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr b/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr
index bb703412228..3326fa521fc 100644
--- a/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr
+++ b/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr
@@ -1,14 +1,14 @@
 error[E0597]: `c` does not live long enough
   --> $DIR/adt-nullary-enums.rs:33:41
    |
-LL |         SomeEnum::SomeVariant(Cell::new(&c)),
-   |                               ----------^^-
-   |                               |         |
-   |                               |         borrowed value does not live long enough
-   |                               argument requires that `c` is borrowed for `'static`
-...
-LL | }
-   | - `c` dropped here while still borrowed
+LL | /     combine(
+LL | |         SomeEnum::SomeVariant(Cell::new(&c)),
+   | |                                         ^^ borrowed value does not live long enough
+LL | |         SomeEnum::SomeOtherVariant::<Cell<&'static u32>>,
+LL | |     );
+   | |_____- argument requires that `c` is borrowed for `'static`
+LL |   }
+   |   - `c` dropped here while still borrowed
 
 error[E0597]: `c` does not live long enough
   --> $DIR/adt-nullary-enums.rs:41:41
diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-nll.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-nll.stderr
index 38731ea8955..5d9c7077fa1 100644
--- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-nll.stderr
+++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-nll.stderr
@@ -10,6 +10,18 @@ LL |         val.use_self::<T>()
    |         |
    |         `val` escapes the function body here
    |         argument requires that `'a` must outlive `'static`
+   |
+note: the used `impl` has a `'static` requirement
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-nll.rs:19:32
+   |
+LL |     impl<T> MyTrait<T> for dyn ObjectTrait<T> {
+   |                                ^^^^^^^^^^^^^^ this has an implicit `'static` lifetime requirement
+LL |         fn use_self<K>(&self) -> &() { panic!() }
+   |            -------- calling this method introduces the `impl`'s 'static` requirement
+help: consider relaxing the implicit `'static` requirement
+   |
+LL |     impl<T> MyTrait<T> for dyn ObjectTrait<T> + '_ {
+   |                                               ++++
 
 error[E0521]: borrowed data escapes outside of function
   --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-nll.rs:74:9
@@ -23,6 +35,18 @@ LL |         val.use_self()
    |         |
    |         `val` escapes the function body here
    |         argument requires that `'a` must outlive `'static`
+   |
+note: the used `impl` has a `'static` requirement
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-nll.rs:69:14
+   |
+LL |     impl dyn ObjectTrait {
+   |              ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement
+LL |         fn use_self(&self) -> &() { panic!() }
+   |            -------- calling this method introduces the `impl`'s 'static` requirement
+help: consider relaxing the implicit `'static` requirement
+   |
+LL |     impl dyn ObjectTrait + '_ {
+   |                          ++++
 
 error[E0521]: borrowed data escapes outside of function
   --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-nll.rs:94:9
@@ -36,6 +60,19 @@ LL |         val.use_self()
    |         |
    |         `val` escapes the function body here
    |         argument requires that `'a` must outlive `'static`
+   |
+note: the used `impl` has a `'static` requirement
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-nll.rs:91:26
+   |
+LL |         fn use_self(&self) -> &() { panic!() }
+   |            -------- calling this method introduces the `impl`'s 'static` requirement
+...
+LL |     impl MyTrait for dyn ObjectTrait {}
+   |                          ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement
+help: consider relaxing the implicit `'static` requirement
+   |
+LL |     impl MyTrait for dyn ObjectTrait + '_ {}
+   |                                      ++++
 
 error[E0521]: borrowed data escapes outside of function
   --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-nll.rs:114:9
@@ -49,6 +86,19 @@ LL |         MyTrait::use_self(val)
    |         |
    |         `val` escapes the function body here
    |         argument requires that `'a` must outlive `'static`
+   |
+note: the used `impl` has a `'static` requirement
+  --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-nll.rs:110:26
+   |
+LL |         fn use_self(&self) -> &() { panic!() }
+   |            -------- calling this method introduces the `impl`'s 'static` requirement
+...
+LL |     impl MyTrait for dyn ObjectTrait {}
+   |                          ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement
+help: consider relaxing the implicit `'static` requirement
+   |
+LL |     impl MyTrait for dyn ObjectTrait + '_ {}
+   |                                      ++++
 
 error: aborting due to 4 previous errors