about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs12
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs851
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note.rs421
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/region.rs1259
4 files changed, 1273 insertions, 1270 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 13839214adc..55147ee337f 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -10,14 +10,12 @@ use rustc_hir::GenericBound::Trait;
 use rustc_hir::QPath::Resolved;
 use rustc_hir::WherePredicate::BoundPredicate;
 use rustc_hir::{PolyTraitRef, TyKind, WhereBoundPredicate};
-use rustc_infer::infer::{
-    error_reporting::nice_region_error::{
-        self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params,
-        HirTraitObjectVisitor, NiceRegionError, TraitObjectVisitor,
-    },
-    error_reporting::unexpected_hidden_region_diagnostic,
-    NllRegionVariableOrigin, RelateParamBound,
+use rustc_infer::infer::error_reporting::nice_region_error::{
+    self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params,
+    HirTraitObjectVisitor, NiceRegionError, TraitObjectVisitor,
 };
+use rustc_infer::infer::error_reporting::region::unexpected_hidden_region_diagnostic;
+use rustc_infer::infer::{NllRegionVariableOrigin, RelateParamBound};
 use rustc_middle::bug;
 use rustc_middle::hir::place::PlaceBase;
 use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index cebb9d09a47..bb1285ee813 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -45,13 +45,10 @@
 //! ported to this system, and which relies on string concatenation at the
 //! time of error detection.
 
-use super::lexical_region_resolve::RegionResolutionError;
-use super::region_constraints::GenericKind;
-use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs};
+use super::{InferCtxt, TypeTrace, ValuePairs};
 
-use crate::errors::{self, ObligationCauseFailureCode, TypeErrorAdditionalDiags};
+use crate::errors::{ObligationCauseFailureCode, TypeErrorAdditionalDiags};
 use crate::infer;
-use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
 use crate::infer::ExpectedFound;
 use crate::traits::{
     IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
@@ -61,38 +58,36 @@ use crate::traits::{
 use crate::infer::relate::{self, RelateResult, TypeRelation};
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::{
-    codes::*, pluralize, struct_span_code_err, Applicability, Diag, DiagCtxtHandle,
-    DiagStyledString, ErrorGuaranteed, IntoDiagArg, StringPart,
+    pluralize, Applicability, Diag, DiagCtxtHandle, DiagStyledString, IntoDiagArg, StringPart,
 };
 use rustc_hir::def::DefKind;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::{self as hir, ParamName};
+use rustc_hir::{self as hir};
 use rustc_macros::extension;
 use rustc_middle::bug;
 use rustc_middle::dep_graph::DepContext;
 use rustc_middle::ty::error::TypeErrorToStringExt;
 use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError, PrintTraitRefExt as _};
-use rustc_middle::ty::Upcast;
 use rustc_middle::ty::{
-    self, error::TypeError, IsSuggestable, List, Region, Ty, TyCtxt, TypeFoldable,
-    TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
+    self, error::TypeError, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
+    TypeVisitable, TypeVisitableExt,
 };
-use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
+use rustc_span::{sym, BytePos, DesugaringKind, Pos, Span};
 use rustc_target::spec::abi;
 use std::borrow::Cow;
 use std::ops::{ControlFlow, Deref};
 use std::path::PathBuf;
 use std::{cmp, fmt, iter};
 
-mod note;
 mod note_and_explain;
 mod suggest;
 
 pub(crate) mod need_type_info;
 pub mod sub_relations;
 pub use need_type_info::TypeAnnotationNeeded;
+pub mod region;
 
 pub mod nice_region_error;
 
@@ -159,245 +154,6 @@ impl<'tcx> Deref for TypeErrCtxt<'_, 'tcx> {
     }
 }
 
-pub(super) fn note_and_explain_region<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    err: &mut Diag<'_>,
-    generic_param_scope: LocalDefId,
-    prefix: &str,
-    region: ty::Region<'tcx>,
-    suffix: &str,
-    alt_span: Option<Span>,
-) {
-    let (description, span) = match *region {
-        ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::RePlaceholder(_) | ty::ReStatic => {
-            msg_span_from_named_region(tcx, generic_param_scope, region, alt_span)
-        }
-
-        ty::ReError(_) => return,
-
-        // FIXME(#125431): `ReVar` shouldn't reach here.
-        ty::ReVar(_) => (format!("lifetime `{region}`"), alt_span),
-
-        ty::ReBound(..) | ty::ReErased => {
-            bug!("unexpected region for note_and_explain_region: {:?}", region);
-        }
-    };
-
-    emit_msg_span(err, prefix, description, span, suffix);
-}
-
-fn explain_free_region<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    err: &mut Diag<'_>,
-    generic_param_scope: LocalDefId,
-    prefix: &str,
-    region: ty::Region<'tcx>,
-    suffix: &str,
-) {
-    let (description, span) = msg_span_from_named_region(tcx, generic_param_scope, region, None);
-
-    label_msg_span(err, prefix, description, span, suffix);
-}
-
-fn msg_span_from_named_region<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    generic_param_scope: LocalDefId,
-    region: ty::Region<'tcx>,
-    alt_span: Option<Span>,
-) -> (String, Option<Span>) {
-    match *region {
-        ty::ReEarlyParam(br) => {
-            let scope = tcx
-                .parent(tcx.generics_of(generic_param_scope).region_param(br, tcx).def_id)
-                .expect_local();
-            let span = if let Some(param) =
-                tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
-            {
-                param.span
-            } else {
-                tcx.def_span(scope)
-            };
-            let text = if br.has_name() {
-                format!("the lifetime `{}` as defined here", br.name)
-            } else {
-                "the anonymous lifetime as defined here".to_string()
-            };
-            (text, Some(span))
-        }
-        ty::ReLateParam(ref fr) => {
-            if !fr.bound_region.is_named()
-                && let Some((ty, _)) =
-                    find_anon_type(tcx, generic_param_scope, region, &fr.bound_region)
-            {
-                ("the anonymous lifetime defined here".to_string(), Some(ty.span))
-            } else {
-                match fr.bound_region {
-                    ty::BoundRegionKind::BrNamed(_, name) => {
-                        let span = if let Some(param) = tcx
-                            .hir()
-                            .get_generics(generic_param_scope)
-                            .and_then(|generics| generics.get_named(name))
-                        {
-                            param.span
-                        } else {
-                            tcx.def_span(generic_param_scope)
-                        };
-                        let text = if name == kw::UnderscoreLifetime {
-                            "the anonymous lifetime as defined here".to_string()
-                        } else {
-                            format!("the lifetime `{name}` as defined here")
-                        };
-                        (text, Some(span))
-                    }
-                    ty::BrAnon => (
-                        "the anonymous lifetime as defined here".to_string(),
-                        Some(tcx.def_span(generic_param_scope)),
-                    ),
-                    _ => (
-                        format!("the lifetime `{region}` as defined here"),
-                        Some(tcx.def_span(generic_param_scope)),
-                    ),
-                }
-            }
-        }
-        ty::ReStatic => ("the static lifetime".to_owned(), alt_span),
-        ty::RePlaceholder(ty::PlaceholderRegion {
-            bound: ty::BoundRegion { kind: ty::BoundRegionKind::BrNamed(def_id, name), .. },
-            ..
-        }) => (format!("the lifetime `{name}` as defined here"), Some(tcx.def_span(def_id))),
-        ty::RePlaceholder(ty::PlaceholderRegion {
-            bound: ty::BoundRegion { kind: ty::BoundRegionKind::BrAnon, .. },
-            ..
-        }) => ("an anonymous lifetime".to_owned(), None),
-        _ => bug!("{:?}", region),
-    }
-}
-
-fn emit_msg_span(
-    err: &mut Diag<'_>,
-    prefix: &str,
-    description: String,
-    span: Option<Span>,
-    suffix: &str,
-) {
-    let message = format!("{prefix}{description}{suffix}");
-
-    if let Some(span) = span {
-        err.span_note(span, message);
-    } else {
-        err.note(message);
-    }
-}
-
-fn label_msg_span(
-    err: &mut Diag<'_>,
-    prefix: &str,
-    description: String,
-    span: Option<Span>,
-    suffix: &str,
-) {
-    let message = format!("{prefix}{description}{suffix}");
-
-    if let Some(span) = span {
-        err.span_label(span, message);
-    } else {
-        err.note(message);
-    }
-}
-
-#[instrument(level = "trace", skip(infcx))]
-pub fn unexpected_hidden_region_diagnostic<'a, 'tcx>(
-    infcx: &'a InferCtxt<'tcx>,
-    generic_param_scope: LocalDefId,
-    span: Span,
-    hidden_ty: Ty<'tcx>,
-    hidden_region: ty::Region<'tcx>,
-    opaque_ty_key: ty::OpaqueTypeKey<'tcx>,
-) -> Diag<'a> {
-    let tcx = infcx.tcx;
-    let mut err = infcx.dcx().create_err(errors::OpaqueCapturesLifetime {
-        span,
-        opaque_ty: Ty::new_opaque(tcx, opaque_ty_key.def_id.to_def_id(), opaque_ty_key.args),
-        opaque_ty_span: tcx.def_span(opaque_ty_key.def_id),
-    });
-
-    // Explain the region we are capturing.
-    match *hidden_region {
-        ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::ReStatic => {
-            // Assuming regionck succeeded (*), we ought to always be
-            // capturing *some* region from the fn header, and hence it
-            // ought to be free. So under normal circumstances, we will go
-            // down this path which gives a decent human readable
-            // explanation.
-            //
-            // (*) if not, the `tainted_by_errors` field would be set to
-            // `Some(ErrorGuaranteed)` in any case, so we wouldn't be here at all.
-            explain_free_region(
-                tcx,
-                &mut err,
-                generic_param_scope,
-                &format!("hidden type `{hidden_ty}` captures "),
-                hidden_region,
-                "",
-            );
-            if let Some(reg_info) = tcx.is_suitable_region(generic_param_scope, hidden_region) {
-                let fn_returns = tcx.return_type_impl_or_dyn_traits(reg_info.def_id);
-                nice_region_error::suggest_new_region_bound(
-                    tcx,
-                    &mut err,
-                    fn_returns,
-                    hidden_region.to_string(),
-                    None,
-                    format!("captures `{hidden_region}`"),
-                    None,
-                    Some(reg_info.def_id),
-                )
-            }
-        }
-        ty::RePlaceholder(_) => {
-            explain_free_region(
-                tcx,
-                &mut err,
-                generic_param_scope,
-                &format!("hidden type `{}` captures ", hidden_ty),
-                hidden_region,
-                "",
-            );
-        }
-        ty::ReError(_) => {
-            err.downgrade_to_delayed_bug();
-        }
-        _ => {
-            // Ugh. This is a painful case: the hidden region is not one
-            // that we can easily summarize or explain. This can happen
-            // in a case like
-            // `tests/ui/multiple-lifetimes/ordinary-bounds-unsuited.rs`:
-            //
-            // ```
-            // fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> {
-            //   if condition() { a } else { b }
-            // }
-            // ```
-            //
-            // Here the captured lifetime is the intersection of `'a` and
-            // `'b`, which we can't quite express.
-
-            // We can at least report a really cryptic error for now.
-            note_and_explain_region(
-                tcx,
-                &mut err,
-                generic_param_scope,
-                &format!("hidden type `{hidden_ty}` captures "),
-                hidden_region,
-                "",
-                None,
-            );
-        }
-    }
-
-    err
-}
-
 impl<'tcx> InferCtxt<'tcx> {
     pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
         let (def_id, args) = match *ty.kind() {
@@ -438,193 +194,6 @@ impl<'tcx> InferCtxt<'tcx> {
 }
 
 impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
-    pub fn report_region_errors(
-        &self,
-        generic_param_scope: LocalDefId,
-        errors: &[RegionResolutionError<'tcx>],
-    ) -> ErrorGuaranteed {
-        assert!(!errors.is_empty());
-
-        if let Some(guaranteed) = self.infcx.tainted_by_errors() {
-            return guaranteed;
-        }
-
-        debug!("report_region_errors(): {} errors to start", errors.len());
-
-        // try to pre-process the errors, which will group some of them
-        // together into a `ProcessedErrors` group:
-        let errors = self.process_errors(errors);
-
-        debug!("report_region_errors: {} errors after preprocessing", errors.len());
-
-        let mut guar = None;
-        for error in errors {
-            debug!("report_region_errors: error = {:?}", error);
-
-            let e = if let Some(guar) =
-                self.try_report_nice_region_error(generic_param_scope, &error)
-            {
-                guar
-            } else {
-                match error.clone() {
-                    // These errors could indicate all manner of different
-                    // problems with many different solutions. Rather
-                    // than generate a "one size fits all" error, what we
-                    // attempt to do is go through a number of specific
-                    // scenarios and try to find the best way to present
-                    // the error. If all of these fails, we fall back to a rather
-                    // general bit of code that displays the error information
-                    RegionResolutionError::ConcreteFailure(origin, sub, sup) => {
-                        if sub.is_placeholder() || sup.is_placeholder() {
-                            self.report_placeholder_failure(generic_param_scope, origin, sub, sup)
-                                .emit()
-                        } else {
-                            self.report_concrete_failure(generic_param_scope, origin, sub, sup)
-                                .emit()
-                        }
-                    }
-
-                    RegionResolutionError::GenericBoundFailure(origin, param_ty, sub) => self
-                        .report_generic_bound_failure(
-                            generic_param_scope,
-                            origin.span(),
-                            Some(origin),
-                            param_ty,
-                            sub,
-                        ),
-
-                    RegionResolutionError::SubSupConflict(
-                        _,
-                        var_origin,
-                        sub_origin,
-                        sub_r,
-                        sup_origin,
-                        sup_r,
-                        _,
-                    ) => {
-                        if sub_r.is_placeholder() {
-                            self.report_placeholder_failure(
-                                generic_param_scope,
-                                sub_origin,
-                                sub_r,
-                                sup_r,
-                            )
-                            .emit()
-                        } else if sup_r.is_placeholder() {
-                            self.report_placeholder_failure(
-                                generic_param_scope,
-                                sup_origin,
-                                sub_r,
-                                sup_r,
-                            )
-                            .emit()
-                        } else {
-                            self.report_sub_sup_conflict(
-                                generic_param_scope,
-                                var_origin,
-                                sub_origin,
-                                sub_r,
-                                sup_origin,
-                                sup_r,
-                            )
-                        }
-                    }
-
-                    RegionResolutionError::UpperBoundUniverseConflict(
-                        _,
-                        _,
-                        _,
-                        sup_origin,
-                        sup_r,
-                    ) => {
-                        assert!(sup_r.is_placeholder());
-
-                        // Make a dummy value for the "sub region" --
-                        // this is the initial value of the
-                        // placeholder. In practice, we expect more
-                        // tailored errors that don't really use this
-                        // value.
-                        let sub_r = self.tcx.lifetimes.re_erased;
-
-                        self.report_placeholder_failure(
-                            generic_param_scope,
-                            sup_origin,
-                            sub_r,
-                            sup_r,
-                        )
-                        .emit()
-                    }
-
-                    RegionResolutionError::CannotNormalize(clause, origin) => {
-                        let clause: ty::Clause<'tcx> =
-                            clause.map_bound(ty::ClauseKind::TypeOutlives).upcast(self.tcx);
-                        self.tcx
-                            .dcx()
-                            .struct_span_err(origin.span(), format!("cannot normalize `{clause}`"))
-                            .emit()
-                    }
-                }
-            };
-
-            guar = Some(e)
-        }
-
-        guar.unwrap()
-    }
-
-    // This method goes through all the errors and try to group certain types
-    // of error together, for the purpose of suggesting explicit lifetime
-    // parameters to the user. This is done so that we can have a more
-    // complete view of what lifetimes should be the same.
-    // If the return value is an empty vector, it means that processing
-    // failed (so the return value of this method should not be used).
-    //
-    // The method also attempts to weed out messages that seem like
-    // duplicates that will be unhelpful to the end-user. But
-    // obviously it never weeds out ALL errors.
-    fn process_errors(
-        &self,
-        errors: &[RegionResolutionError<'tcx>],
-    ) -> Vec<RegionResolutionError<'tcx>> {
-        debug!("process_errors()");
-
-        // We want to avoid reporting generic-bound failures if we can
-        // avoid it: these have a very high rate of being unhelpful in
-        // practice. This is because they are basically secondary
-        // checks that test the state of the region graph after the
-        // rest of inference is done, and the other kinds of errors
-        // indicate that the region constraint graph is internally
-        // inconsistent, so these test results are likely to be
-        // meaningless.
-        //
-        // Therefore, we filter them out of the list unless they are
-        // the only thing in the list.
-
-        let is_bound_failure = |e: &RegionResolutionError<'tcx>| match *e {
-            RegionResolutionError::GenericBoundFailure(..) => true,
-            RegionResolutionError::ConcreteFailure(..)
-            | RegionResolutionError::SubSupConflict(..)
-            | RegionResolutionError::UpperBoundUniverseConflict(..)
-            | RegionResolutionError::CannotNormalize(..) => false,
-        };
-
-        let mut errors = if errors.iter().all(|e| is_bound_failure(e)) {
-            errors.to_owned()
-        } else {
-            errors.iter().filter(|&e| !is_bound_failure(e)).cloned().collect()
-        };
-
-        // sort the errors by span, for better error message stability.
-        errors.sort_by_key(|u| match *u {
-            RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(),
-            RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(),
-            RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _, _) => rvo.span(),
-            RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(),
-            RegionResolutionError::CannotNormalize(_, ref sro) => sro.span(),
-        });
-        errors
-    }
-
     /// Adds a note if the types come from similarly named crates
     fn check_and_note_conflicting_crates(&self, err: &mut Diag<'_>, terr: TypeError<'tcx>) {
         use hir::def_id::CrateNum;
@@ -2341,359 +1910,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         ))
     }
 
-    pub fn report_generic_bound_failure(
-        &self,
-        generic_param_scope: LocalDefId,
-        span: Span,
-        origin: Option<SubregionOrigin<'tcx>>,
-        bound_kind: GenericKind<'tcx>,
-        sub: Region<'tcx>,
-    ) -> ErrorGuaranteed {
-        self.construct_generic_bound_failure(generic_param_scope, span, origin, bound_kind, sub)
-            .emit()
-    }
-
-    pub fn construct_generic_bound_failure(
-        &self,
-        generic_param_scope: LocalDefId,
-        span: Span,
-        origin: Option<SubregionOrigin<'tcx>>,
-        bound_kind: GenericKind<'tcx>,
-        sub: Region<'tcx>,
-    ) -> Diag<'a> {
-        if let Some(SubregionOrigin::CompareImplItemObligation {
-            span,
-            impl_item_def_id,
-            trait_item_def_id,
-        }) = origin
-        {
-            return self.infcx.report_extra_impl_obligation(
-                span,
-                impl_item_def_id,
-                trait_item_def_id,
-                &format!("`{bound_kind}: {sub}`"),
-            );
-        }
-
-        let labeled_user_string = match bound_kind {
-            GenericKind::Param(ref p) => format!("the parameter type `{p}`"),
-            GenericKind::Placeholder(ref p) => format!("the placeholder type `{p:?}`"),
-            GenericKind::Alias(ref p) => match p.kind(self.tcx) {
-                ty::Projection | ty::Inherent => {
-                    format!("the associated type `{p}`")
-                }
-                ty::Weak => format!("the type alias `{p}`"),
-                ty::Opaque => format!("the opaque type `{p}`"),
-            },
-        };
-
-        let mut err = self
-            .tcx
-            .dcx()
-            .struct_span_err(span, format!("{labeled_user_string} may not live long enough"));
-        err.code(match sub.kind() {
-            ty::ReEarlyParam(_) | ty::ReLateParam(_) if sub.has_name() => E0309,
-            ty::ReStatic => E0310,
-            _ => E0311,
-        });
-
-        '_explain: {
-            let (description, span) = match sub.kind() {
-                ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::ReStatic => {
-                    msg_span_from_named_region(self.tcx, generic_param_scope, sub, Some(span))
-                }
-                _ => (format!("lifetime `{sub}`"), Some(span)),
-            };
-            let prefix = format!("{labeled_user_string} must be valid for ");
-            label_msg_span(&mut err, &prefix, description, span, "...");
-            if let Some(origin) = origin {
-                self.note_region_origin(&mut err, &origin);
-            }
-        }
-
-        'suggestion: {
-            let msg = "consider adding an explicit lifetime bound";
-
-            if (bound_kind, sub).has_infer_regions()
-                || (bound_kind, sub).has_placeholders()
-                || !bound_kind.is_suggestable(self.tcx, false)
-            {
-                let lt_name = sub.get_name_or_anon().to_string();
-                err.help(format!("{msg} `{bound_kind}: {lt_name}`..."));
-                break 'suggestion;
-            }
-
-            let mut generic_param_scope = generic_param_scope;
-            while self.tcx.def_kind(generic_param_scope) == DefKind::OpaqueTy {
-                generic_param_scope = self.tcx.local_parent(generic_param_scope);
-            }
-
-            // type_param_sugg_span is (span, has_bounds, needs_parentheses)
-            let (type_scope, type_param_sugg_span) = match bound_kind {
-                GenericKind::Param(param) => {
-                    let generics = self.tcx.generics_of(generic_param_scope);
-                    let type_param = generics.type_param(param, self.tcx);
-                    let def_id = type_param.def_id.expect_local();
-                    let scope = self.tcx.local_def_id_to_hir_id(def_id).owner.def_id;
-                    // Get the `hir::Param` to verify whether it already has any bounds.
-                    // We do this to avoid suggesting code that ends up as `T: 'a'b`,
-                    // instead we suggest `T: 'a + 'b` in that case.
-                    let hir_generics = self.tcx.hir().get_generics(scope).unwrap();
-                    let sugg_span = match hir_generics.bounds_span_for_suggestions(def_id) {
-                        Some((span, open_paren_sp)) => Some((span, true, open_paren_sp)),
-                        // If `param` corresponds to `Self`, no usable suggestion span.
-                        None if generics.has_self && param.index == 0 => None,
-                        None => {
-                            let span = if let Some(param) =
-                                hir_generics.params.iter().find(|param| param.def_id == def_id)
-                                && let ParamName::Plain(ident) = param.name
-                            {
-                                ident.span.shrink_to_hi()
-                            } else {
-                                let span = self.tcx.def_span(def_id);
-                                span.shrink_to_hi()
-                            };
-                            Some((span, false, None))
-                        }
-                    };
-                    (scope, sugg_span)
-                }
-                _ => (generic_param_scope, None),
-            };
-            let suggestion_scope = {
-                let lifetime_scope = match sub.kind() {
-                    ty::ReStatic => hir::def_id::CRATE_DEF_ID,
-                    _ => match self.tcx.is_suitable_region(generic_param_scope, sub) {
-                        Some(info) => info.def_id,
-                        None => generic_param_scope,
-                    },
-                };
-                match self.tcx.is_descendant_of(type_scope.into(), lifetime_scope.into()) {
-                    true => type_scope,
-                    false => lifetime_scope,
-                }
-            };
-
-            let mut suggs = vec![];
-            let lt_name = self.suggest_name_region(generic_param_scope, sub, &mut suggs);
-
-            if let Some((sp, has_lifetimes, open_paren_sp)) = type_param_sugg_span
-                && suggestion_scope == type_scope
-            {
-                let suggestion =
-                    if has_lifetimes { format!(" + {lt_name}") } else { format!(": {lt_name}") };
-
-                if let Some(open_paren_sp) = open_paren_sp {
-                    suggs.push((open_paren_sp, "(".to_string()));
-                    suggs.push((sp, format!("){suggestion}")));
-                } else {
-                    suggs.push((sp, suggestion))
-                }
-            } else if let GenericKind::Alias(ref p) = bound_kind
-                && let ty::Projection = p.kind(self.tcx)
-                && let DefKind::AssocTy = self.tcx.def_kind(p.def_id)
-                && let Some(ty::ImplTraitInTraitData::Trait { .. }) =
-                    self.tcx.opt_rpitit_info(p.def_id)
-            {
-                // The lifetime found in the `impl` is longer than the one on the RPITIT.
-                // Do not suggest `<Type as Trait>::{opaque}: 'static`.
-            } else if let Some(generics) = self.tcx.hir().get_generics(suggestion_scope) {
-                let pred = format!("{bound_kind}: {lt_name}");
-                let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred);
-                suggs.push((generics.tail_span_for_predicate_suggestion(), suggestion))
-            } else {
-                let consider = format!("{msg} `{bound_kind}: {sub}`...");
-                err.help(consider);
-            }
-
-            if !suggs.is_empty() {
-                err.multipart_suggestion_verbose(
-                    msg,
-                    suggs,
-                    Applicability::MaybeIncorrect, // Issue #41966
-                );
-            }
-        }
-
-        err
-    }
-
-    pub fn suggest_name_region(
-        &self,
-        generic_param_scope: LocalDefId,
-        lifetime: Region<'tcx>,
-        add_lt_suggs: &mut Vec<(Span, String)>,
-    ) -> String {
-        struct LifetimeReplaceVisitor<'tcx, 'a> {
-            tcx: TyCtxt<'tcx>,
-            needle: hir::LifetimeName,
-            new_lt: &'a str,
-            add_lt_suggs: &'a mut Vec<(Span, String)>,
-        }
-
-        impl<'hir, 'tcx> hir::intravisit::Visitor<'hir> for LifetimeReplaceVisitor<'tcx, '_> {
-            fn visit_lifetime(&mut self, lt: &'hir hir::Lifetime) {
-                if lt.res == self.needle {
-                    let (pos, span) = lt.suggestion_position();
-                    let new_lt = &self.new_lt;
-                    let sugg = match pos {
-                        hir::LifetimeSuggestionPosition::Normal => format!("{new_lt}"),
-                        hir::LifetimeSuggestionPosition::Ampersand => format!("{new_lt} "),
-                        hir::LifetimeSuggestionPosition::ElidedPath => format!("<{new_lt}>"),
-                        hir::LifetimeSuggestionPosition::ElidedPathArgument => {
-                            format!("{new_lt}, ")
-                        }
-                        hir::LifetimeSuggestionPosition::ObjectDefault => format!("+ {new_lt}"),
-                    };
-                    self.add_lt_suggs.push((span, sugg));
-                }
-            }
-
-            fn visit_ty(&mut self, ty: &'hir hir::Ty<'hir>) {
-                let hir::TyKind::OpaqueDef(item_id, _, _) = ty.kind else {
-                    return hir::intravisit::walk_ty(self, ty);
-                };
-                let opaque_ty = self.tcx.hir().item(item_id).expect_opaque_ty();
-                if let Some(&(_, b)) =
-                    opaque_ty.lifetime_mapping.iter().find(|&(a, _)| a.res == self.needle)
-                {
-                    let prev_needle =
-                        std::mem::replace(&mut self.needle, hir::LifetimeName::Param(b));
-                    for bound in opaque_ty.bounds {
-                        self.visit_param_bound(bound);
-                    }
-                    self.needle = prev_needle;
-                }
-            }
-        }
-
-        let (lifetime_def_id, lifetime_scope) =
-            match self.tcx.is_suitable_region(generic_param_scope, lifetime) {
-                Some(info) if !lifetime.has_name() => {
-                    (info.bound_region.get_id().unwrap().expect_local(), info.def_id)
-                }
-                _ => return lifetime.get_name_or_anon().to_string(),
-            };
-
-        let new_lt = {
-            let generics = self.tcx.generics_of(lifetime_scope);
-            let mut used_names =
-                iter::successors(Some(generics), |g| g.parent.map(|p| self.tcx.generics_of(p)))
-                    .flat_map(|g| &g.own_params)
-                    .filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime))
-                    .map(|p| p.name)
-                    .collect::<Vec<_>>();
-            let hir_id = self.tcx.local_def_id_to_hir_id(lifetime_scope);
-            // consider late-bound lifetimes ...
-            used_names.extend(self.tcx.late_bound_vars(hir_id).into_iter().filter_map(
-                |p| match p {
-                    ty::BoundVariableKind::Region(lt) => lt.get_name(),
-                    _ => None,
-                },
-            ));
-            (b'a'..=b'z')
-                .map(|c| format!("'{}", c as char))
-                .find(|candidate| !used_names.iter().any(|e| e.as_str() == candidate))
-                .unwrap_or("'lt".to_string())
-        };
-
-        let mut visitor = LifetimeReplaceVisitor {
-            tcx: self.tcx,
-            needle: hir::LifetimeName::Param(lifetime_def_id),
-            add_lt_suggs,
-            new_lt: &new_lt,
-        };
-        match self.tcx.expect_hir_owner_node(lifetime_scope) {
-            hir::OwnerNode::Item(i) => visitor.visit_item(i),
-            hir::OwnerNode::ForeignItem(i) => visitor.visit_foreign_item(i),
-            hir::OwnerNode::ImplItem(i) => visitor.visit_impl_item(i),
-            hir::OwnerNode::TraitItem(i) => visitor.visit_trait_item(i),
-            hir::OwnerNode::Crate(_) => bug!("OwnerNode::Crate doesn't not have generics"),
-            hir::OwnerNode::Synthetic => unreachable!(),
-        }
-
-        let ast_generics = self.tcx.hir().get_generics(lifetime_scope).unwrap();
-        let sugg = ast_generics
-            .span_for_lifetime_suggestion()
-            .map(|span| (span, format!("{new_lt}, ")))
-            .unwrap_or_else(|| (ast_generics.span, format!("<{new_lt}>")));
-        add_lt_suggs.push(sugg);
-
-        new_lt
-    }
-
-    fn report_sub_sup_conflict(
-        &self,
-        generic_param_scope: LocalDefId,
-        var_origin: RegionVariableOrigin,
-        sub_origin: SubregionOrigin<'tcx>,
-        sub_region: Region<'tcx>,
-        sup_origin: SubregionOrigin<'tcx>,
-        sup_region: Region<'tcx>,
-    ) -> ErrorGuaranteed {
-        let mut err = self.report_inference_failure(var_origin);
-
-        note_and_explain_region(
-            self.tcx,
-            &mut err,
-            generic_param_scope,
-            "first, the lifetime cannot outlive ",
-            sup_region,
-            "...",
-            None,
-        );
-
-        debug!("report_sub_sup_conflict: var_origin={:?}", var_origin);
-        debug!("report_sub_sup_conflict: sub_region={:?}", sub_region);
-        debug!("report_sub_sup_conflict: sub_origin={:?}", sub_origin);
-        debug!("report_sub_sup_conflict: sup_region={:?}", sup_region);
-        debug!("report_sub_sup_conflict: sup_origin={:?}", sup_origin);
-
-        if let infer::Subtype(ref sup_trace) = sup_origin
-            && let infer::Subtype(ref sub_trace) = sub_origin
-            && let Some((sup_expected, sup_found, _)) = self.values_str(sup_trace.values)
-            && let Some((sub_expected, sub_found, _)) = self.values_str(sub_trace.values)
-            && sub_expected == sup_expected
-            && sub_found == sup_found
-        {
-            note_and_explain_region(
-                self.tcx,
-                &mut err,
-                generic_param_scope,
-                "...but the lifetime must also be valid for ",
-                sub_region,
-                "...",
-                None,
-            );
-            err.span_note(
-                sup_trace.cause.span,
-                format!("...so that the {}", sup_trace.cause.as_requirement_str()),
-            );
-
-            err.note_expected_found(&"", sup_expected, &"", sup_found);
-            return if sub_region.is_error() | sup_region.is_error() {
-                err.delay_as_bug()
-            } else {
-                err.emit()
-            };
-        }
-
-        self.note_region_origin(&mut err, &sup_origin);
-
-        note_and_explain_region(
-            self.tcx,
-            &mut err,
-            generic_param_scope,
-            "but, the lifetime must be valid for ",
-            sub_region,
-            "...",
-            None,
-        );
-
-        self.note_region_origin(&mut err, &sub_origin);
-        if sub_region.is_error() | sup_region.is_error() { err.delay_as_bug() } else { err.emit() }
-    }
-
     /// Determine whether an error associated with the given span and definition
     /// should be treated as being caused by the implicit `From` conversion
     /// within `?` desugaring.
@@ -2792,55 +2008,6 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for SameTypeModuloInfer<'_, 'tcx> {
     }
 }
 
-impl<'tcx> InferCtxt<'tcx> {
-    fn report_inference_failure(&self, var_origin: RegionVariableOrigin) -> Diag<'_> {
-        let br_string = |br: ty::BoundRegionKind| {
-            let mut s = match br {
-                ty::BrNamed(_, name) => name.to_string(),
-                _ => String::new(),
-            };
-            if !s.is_empty() {
-                s.push(' ');
-            }
-            s
-        };
-        let var_description = match var_origin {
-            infer::MiscVariable(_) => String::new(),
-            infer::PatternRegion(_) => " for pattern".to_string(),
-            infer::AddrOfRegion(_) => " for borrow expression".to_string(),
-            infer::Autoref(_) => " for autoref".to_string(),
-            infer::Coercion(_) => " for automatic coercion".to_string(),
-            infer::BoundRegion(_, br, infer::FnCall) => {
-                format!(" for lifetime parameter {}in function call", br_string(br))
-            }
-            infer::BoundRegion(_, br, infer::HigherRankedType) => {
-                format!(" for lifetime parameter {}in generic type", br_string(br))
-            }
-            infer::BoundRegion(_, br, infer::AssocTypeProjection(def_id)) => format!(
-                " for lifetime parameter {}in trait containing associated type `{}`",
-                br_string(br),
-                self.tcx.associated_item(def_id).name
-            ),
-            infer::RegionParameterDefinition(_, name) => {
-                format!(" for lifetime parameter `{name}`")
-            }
-            infer::UpvarRegion(ref upvar_id, _) => {
-                let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
-                format!(" for capture of `{var_name}` by closure")
-            }
-            infer::Nll(..) => bug!("NLL variable found in lexical phase"),
-        };
-
-        struct_span_code_err!(
-            self.dcx(),
-            var_origin.span(),
-            E0495,
-            "cannot infer an appropriate lifetime{} due to conflicting requirements",
-            var_description
-        )
-    }
-}
-
 pub enum FailureCode {
     Error0317,
     Error0580,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
deleted file mode 100644
index d1fc9c9f140..00000000000
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ /dev/null
@@ -1,421 +0,0 @@
-use crate::errors::{
-    note_and_explain, FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent,
-    RefLongerThanData, RegionOriginNote, WhereClauseSuggestions,
-};
-use crate::fluent_generated as fluent;
-use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt};
-use crate::infer::{self, SubregionOrigin};
-use rustc_errors::{Diag, Subdiagnostic};
-use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::traits::ObligationCauseCode;
-use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::{self, IsSuggestable, Region, Ty};
-use rustc_span::symbol::kw;
-
-use super::ObligationCauseAsDiagArg;
-
-impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
-    pub(super) fn note_region_origin(&self, err: &mut Diag<'_>, origin: &SubregionOrigin<'tcx>) {
-        match *origin {
-            infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
-                span: trace.cause.span,
-                requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
-                expected_found: self.values_str(trace.values).map(|(e, f, _)| (e, f)),
-            }
-            .add_to_diag(err),
-            infer::Reborrow(span) => {
-                RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diag(err)
-            }
-            infer::RelateObjectBound(span) => {
-                RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound }
-                    .add_to_diag(err);
-            }
-            infer::ReferenceOutlivesReferent(ty, span) => {
-                RegionOriginNote::WithName {
-                    span,
-                    msg: fluent::infer_reference_outlives_referent,
-                    name: &self.ty_to_string(ty),
-                    continues: false,
-                }
-                .add_to_diag(err);
-            }
-            infer::RelateParamBound(span, ty, opt_span) => {
-                RegionOriginNote::WithName {
-                    span,
-                    msg: fluent::infer_relate_param_bound,
-                    name: &self.ty_to_string(ty),
-                    continues: opt_span.is_some(),
-                }
-                .add_to_diag(err);
-                if let Some(span) = opt_span {
-                    RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 }
-                        .add_to_diag(err);
-                }
-            }
-            infer::RelateRegionParamBound(span) => {
-                RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound }
-                    .add_to_diag(err);
-            }
-            infer::CompareImplItemObligation { span, .. } => {
-                RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation }
-                    .add_to_diag(err);
-            }
-            infer::CheckAssociatedTypeBounds { ref parent, .. } => {
-                self.note_region_origin(err, parent);
-            }
-            infer::AscribeUserTypeProvePredicate(span) => {
-                RegionOriginNote::Plain {
-                    span,
-                    msg: fluent::infer_ascribe_user_type_prove_predicate,
-                }
-                .add_to_diag(err);
-            }
-        }
-    }
-
-    pub(super) fn report_concrete_failure(
-        &self,
-        generic_param_scope: LocalDefId,
-        origin: SubregionOrigin<'tcx>,
-        sub: Region<'tcx>,
-        sup: Region<'tcx>,
-    ) -> Diag<'a> {
-        let mut err = match origin {
-            infer::Subtype(box trace) => {
-                let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
-                let mut err = self.report_and_explain_type_error(trace, terr);
-                match (*sub, *sup) {
-                    (ty::RePlaceholder(_), ty::RePlaceholder(_)) => {}
-                    (ty::RePlaceholder(_), _) => {
-                        note_and_explain_region(
-                            self.tcx,
-                            &mut err,
-                            generic_param_scope,
-                            "",
-                            sup,
-                            " doesn't meet the lifetime requirements",
-                            None,
-                        );
-                    }
-                    (_, ty::RePlaceholder(_)) => {
-                        note_and_explain_region(
-                            self.tcx,
-                            &mut err,
-                            generic_param_scope,
-                            "the required lifetime does not necessarily outlive ",
-                            sub,
-                            "",
-                            None,
-                        );
-                    }
-                    _ => {
-                        note_and_explain_region(
-                            self.tcx,
-                            &mut err,
-                            generic_param_scope,
-                            "",
-                            sup,
-                            "...",
-                            None,
-                        );
-                        note_and_explain_region(
-                            self.tcx,
-                            &mut err,
-                            generic_param_scope,
-                            "...does not necessarily outlive ",
-                            sub,
-                            "",
-                            None,
-                        );
-                    }
-                }
-                err
-            }
-            infer::Reborrow(span) => {
-                let reference_valid = note_and_explain::RegionExplanation::new(
-                    self.tcx,
-                    generic_param_scope,
-                    sub,
-                    None,
-                    note_and_explain::PrefixKind::RefValidFor,
-                    note_and_explain::SuffixKind::Continues,
-                );
-                let content_valid = note_and_explain::RegionExplanation::new(
-                    self.tcx,
-                    generic_param_scope,
-                    sup,
-                    None,
-                    note_and_explain::PrefixKind::ContentValidFor,
-                    note_and_explain::SuffixKind::Empty,
-                );
-                self.dcx().create_err(OutlivesContent {
-                    span,
-                    notes: reference_valid.into_iter().chain(content_valid).collect(),
-                })
-            }
-            infer::RelateObjectBound(span) => {
-                let object_valid = note_and_explain::RegionExplanation::new(
-                    self.tcx,
-                    generic_param_scope,
-                    sub,
-                    None,
-                    note_and_explain::PrefixKind::TypeObjValidFor,
-                    note_and_explain::SuffixKind::Empty,
-                );
-                let pointer_valid = note_and_explain::RegionExplanation::new(
-                    self.tcx,
-                    generic_param_scope,
-                    sup,
-                    None,
-                    note_and_explain::PrefixKind::SourcePointerValidFor,
-                    note_and_explain::SuffixKind::Empty,
-                );
-                self.dcx().create_err(OutlivesBound {
-                    span,
-                    notes: object_valid.into_iter().chain(pointer_valid).collect(),
-                })
-            }
-            infer::RelateParamBound(span, ty, opt_span) => {
-                let prefix = match *sub {
-                    ty::ReStatic => note_and_explain::PrefixKind::TypeSatisfy,
-                    _ => note_and_explain::PrefixKind::TypeOutlive,
-                };
-                let suffix = if opt_span.is_some() {
-                    note_and_explain::SuffixKind::ReqByBinding
-                } else {
-                    note_and_explain::SuffixKind::Empty
-                };
-                let note = note_and_explain::RegionExplanation::new(
-                    self.tcx,
-                    generic_param_scope,
-                    sub,
-                    opt_span,
-                    prefix,
-                    suffix,
-                );
-                self.dcx().create_err(FulfillReqLifetime {
-                    span,
-                    ty: self.resolve_vars_if_possible(ty),
-                    note,
-                })
-            }
-            infer::RelateRegionParamBound(span) => {
-                let param_instantiated = note_and_explain::RegionExplanation::new(
-                    self.tcx,
-                    generic_param_scope,
-                    sup,
-                    None,
-                    note_and_explain::PrefixKind::LfParamInstantiatedWith,
-                    note_and_explain::SuffixKind::Empty,
-                );
-                let param_must_outlive = note_and_explain::RegionExplanation::new(
-                    self.tcx,
-                    generic_param_scope,
-                    sub,
-                    None,
-                    note_and_explain::PrefixKind::LfParamMustOutlive,
-                    note_and_explain::SuffixKind::Empty,
-                );
-                self.dcx().create_err(LfBoundNotSatisfied {
-                    span,
-                    notes: param_instantiated.into_iter().chain(param_must_outlive).collect(),
-                })
-            }
-            infer::ReferenceOutlivesReferent(ty, span) => {
-                let pointer_valid = note_and_explain::RegionExplanation::new(
-                    self.tcx,
-                    generic_param_scope,
-                    sub,
-                    None,
-                    note_and_explain::PrefixKind::PointerValidFor,
-                    note_and_explain::SuffixKind::Empty,
-                );
-                let data_valid = note_and_explain::RegionExplanation::new(
-                    self.tcx,
-                    generic_param_scope,
-                    sup,
-                    None,
-                    note_and_explain::PrefixKind::DataValidFor,
-                    note_and_explain::SuffixKind::Empty,
-                );
-                self.dcx().create_err(RefLongerThanData {
-                    span,
-                    ty: self.resolve_vars_if_possible(ty),
-                    notes: pointer_valid.into_iter().chain(data_valid).collect(),
-                })
-            }
-            infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => {
-                let mut err = self.infcx.report_extra_impl_obligation(
-                    span,
-                    impl_item_def_id,
-                    trait_item_def_id,
-                    &format!("`{sup}: {sub}`"),
-                );
-                // We should only suggest rewriting the `where` clause if the predicate is within that `where` clause
-                if let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id)
-                    && generics.where_clause_span.contains(span)
-                {
-                    self.suggest_copy_trait_method_bounds(
-                        trait_item_def_id,
-                        impl_item_def_id,
-                        &mut err,
-                    );
-                }
-                err
-            }
-            infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
-                let mut err = self.report_concrete_failure(generic_param_scope, *parent, sub, sup);
-
-                // Don't mention the item name if it's an RPITIT, since that'll just confuse
-                // folks.
-                if !self.tcx.is_impl_trait_in_trait(impl_item_def_id.to_def_id()) {
-                    let trait_item_span = self.tcx.def_span(trait_item_def_id);
-                    let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
-                    err.span_label(
-                        trait_item_span,
-                        format!("definition of `{item_name}` from trait"),
-                    );
-                }
-
-                self.suggest_copy_trait_method_bounds(
-                    trait_item_def_id,
-                    impl_item_def_id,
-                    &mut err,
-                );
-                err
-            }
-            infer::AscribeUserTypeProvePredicate(span) => {
-                let instantiated = note_and_explain::RegionExplanation::new(
-                    self.tcx,
-                    generic_param_scope,
-                    sup,
-                    None,
-                    note_and_explain::PrefixKind::LfInstantiatedWith,
-                    note_and_explain::SuffixKind::Empty,
-                );
-                let must_outlive = note_and_explain::RegionExplanation::new(
-                    self.tcx,
-                    generic_param_scope,
-                    sub,
-                    None,
-                    note_and_explain::PrefixKind::LfMustOutlive,
-                    note_and_explain::SuffixKind::Empty,
-                );
-                self.dcx().create_err(LfBoundNotSatisfied {
-                    span,
-                    notes: instantiated.into_iter().chain(must_outlive).collect(),
-                })
-            }
-        };
-        if sub.is_error() || sup.is_error() {
-            err.downgrade_to_delayed_bug();
-        }
-        err
-    }
-
-    pub fn suggest_copy_trait_method_bounds(
-        &self,
-        trait_item_def_id: DefId,
-        impl_item_def_id: LocalDefId,
-        err: &mut Diag<'_>,
-    ) {
-        // FIXME(compiler-errors): Right now this is only being used for region
-        // predicate mismatches. Ideally, we'd use it for *all* predicate mismatches,
-        // but right now it's not really very smart when it comes to implicit `Sized`
-        // predicates and bounds on the trait itself.
-
-        let Some(impl_def_id) = self.tcx.associated_item(impl_item_def_id).impl_container(self.tcx)
-        else {
-            return;
-        };
-        let Some(trait_ref) = self.tcx.impl_trait_ref(impl_def_id) else {
-            return;
-        };
-        let trait_args = trait_ref
-            .instantiate_identity()
-            // Replace the explicit self type with `Self` for better suggestion rendering
-            .with_self_ty(self.tcx, Ty::new_param(self.tcx, 0, kw::SelfUpper))
-            .args;
-        let trait_item_args = ty::GenericArgs::identity_for_item(self.tcx, impl_item_def_id)
-            .rebase_onto(self.tcx, impl_def_id, trait_args);
-
-        let Ok(trait_predicates) =
-            self.tcx
-                .explicit_predicates_of(trait_item_def_id)
-                .instantiate_own(self.tcx, trait_item_args)
-                .map(|(pred, _)| {
-                    if pred.is_suggestable(self.tcx, false) {
-                        Ok(pred.to_string())
-                    } else {
-                        Err(())
-                    }
-                })
-                .collect::<Result<Vec<_>, ()>>()
-        else {
-            return;
-        };
-
-        let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) else {
-            return;
-        };
-
-        let suggestion = if trait_predicates.is_empty() {
-            WhereClauseSuggestions::Remove { span: generics.where_clause_span }
-        } else {
-            let space = if generics.where_clause_span.is_empty() { " " } else { "" };
-            WhereClauseSuggestions::CopyPredicates {
-                span: generics.where_clause_span,
-                space,
-                trait_predicates: trait_predicates.join(", "),
-            }
-        };
-        err.subdiagnostic(suggestion);
-    }
-
-    pub(super) fn report_placeholder_failure(
-        &self,
-        generic_param_scope: LocalDefId,
-        placeholder_origin: SubregionOrigin<'tcx>,
-        sub: Region<'tcx>,
-        sup: Region<'tcx>,
-    ) -> Diag<'a> {
-        // I can't think how to do better than this right now. -nikomatsakis
-        debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure");
-        match placeholder_origin {
-            infer::Subtype(box ref trace)
-                if matches!(
-                    &trace.cause.code().peel_derives(),
-                    ObligationCauseCode::WhereClause(..)
-                        | ObligationCauseCode::WhereClauseInExpr(..)
-                ) =>
-            {
-                // Hack to get around the borrow checker because trace.cause has an `Rc`.
-                if let ObligationCauseCode::WhereClause(_, span)
-                | ObligationCauseCode::WhereClauseInExpr(_, span, ..) =
-                    &trace.cause.code().peel_derives()
-                    && !span.is_dummy()
-                {
-                    let span = *span;
-                    self.report_concrete_failure(generic_param_scope, placeholder_origin, sub, sup)
-                        .with_span_note(span, "the lifetime requirement is introduced here")
-                } else {
-                    unreachable!(
-                        "control flow ensures we have a `BindingObligation` or `WhereClauseInExpr` here..."
-                    )
-                }
-            }
-            infer::Subtype(box trace) => {
-                let terr = TypeError::RegionsPlaceholderMismatch;
-                return self.report_and_explain_type_error(trace, terr);
-            }
-            _ => {
-                return self.report_concrete_failure(
-                    generic_param_scope,
-                    placeholder_origin,
-                    sub,
-                    sup,
-                );
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/region.rs b/compiler/rustc_infer/src/infer/error_reporting/region.rs
new file mode 100644
index 00000000000..5a465f46e47
--- /dev/null
+++ b/compiler/rustc_infer/src/infer/error_reporting/region.rs
@@ -0,0 +1,1259 @@
+use std::iter;
+
+use rustc_errors::{
+    struct_span_code_err, Applicability, Diag, Subdiagnostic, E0309, E0310, E0311, E0495,
+};
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::{self as hir, ParamName};
+use rustc_middle::bug;
+use rustc_middle::traits::ObligationCauseCode;
+use rustc_middle::ty::error::TypeError;
+use rustc_middle::ty::{self, IsSuggestable, Region, Ty, TyCtxt, TypeVisitableExt as _};
+use rustc_span::symbol::kw;
+use rustc_span::{ErrorGuaranteed, Span};
+use rustc_type_ir::Upcast as _;
+
+use super::nice_region_error::find_anon_type;
+use super::{nice_region_error, ObligationCauseAsDiagArg};
+use crate::errors::{
+    self, note_and_explain, FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound,
+    OutlivesContent, RefLongerThanData, RegionOriginNote, WhereClauseSuggestions,
+};
+use crate::fluent_generated as fluent;
+use crate::infer::error_reporting::{ObligationCauseExt as _, TypeErrCtxt};
+use crate::infer::region_constraints::GenericKind;
+use crate::infer::{self, InferCtxt, RegionResolutionError, RegionVariableOrigin, SubregionOrigin};
+
+impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
+    pub fn report_region_errors(
+        &self,
+        generic_param_scope: LocalDefId,
+        errors: &[RegionResolutionError<'tcx>],
+    ) -> ErrorGuaranteed {
+        assert!(!errors.is_empty());
+
+        if let Some(guaranteed) = self.infcx.tainted_by_errors() {
+            return guaranteed;
+        }
+
+        debug!("report_region_errors(): {} errors to start", errors.len());
+
+        // try to pre-process the errors, which will group some of them
+        // together into a `ProcessedErrors` group:
+        let errors = self.process_errors(errors);
+
+        debug!("report_region_errors: {} errors after preprocessing", errors.len());
+
+        let mut guar = None;
+        for error in errors {
+            debug!("report_region_errors: error = {:?}", error);
+
+            let e = if let Some(guar) =
+                self.try_report_nice_region_error(generic_param_scope, &error)
+            {
+                guar
+            } else {
+                match error.clone() {
+                    // These errors could indicate all manner of different
+                    // problems with many different solutions. Rather
+                    // than generate a "one size fits all" error, what we
+                    // attempt to do is go through a number of specific
+                    // scenarios and try to find the best way to present
+                    // the error. If all of these fails, we fall back to a rather
+                    // general bit of code that displays the error information
+                    RegionResolutionError::ConcreteFailure(origin, sub, sup) => {
+                        if sub.is_placeholder() || sup.is_placeholder() {
+                            self.report_placeholder_failure(generic_param_scope, origin, sub, sup)
+                                .emit()
+                        } else {
+                            self.report_concrete_failure(generic_param_scope, origin, sub, sup)
+                                .emit()
+                        }
+                    }
+
+                    RegionResolutionError::GenericBoundFailure(origin, param_ty, sub) => self
+                        .report_generic_bound_failure(
+                            generic_param_scope,
+                            origin.span(),
+                            Some(origin),
+                            param_ty,
+                            sub,
+                        ),
+
+                    RegionResolutionError::SubSupConflict(
+                        _,
+                        var_origin,
+                        sub_origin,
+                        sub_r,
+                        sup_origin,
+                        sup_r,
+                        _,
+                    ) => {
+                        if sub_r.is_placeholder() {
+                            self.report_placeholder_failure(
+                                generic_param_scope,
+                                sub_origin,
+                                sub_r,
+                                sup_r,
+                            )
+                            .emit()
+                        } else if sup_r.is_placeholder() {
+                            self.report_placeholder_failure(
+                                generic_param_scope,
+                                sup_origin,
+                                sub_r,
+                                sup_r,
+                            )
+                            .emit()
+                        } else {
+                            self.report_sub_sup_conflict(
+                                generic_param_scope,
+                                var_origin,
+                                sub_origin,
+                                sub_r,
+                                sup_origin,
+                                sup_r,
+                            )
+                        }
+                    }
+
+                    RegionResolutionError::UpperBoundUniverseConflict(
+                        _,
+                        _,
+                        _,
+                        sup_origin,
+                        sup_r,
+                    ) => {
+                        assert!(sup_r.is_placeholder());
+
+                        // Make a dummy value for the "sub region" --
+                        // this is the initial value of the
+                        // placeholder. In practice, we expect more
+                        // tailored errors that don't really use this
+                        // value.
+                        let sub_r = self.tcx.lifetimes.re_erased;
+
+                        self.report_placeholder_failure(
+                            generic_param_scope,
+                            sup_origin,
+                            sub_r,
+                            sup_r,
+                        )
+                        .emit()
+                    }
+
+                    RegionResolutionError::CannotNormalize(clause, origin) => {
+                        let clause: ty::Clause<'tcx> =
+                            clause.map_bound(ty::ClauseKind::TypeOutlives).upcast(self.tcx);
+                        self.tcx
+                            .dcx()
+                            .struct_span_err(origin.span(), format!("cannot normalize `{clause}`"))
+                            .emit()
+                    }
+                }
+            };
+
+            guar = Some(e)
+        }
+
+        guar.unwrap()
+    }
+
+    // This method goes through all the errors and try to group certain types
+    // of error together, for the purpose of suggesting explicit lifetime
+    // parameters to the user. This is done so that we can have a more
+    // complete view of what lifetimes should be the same.
+    // If the return value is an empty vector, it means that processing
+    // failed (so the return value of this method should not be used).
+    //
+    // The method also attempts to weed out messages that seem like
+    // duplicates that will be unhelpful to the end-user. But
+    // obviously it never weeds out ALL errors.
+    fn process_errors(
+        &self,
+        errors: &[RegionResolutionError<'tcx>],
+    ) -> Vec<RegionResolutionError<'tcx>> {
+        debug!("process_errors()");
+
+        // We want to avoid reporting generic-bound failures if we can
+        // avoid it: these have a very high rate of being unhelpful in
+        // practice. This is because they are basically secondary
+        // checks that test the state of the region graph after the
+        // rest of inference is done, and the other kinds of errors
+        // indicate that the region constraint graph is internally
+        // inconsistent, so these test results are likely to be
+        // meaningless.
+        //
+        // Therefore, we filter them out of the list unless they are
+        // the only thing in the list.
+
+        let is_bound_failure = |e: &RegionResolutionError<'tcx>| match *e {
+            RegionResolutionError::GenericBoundFailure(..) => true,
+            RegionResolutionError::ConcreteFailure(..)
+            | RegionResolutionError::SubSupConflict(..)
+            | RegionResolutionError::UpperBoundUniverseConflict(..)
+            | RegionResolutionError::CannotNormalize(..) => false,
+        };
+
+        let mut errors = if errors.iter().all(|e| is_bound_failure(e)) {
+            errors.to_owned()
+        } else {
+            errors.iter().filter(|&e| !is_bound_failure(e)).cloned().collect()
+        };
+
+        // sort the errors by span, for better error message stability.
+        errors.sort_by_key(|u| match *u {
+            RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(),
+            RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(),
+            RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _, _) => rvo.span(),
+            RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(),
+            RegionResolutionError::CannotNormalize(_, ref sro) => sro.span(),
+        });
+        errors
+    }
+
+    pub(super) fn note_region_origin(&self, err: &mut Diag<'_>, origin: &SubregionOrigin<'tcx>) {
+        match *origin {
+            infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
+                span: trace.cause.span,
+                requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
+                expected_found: self.values_str(trace.values).map(|(e, f, _)| (e, f)),
+            }
+            .add_to_diag(err),
+            infer::Reborrow(span) => {
+                RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diag(err)
+            }
+            infer::RelateObjectBound(span) => {
+                RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound }
+                    .add_to_diag(err);
+            }
+            infer::ReferenceOutlivesReferent(ty, span) => {
+                RegionOriginNote::WithName {
+                    span,
+                    msg: fluent::infer_reference_outlives_referent,
+                    name: &self.ty_to_string(ty),
+                    continues: false,
+                }
+                .add_to_diag(err);
+            }
+            infer::RelateParamBound(span, ty, opt_span) => {
+                RegionOriginNote::WithName {
+                    span,
+                    msg: fluent::infer_relate_param_bound,
+                    name: &self.ty_to_string(ty),
+                    continues: opt_span.is_some(),
+                }
+                .add_to_diag(err);
+                if let Some(span) = opt_span {
+                    RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 }
+                        .add_to_diag(err);
+                }
+            }
+            infer::RelateRegionParamBound(span) => {
+                RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound }
+                    .add_to_diag(err);
+            }
+            infer::CompareImplItemObligation { span, .. } => {
+                RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation }
+                    .add_to_diag(err);
+            }
+            infer::CheckAssociatedTypeBounds { ref parent, .. } => {
+                self.note_region_origin(err, parent);
+            }
+            infer::AscribeUserTypeProvePredicate(span) => {
+                RegionOriginNote::Plain {
+                    span,
+                    msg: fluent::infer_ascribe_user_type_prove_predicate,
+                }
+                .add_to_diag(err);
+            }
+        }
+    }
+
+    pub(super) fn report_concrete_failure(
+        &self,
+        generic_param_scope: LocalDefId,
+        origin: SubregionOrigin<'tcx>,
+        sub: Region<'tcx>,
+        sup: Region<'tcx>,
+    ) -> Diag<'a> {
+        let mut err = match origin {
+            infer::Subtype(box trace) => {
+                let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
+                let mut err = self.report_and_explain_type_error(trace, terr);
+                match (*sub, *sup) {
+                    (ty::RePlaceholder(_), ty::RePlaceholder(_)) => {}
+                    (ty::RePlaceholder(_), _) => {
+                        note_and_explain_region(
+                            self.tcx,
+                            &mut err,
+                            generic_param_scope,
+                            "",
+                            sup,
+                            " doesn't meet the lifetime requirements",
+                            None,
+                        );
+                    }
+                    (_, ty::RePlaceholder(_)) => {
+                        note_and_explain_region(
+                            self.tcx,
+                            &mut err,
+                            generic_param_scope,
+                            "the required lifetime does not necessarily outlive ",
+                            sub,
+                            "",
+                            None,
+                        );
+                    }
+                    _ => {
+                        note_and_explain_region(
+                            self.tcx,
+                            &mut err,
+                            generic_param_scope,
+                            "",
+                            sup,
+                            "...",
+                            None,
+                        );
+                        note_and_explain_region(
+                            self.tcx,
+                            &mut err,
+                            generic_param_scope,
+                            "...does not necessarily outlive ",
+                            sub,
+                            "",
+                            None,
+                        );
+                    }
+                }
+                err
+            }
+            infer::Reborrow(span) => {
+                let reference_valid = note_and_explain::RegionExplanation::new(
+                    self.tcx,
+                    generic_param_scope,
+                    sub,
+                    None,
+                    note_and_explain::PrefixKind::RefValidFor,
+                    note_and_explain::SuffixKind::Continues,
+                );
+                let content_valid = note_and_explain::RegionExplanation::new(
+                    self.tcx,
+                    generic_param_scope,
+                    sup,
+                    None,
+                    note_and_explain::PrefixKind::ContentValidFor,
+                    note_and_explain::SuffixKind::Empty,
+                );
+                self.dcx().create_err(OutlivesContent {
+                    span,
+                    notes: reference_valid.into_iter().chain(content_valid).collect(),
+                })
+            }
+            infer::RelateObjectBound(span) => {
+                let object_valid = note_and_explain::RegionExplanation::new(
+                    self.tcx,
+                    generic_param_scope,
+                    sub,
+                    None,
+                    note_and_explain::PrefixKind::TypeObjValidFor,
+                    note_and_explain::SuffixKind::Empty,
+                );
+                let pointer_valid = note_and_explain::RegionExplanation::new(
+                    self.tcx,
+                    generic_param_scope,
+                    sup,
+                    None,
+                    note_and_explain::PrefixKind::SourcePointerValidFor,
+                    note_and_explain::SuffixKind::Empty,
+                );
+                self.dcx().create_err(OutlivesBound {
+                    span,
+                    notes: object_valid.into_iter().chain(pointer_valid).collect(),
+                })
+            }
+            infer::RelateParamBound(span, ty, opt_span) => {
+                let prefix = match *sub {
+                    ty::ReStatic => note_and_explain::PrefixKind::TypeSatisfy,
+                    _ => note_and_explain::PrefixKind::TypeOutlive,
+                };
+                let suffix = if opt_span.is_some() {
+                    note_and_explain::SuffixKind::ReqByBinding
+                } else {
+                    note_and_explain::SuffixKind::Empty
+                };
+                let note = note_and_explain::RegionExplanation::new(
+                    self.tcx,
+                    generic_param_scope,
+                    sub,
+                    opt_span,
+                    prefix,
+                    suffix,
+                );
+                self.dcx().create_err(FulfillReqLifetime {
+                    span,
+                    ty: self.resolve_vars_if_possible(ty),
+                    note,
+                })
+            }
+            infer::RelateRegionParamBound(span) => {
+                let param_instantiated = note_and_explain::RegionExplanation::new(
+                    self.tcx,
+                    generic_param_scope,
+                    sup,
+                    None,
+                    note_and_explain::PrefixKind::LfParamInstantiatedWith,
+                    note_and_explain::SuffixKind::Empty,
+                );
+                let param_must_outlive = note_and_explain::RegionExplanation::new(
+                    self.tcx,
+                    generic_param_scope,
+                    sub,
+                    None,
+                    note_and_explain::PrefixKind::LfParamMustOutlive,
+                    note_and_explain::SuffixKind::Empty,
+                );
+                self.dcx().create_err(LfBoundNotSatisfied {
+                    span,
+                    notes: param_instantiated.into_iter().chain(param_must_outlive).collect(),
+                })
+            }
+            infer::ReferenceOutlivesReferent(ty, span) => {
+                let pointer_valid = note_and_explain::RegionExplanation::new(
+                    self.tcx,
+                    generic_param_scope,
+                    sub,
+                    None,
+                    note_and_explain::PrefixKind::PointerValidFor,
+                    note_and_explain::SuffixKind::Empty,
+                );
+                let data_valid = note_and_explain::RegionExplanation::new(
+                    self.tcx,
+                    generic_param_scope,
+                    sup,
+                    None,
+                    note_and_explain::PrefixKind::DataValidFor,
+                    note_and_explain::SuffixKind::Empty,
+                );
+                self.dcx().create_err(RefLongerThanData {
+                    span,
+                    ty: self.resolve_vars_if_possible(ty),
+                    notes: pointer_valid.into_iter().chain(data_valid).collect(),
+                })
+            }
+            infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => {
+                let mut err = self.infcx.report_extra_impl_obligation(
+                    span,
+                    impl_item_def_id,
+                    trait_item_def_id,
+                    &format!("`{sup}: {sub}`"),
+                );
+                // We should only suggest rewriting the `where` clause if the predicate is within that `where` clause
+                if let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id)
+                    && generics.where_clause_span.contains(span)
+                {
+                    self.suggest_copy_trait_method_bounds(
+                        trait_item_def_id,
+                        impl_item_def_id,
+                        &mut err,
+                    );
+                }
+                err
+            }
+            infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
+                let mut err = self.report_concrete_failure(generic_param_scope, *parent, sub, sup);
+
+                // Don't mention the item name if it's an RPITIT, since that'll just confuse
+                // folks.
+                if !self.tcx.is_impl_trait_in_trait(impl_item_def_id.to_def_id()) {
+                    let trait_item_span = self.tcx.def_span(trait_item_def_id);
+                    let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
+                    err.span_label(
+                        trait_item_span,
+                        format!("definition of `{item_name}` from trait"),
+                    );
+                }
+
+                self.suggest_copy_trait_method_bounds(
+                    trait_item_def_id,
+                    impl_item_def_id,
+                    &mut err,
+                );
+                err
+            }
+            infer::AscribeUserTypeProvePredicate(span) => {
+                let instantiated = note_and_explain::RegionExplanation::new(
+                    self.tcx,
+                    generic_param_scope,
+                    sup,
+                    None,
+                    note_and_explain::PrefixKind::LfInstantiatedWith,
+                    note_and_explain::SuffixKind::Empty,
+                );
+                let must_outlive = note_and_explain::RegionExplanation::new(
+                    self.tcx,
+                    generic_param_scope,
+                    sub,
+                    None,
+                    note_and_explain::PrefixKind::LfMustOutlive,
+                    note_and_explain::SuffixKind::Empty,
+                );
+                self.dcx().create_err(LfBoundNotSatisfied {
+                    span,
+                    notes: instantiated.into_iter().chain(must_outlive).collect(),
+                })
+            }
+        };
+        if sub.is_error() || sup.is_error() {
+            err.downgrade_to_delayed_bug();
+        }
+        err
+    }
+
+    pub fn suggest_copy_trait_method_bounds(
+        &self,
+        trait_item_def_id: DefId,
+        impl_item_def_id: LocalDefId,
+        err: &mut Diag<'_>,
+    ) {
+        // FIXME(compiler-errors): Right now this is only being used for region
+        // predicate mismatches. Ideally, we'd use it for *all* predicate mismatches,
+        // but right now it's not really very smart when it comes to implicit `Sized`
+        // predicates and bounds on the trait itself.
+
+        let Some(impl_def_id) = self.tcx.associated_item(impl_item_def_id).impl_container(self.tcx)
+        else {
+            return;
+        };
+        let Some(trait_ref) = self.tcx.impl_trait_ref(impl_def_id) else {
+            return;
+        };
+        let trait_args = trait_ref
+            .instantiate_identity()
+            // Replace the explicit self type with `Self` for better suggestion rendering
+            .with_self_ty(self.tcx, Ty::new_param(self.tcx, 0, kw::SelfUpper))
+            .args;
+        let trait_item_args = ty::GenericArgs::identity_for_item(self.tcx, impl_item_def_id)
+            .rebase_onto(self.tcx, impl_def_id, trait_args);
+
+        let Ok(trait_predicates) =
+            self.tcx
+                .explicit_predicates_of(trait_item_def_id)
+                .instantiate_own(self.tcx, trait_item_args)
+                .map(|(pred, _)| {
+                    if pred.is_suggestable(self.tcx, false) {
+                        Ok(pred.to_string())
+                    } else {
+                        Err(())
+                    }
+                })
+                .collect::<Result<Vec<_>, ()>>()
+        else {
+            return;
+        };
+
+        let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) else {
+            return;
+        };
+
+        let suggestion = if trait_predicates.is_empty() {
+            WhereClauseSuggestions::Remove { span: generics.where_clause_span }
+        } else {
+            let space = if generics.where_clause_span.is_empty() { " " } else { "" };
+            WhereClauseSuggestions::CopyPredicates {
+                span: generics.where_clause_span,
+                space,
+                trait_predicates: trait_predicates.join(", "),
+            }
+        };
+        err.subdiagnostic(suggestion);
+    }
+
+    pub(super) fn report_placeholder_failure(
+        &self,
+        generic_param_scope: LocalDefId,
+        placeholder_origin: SubregionOrigin<'tcx>,
+        sub: Region<'tcx>,
+        sup: Region<'tcx>,
+    ) -> Diag<'a> {
+        // I can't think how to do better than this right now. -nikomatsakis
+        debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure");
+        match placeholder_origin {
+            infer::Subtype(box ref trace)
+                if matches!(
+                    &trace.cause.code().peel_derives(),
+                    ObligationCauseCode::WhereClause(..)
+                        | ObligationCauseCode::WhereClauseInExpr(..)
+                ) =>
+            {
+                // Hack to get around the borrow checker because trace.cause has an `Rc`.
+                if let ObligationCauseCode::WhereClause(_, span)
+                | ObligationCauseCode::WhereClauseInExpr(_, span, ..) =
+                    &trace.cause.code().peel_derives()
+                    && !span.is_dummy()
+                {
+                    let span = *span;
+                    self.report_concrete_failure(generic_param_scope, placeholder_origin, sub, sup)
+                        .with_span_note(span, "the lifetime requirement is introduced here")
+                } else {
+                    unreachable!(
+                        "control flow ensures we have a `BindingObligation` or `WhereClauseInExpr` here..."
+                    )
+                }
+            }
+            infer::Subtype(box trace) => {
+                let terr = TypeError::RegionsPlaceholderMismatch;
+                return self.report_and_explain_type_error(trace, terr);
+            }
+            _ => {
+                return self.report_concrete_failure(
+                    generic_param_scope,
+                    placeholder_origin,
+                    sub,
+                    sup,
+                );
+            }
+        }
+    }
+
+    pub fn report_generic_bound_failure(
+        &self,
+        generic_param_scope: LocalDefId,
+        span: Span,
+        origin: Option<SubregionOrigin<'tcx>>,
+        bound_kind: GenericKind<'tcx>,
+        sub: Region<'tcx>,
+    ) -> ErrorGuaranteed {
+        self.construct_generic_bound_failure(generic_param_scope, span, origin, bound_kind, sub)
+            .emit()
+    }
+
+    pub fn construct_generic_bound_failure(
+        &self,
+        generic_param_scope: LocalDefId,
+        span: Span,
+        origin: Option<SubregionOrigin<'tcx>>,
+        bound_kind: GenericKind<'tcx>,
+        sub: Region<'tcx>,
+    ) -> Diag<'a> {
+        if let Some(SubregionOrigin::CompareImplItemObligation {
+            span,
+            impl_item_def_id,
+            trait_item_def_id,
+        }) = origin
+        {
+            return self.infcx.report_extra_impl_obligation(
+                span,
+                impl_item_def_id,
+                trait_item_def_id,
+                &format!("`{bound_kind}: {sub}`"),
+            );
+        }
+
+        let labeled_user_string = match bound_kind {
+            GenericKind::Param(ref p) => format!("the parameter type `{p}`"),
+            GenericKind::Placeholder(ref p) => format!("the placeholder type `{p:?}`"),
+            GenericKind::Alias(ref p) => match p.kind(self.tcx) {
+                ty::Projection | ty::Inherent => {
+                    format!("the associated type `{p}`")
+                }
+                ty::Weak => format!("the type alias `{p}`"),
+                ty::Opaque => format!("the opaque type `{p}`"),
+            },
+        };
+
+        let mut err = self
+            .tcx
+            .dcx()
+            .struct_span_err(span, format!("{labeled_user_string} may not live long enough"));
+        err.code(match sub.kind() {
+            ty::ReEarlyParam(_) | ty::ReLateParam(_) if sub.has_name() => E0309,
+            ty::ReStatic => E0310,
+            _ => E0311,
+        });
+
+        '_explain: {
+            let (description, span) = match sub.kind() {
+                ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::ReStatic => {
+                    msg_span_from_named_region(self.tcx, generic_param_scope, sub, Some(span))
+                }
+                _ => (format!("lifetime `{sub}`"), Some(span)),
+            };
+            let prefix = format!("{labeled_user_string} must be valid for ");
+            label_msg_span(&mut err, &prefix, description, span, "...");
+            if let Some(origin) = origin {
+                self.note_region_origin(&mut err, &origin);
+            }
+        }
+
+        'suggestion: {
+            let msg = "consider adding an explicit lifetime bound";
+
+            if (bound_kind, sub).has_infer_regions()
+                || (bound_kind, sub).has_placeholders()
+                || !bound_kind.is_suggestable(self.tcx, false)
+            {
+                let lt_name = sub.get_name_or_anon().to_string();
+                err.help(format!("{msg} `{bound_kind}: {lt_name}`..."));
+                break 'suggestion;
+            }
+
+            let mut generic_param_scope = generic_param_scope;
+            while self.tcx.def_kind(generic_param_scope) == DefKind::OpaqueTy {
+                generic_param_scope = self.tcx.local_parent(generic_param_scope);
+            }
+
+            // type_param_sugg_span is (span, has_bounds, needs_parentheses)
+            let (type_scope, type_param_sugg_span) = match bound_kind {
+                GenericKind::Param(param) => {
+                    let generics = self.tcx.generics_of(generic_param_scope);
+                    let type_param = generics.type_param(param, self.tcx);
+                    let def_id = type_param.def_id.expect_local();
+                    let scope = self.tcx.local_def_id_to_hir_id(def_id).owner.def_id;
+                    // Get the `hir::Param` to verify whether it already has any bounds.
+                    // We do this to avoid suggesting code that ends up as `T: 'a'b`,
+                    // instead we suggest `T: 'a + 'b` in that case.
+                    let hir_generics = self.tcx.hir().get_generics(scope).unwrap();
+                    let sugg_span = match hir_generics.bounds_span_for_suggestions(def_id) {
+                        Some((span, open_paren_sp)) => Some((span, true, open_paren_sp)),
+                        // If `param` corresponds to `Self`, no usable suggestion span.
+                        None if generics.has_self && param.index == 0 => None,
+                        None => {
+                            let span = if let Some(param) =
+                                hir_generics.params.iter().find(|param| param.def_id == def_id)
+                                && let ParamName::Plain(ident) = param.name
+                            {
+                                ident.span.shrink_to_hi()
+                            } else {
+                                let span = self.tcx.def_span(def_id);
+                                span.shrink_to_hi()
+                            };
+                            Some((span, false, None))
+                        }
+                    };
+                    (scope, sugg_span)
+                }
+                _ => (generic_param_scope, None),
+            };
+            let suggestion_scope = {
+                let lifetime_scope = match sub.kind() {
+                    ty::ReStatic => hir::def_id::CRATE_DEF_ID,
+                    _ => match self.tcx.is_suitable_region(generic_param_scope, sub) {
+                        Some(info) => info.def_id,
+                        None => generic_param_scope,
+                    },
+                };
+                match self.tcx.is_descendant_of(type_scope.into(), lifetime_scope.into()) {
+                    true => type_scope,
+                    false => lifetime_scope,
+                }
+            };
+
+            let mut suggs = vec![];
+            let lt_name = self.suggest_name_region(generic_param_scope, sub, &mut suggs);
+
+            if let Some((sp, has_lifetimes, open_paren_sp)) = type_param_sugg_span
+                && suggestion_scope == type_scope
+            {
+                let suggestion =
+                    if has_lifetimes { format!(" + {lt_name}") } else { format!(": {lt_name}") };
+
+                if let Some(open_paren_sp) = open_paren_sp {
+                    suggs.push((open_paren_sp, "(".to_string()));
+                    suggs.push((sp, format!("){suggestion}")));
+                } else {
+                    suggs.push((sp, suggestion))
+                }
+            } else if let GenericKind::Alias(ref p) = bound_kind
+                && let ty::Projection = p.kind(self.tcx)
+                && let DefKind::AssocTy = self.tcx.def_kind(p.def_id)
+                && let Some(ty::ImplTraitInTraitData::Trait { .. }) =
+                    self.tcx.opt_rpitit_info(p.def_id)
+            {
+                // The lifetime found in the `impl` is longer than the one on the RPITIT.
+                // Do not suggest `<Type as Trait>::{opaque}: 'static`.
+            } else if let Some(generics) = self.tcx.hir().get_generics(suggestion_scope) {
+                let pred = format!("{bound_kind}: {lt_name}");
+                let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred);
+                suggs.push((generics.tail_span_for_predicate_suggestion(), suggestion))
+            } else {
+                let consider = format!("{msg} `{bound_kind}: {sub}`...");
+                err.help(consider);
+            }
+
+            if !suggs.is_empty() {
+                err.multipart_suggestion_verbose(
+                    msg,
+                    suggs,
+                    Applicability::MaybeIncorrect, // Issue #41966
+                );
+            }
+        }
+
+        err
+    }
+
+    pub fn suggest_name_region(
+        &self,
+        generic_param_scope: LocalDefId,
+        lifetime: Region<'tcx>,
+        add_lt_suggs: &mut Vec<(Span, String)>,
+    ) -> String {
+        struct LifetimeReplaceVisitor<'tcx, 'a> {
+            tcx: TyCtxt<'tcx>,
+            needle: hir::LifetimeName,
+            new_lt: &'a str,
+            add_lt_suggs: &'a mut Vec<(Span, String)>,
+        }
+
+        impl<'hir, 'tcx> hir::intravisit::Visitor<'hir> for LifetimeReplaceVisitor<'tcx, '_> {
+            fn visit_lifetime(&mut self, lt: &'hir hir::Lifetime) {
+                if lt.res == self.needle {
+                    let (pos, span) = lt.suggestion_position();
+                    let new_lt = &self.new_lt;
+                    let sugg = match pos {
+                        hir::LifetimeSuggestionPosition::Normal => format!("{new_lt}"),
+                        hir::LifetimeSuggestionPosition::Ampersand => format!("{new_lt} "),
+                        hir::LifetimeSuggestionPosition::ElidedPath => format!("<{new_lt}>"),
+                        hir::LifetimeSuggestionPosition::ElidedPathArgument => {
+                            format!("{new_lt}, ")
+                        }
+                        hir::LifetimeSuggestionPosition::ObjectDefault => format!("+ {new_lt}"),
+                    };
+                    self.add_lt_suggs.push((span, sugg));
+                }
+            }
+
+            fn visit_ty(&mut self, ty: &'hir hir::Ty<'hir>) {
+                let hir::TyKind::OpaqueDef(item_id, _, _) = ty.kind else {
+                    return hir::intravisit::walk_ty(self, ty);
+                };
+                let opaque_ty = self.tcx.hir().item(item_id).expect_opaque_ty();
+                if let Some(&(_, b)) =
+                    opaque_ty.lifetime_mapping.iter().find(|&(a, _)| a.res == self.needle)
+                {
+                    let prev_needle =
+                        std::mem::replace(&mut self.needle, hir::LifetimeName::Param(b));
+                    for bound in opaque_ty.bounds {
+                        self.visit_param_bound(bound);
+                    }
+                    self.needle = prev_needle;
+                }
+            }
+        }
+
+        let (lifetime_def_id, lifetime_scope) =
+            match self.tcx.is_suitable_region(generic_param_scope, lifetime) {
+                Some(info) if !lifetime.has_name() => {
+                    (info.bound_region.get_id().unwrap().expect_local(), info.def_id)
+                }
+                _ => return lifetime.get_name_or_anon().to_string(),
+            };
+
+        let new_lt = {
+            let generics = self.tcx.generics_of(lifetime_scope);
+            let mut used_names =
+                iter::successors(Some(generics), |g| g.parent.map(|p| self.tcx.generics_of(p)))
+                    .flat_map(|g| &g.own_params)
+                    .filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime))
+                    .map(|p| p.name)
+                    .collect::<Vec<_>>();
+            let hir_id = self.tcx.local_def_id_to_hir_id(lifetime_scope);
+            // consider late-bound lifetimes ...
+            used_names.extend(self.tcx.late_bound_vars(hir_id).into_iter().filter_map(
+                |p| match p {
+                    ty::BoundVariableKind::Region(lt) => lt.get_name(),
+                    _ => None,
+                },
+            ));
+            (b'a'..=b'z')
+                .map(|c| format!("'{}", c as char))
+                .find(|candidate| !used_names.iter().any(|e| e.as_str() == candidate))
+                .unwrap_or("'lt".to_string())
+        };
+
+        let mut visitor = LifetimeReplaceVisitor {
+            tcx: self.tcx,
+            needle: hir::LifetimeName::Param(lifetime_def_id),
+            add_lt_suggs,
+            new_lt: &new_lt,
+        };
+        match self.tcx.expect_hir_owner_node(lifetime_scope) {
+            hir::OwnerNode::Item(i) => visitor.visit_item(i),
+            hir::OwnerNode::ForeignItem(i) => visitor.visit_foreign_item(i),
+            hir::OwnerNode::ImplItem(i) => visitor.visit_impl_item(i),
+            hir::OwnerNode::TraitItem(i) => visitor.visit_trait_item(i),
+            hir::OwnerNode::Crate(_) => bug!("OwnerNode::Crate doesn't not have generics"),
+            hir::OwnerNode::Synthetic => unreachable!(),
+        }
+
+        let ast_generics = self.tcx.hir().get_generics(lifetime_scope).unwrap();
+        let sugg = ast_generics
+            .span_for_lifetime_suggestion()
+            .map(|span| (span, format!("{new_lt}, ")))
+            .unwrap_or_else(|| (ast_generics.span, format!("<{new_lt}>")));
+        add_lt_suggs.push(sugg);
+
+        new_lt
+    }
+
+    fn report_sub_sup_conflict(
+        &self,
+        generic_param_scope: LocalDefId,
+        var_origin: RegionVariableOrigin,
+        sub_origin: SubregionOrigin<'tcx>,
+        sub_region: Region<'tcx>,
+        sup_origin: SubregionOrigin<'tcx>,
+        sup_region: Region<'tcx>,
+    ) -> ErrorGuaranteed {
+        let mut err = self.report_inference_failure(var_origin);
+
+        note_and_explain_region(
+            self.tcx,
+            &mut err,
+            generic_param_scope,
+            "first, the lifetime cannot outlive ",
+            sup_region,
+            "...",
+            None,
+        );
+
+        debug!("report_sub_sup_conflict: var_origin={:?}", var_origin);
+        debug!("report_sub_sup_conflict: sub_region={:?}", sub_region);
+        debug!("report_sub_sup_conflict: sub_origin={:?}", sub_origin);
+        debug!("report_sub_sup_conflict: sup_region={:?}", sup_region);
+        debug!("report_sub_sup_conflict: sup_origin={:?}", sup_origin);
+
+        if let infer::Subtype(ref sup_trace) = sup_origin
+            && let infer::Subtype(ref sub_trace) = sub_origin
+            && let Some((sup_expected, sup_found, _)) = self.values_str(sup_trace.values)
+            && let Some((sub_expected, sub_found, _)) = self.values_str(sub_trace.values)
+            && sub_expected == sup_expected
+            && sub_found == sup_found
+        {
+            note_and_explain_region(
+                self.tcx,
+                &mut err,
+                generic_param_scope,
+                "...but the lifetime must also be valid for ",
+                sub_region,
+                "...",
+                None,
+            );
+            err.span_note(
+                sup_trace.cause.span,
+                format!("...so that the {}", sup_trace.cause.as_requirement_str()),
+            );
+
+            err.note_expected_found(&"", sup_expected, &"", sup_found);
+            return if sub_region.is_error() | sup_region.is_error() {
+                err.delay_as_bug()
+            } else {
+                err.emit()
+            };
+        }
+
+        self.note_region_origin(&mut err, &sup_origin);
+
+        note_and_explain_region(
+            self.tcx,
+            &mut err,
+            generic_param_scope,
+            "but, the lifetime must be valid for ",
+            sub_region,
+            "...",
+            None,
+        );
+
+        self.note_region_origin(&mut err, &sub_origin);
+        if sub_region.is_error() | sup_region.is_error() { err.delay_as_bug() } else { err.emit() }
+    }
+
+    fn report_inference_failure(&self, var_origin: RegionVariableOrigin) -> Diag<'_> {
+        let br_string = |br: ty::BoundRegionKind| {
+            let mut s = match br {
+                ty::BrNamed(_, name) => name.to_string(),
+                _ => String::new(),
+            };
+            if !s.is_empty() {
+                s.push(' ');
+            }
+            s
+        };
+        let var_description = match var_origin {
+            infer::MiscVariable(_) => String::new(),
+            infer::PatternRegion(_) => " for pattern".to_string(),
+            infer::AddrOfRegion(_) => " for borrow expression".to_string(),
+            infer::Autoref(_) => " for autoref".to_string(),
+            infer::Coercion(_) => " for automatic coercion".to_string(),
+            infer::BoundRegion(_, br, infer::FnCall) => {
+                format!(" for lifetime parameter {}in function call", br_string(br))
+            }
+            infer::BoundRegion(_, br, infer::HigherRankedType) => {
+                format!(" for lifetime parameter {}in generic type", br_string(br))
+            }
+            infer::BoundRegion(_, br, infer::AssocTypeProjection(def_id)) => format!(
+                " for lifetime parameter {}in trait containing associated type `{}`",
+                br_string(br),
+                self.tcx.associated_item(def_id).name
+            ),
+            infer::RegionParameterDefinition(_, name) => {
+                format!(" for lifetime parameter `{name}`")
+            }
+            infer::UpvarRegion(ref upvar_id, _) => {
+                let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
+                format!(" for capture of `{var_name}` by closure")
+            }
+            infer::Nll(..) => bug!("NLL variable found in lexical phase"),
+        };
+
+        struct_span_code_err!(
+            self.dcx(),
+            var_origin.span(),
+            E0495,
+            "cannot infer an appropriate lifetime{} due to conflicting requirements",
+            var_description
+        )
+    }
+}
+
+pub(super) fn note_and_explain_region<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    err: &mut Diag<'_>,
+    generic_param_scope: LocalDefId,
+    prefix: &str,
+    region: ty::Region<'tcx>,
+    suffix: &str,
+    alt_span: Option<Span>,
+) {
+    let (description, span) = match *region {
+        ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::RePlaceholder(_) | ty::ReStatic => {
+            msg_span_from_named_region(tcx, generic_param_scope, region, alt_span)
+        }
+
+        ty::ReError(_) => return,
+
+        // FIXME(#125431): `ReVar` shouldn't reach here.
+        ty::ReVar(_) => (format!("lifetime `{region}`"), alt_span),
+
+        ty::ReBound(..) | ty::ReErased => {
+            bug!("unexpected region for note_and_explain_region: {:?}", region);
+        }
+    };
+
+    emit_msg_span(err, prefix, description, span, suffix);
+}
+
+fn explain_free_region<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    err: &mut Diag<'_>,
+    generic_param_scope: LocalDefId,
+    prefix: &str,
+    region: ty::Region<'tcx>,
+    suffix: &str,
+) {
+    let (description, span) = msg_span_from_named_region(tcx, generic_param_scope, region, None);
+
+    label_msg_span(err, prefix, description, span, suffix);
+}
+
+fn msg_span_from_named_region<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    generic_param_scope: LocalDefId,
+    region: ty::Region<'tcx>,
+    alt_span: Option<Span>,
+) -> (String, Option<Span>) {
+    match *region {
+        ty::ReEarlyParam(br) => {
+            let scope = tcx
+                .parent(tcx.generics_of(generic_param_scope).region_param(br, tcx).def_id)
+                .expect_local();
+            let span = if let Some(param) =
+                tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
+            {
+                param.span
+            } else {
+                tcx.def_span(scope)
+            };
+            let text = if br.has_name() {
+                format!("the lifetime `{}` as defined here", br.name)
+            } else {
+                "the anonymous lifetime as defined here".to_string()
+            };
+            (text, Some(span))
+        }
+        ty::ReLateParam(ref fr) => {
+            if !fr.bound_region.is_named()
+                && let Some((ty, _)) =
+                    find_anon_type(tcx, generic_param_scope, region, &fr.bound_region)
+            {
+                ("the anonymous lifetime defined here".to_string(), Some(ty.span))
+            } else {
+                match fr.bound_region {
+                    ty::BoundRegionKind::BrNamed(_, name) => {
+                        let span = if let Some(param) = tcx
+                            .hir()
+                            .get_generics(generic_param_scope)
+                            .and_then(|generics| generics.get_named(name))
+                        {
+                            param.span
+                        } else {
+                            tcx.def_span(generic_param_scope)
+                        };
+                        let text = if name == kw::UnderscoreLifetime {
+                            "the anonymous lifetime as defined here".to_string()
+                        } else {
+                            format!("the lifetime `{name}` as defined here")
+                        };
+                        (text, Some(span))
+                    }
+                    ty::BrAnon => (
+                        "the anonymous lifetime as defined here".to_string(),
+                        Some(tcx.def_span(generic_param_scope)),
+                    ),
+                    _ => (
+                        format!("the lifetime `{region}` as defined here"),
+                        Some(tcx.def_span(generic_param_scope)),
+                    ),
+                }
+            }
+        }
+        ty::ReStatic => ("the static lifetime".to_owned(), alt_span),
+        ty::RePlaceholder(ty::PlaceholderRegion {
+            bound: ty::BoundRegion { kind: ty::BoundRegionKind::BrNamed(def_id, name), .. },
+            ..
+        }) => (format!("the lifetime `{name}` as defined here"), Some(tcx.def_span(def_id))),
+        ty::RePlaceholder(ty::PlaceholderRegion {
+            bound: ty::BoundRegion { kind: ty::BoundRegionKind::BrAnon, .. },
+            ..
+        }) => ("an anonymous lifetime".to_owned(), None),
+        _ => bug!("{:?}", region),
+    }
+}
+
+fn emit_msg_span(
+    err: &mut Diag<'_>,
+    prefix: &str,
+    description: String,
+    span: Option<Span>,
+    suffix: &str,
+) {
+    let message = format!("{prefix}{description}{suffix}");
+
+    if let Some(span) = span {
+        err.span_note(span, message);
+    } else {
+        err.note(message);
+    }
+}
+
+fn label_msg_span(
+    err: &mut Diag<'_>,
+    prefix: &str,
+    description: String,
+    span: Option<Span>,
+    suffix: &str,
+) {
+    let message = format!("{prefix}{description}{suffix}");
+
+    if let Some(span) = span {
+        err.span_label(span, message);
+    } else {
+        err.note(message);
+    }
+}
+
+#[instrument(level = "trace", skip(infcx))]
+pub fn unexpected_hidden_region_diagnostic<'a, 'tcx>(
+    infcx: &'a InferCtxt<'tcx>,
+    generic_param_scope: LocalDefId,
+    span: Span,
+    hidden_ty: Ty<'tcx>,
+    hidden_region: ty::Region<'tcx>,
+    opaque_ty_key: ty::OpaqueTypeKey<'tcx>,
+) -> Diag<'a> {
+    let tcx = infcx.tcx;
+    let mut err = infcx.dcx().create_err(errors::OpaqueCapturesLifetime {
+        span,
+        opaque_ty: Ty::new_opaque(tcx, opaque_ty_key.def_id.to_def_id(), opaque_ty_key.args),
+        opaque_ty_span: tcx.def_span(opaque_ty_key.def_id),
+    });
+
+    // Explain the region we are capturing.
+    match *hidden_region {
+        ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::ReStatic => {
+            // Assuming regionck succeeded (*), we ought to always be
+            // capturing *some* region from the fn header, and hence it
+            // ought to be free. So under normal circumstances, we will go
+            // down this path which gives a decent human readable
+            // explanation.
+            //
+            // (*) if not, the `tainted_by_errors` field would be set to
+            // `Some(ErrorGuaranteed)` in any case, so we wouldn't be here at all.
+            explain_free_region(
+                tcx,
+                &mut err,
+                generic_param_scope,
+                &format!("hidden type `{hidden_ty}` captures "),
+                hidden_region,
+                "",
+            );
+            if let Some(reg_info) = tcx.is_suitable_region(generic_param_scope, hidden_region) {
+                let fn_returns = tcx.return_type_impl_or_dyn_traits(reg_info.def_id);
+                nice_region_error::suggest_new_region_bound(
+                    tcx,
+                    &mut err,
+                    fn_returns,
+                    hidden_region.to_string(),
+                    None,
+                    format!("captures `{hidden_region}`"),
+                    None,
+                    Some(reg_info.def_id),
+                )
+            }
+        }
+        ty::RePlaceholder(_) => {
+            explain_free_region(
+                tcx,
+                &mut err,
+                generic_param_scope,
+                &format!("hidden type `{}` captures ", hidden_ty),
+                hidden_region,
+                "",
+            );
+        }
+        ty::ReError(_) => {
+            err.downgrade_to_delayed_bug();
+        }
+        _ => {
+            // Ugh. This is a painful case: the hidden region is not one
+            // that we can easily summarize or explain. This can happen
+            // in a case like
+            // `tests/ui/multiple-lifetimes/ordinary-bounds-unsuited.rs`:
+            //
+            // ```
+            // fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> {
+            //   if condition() { a } else { b }
+            // }
+            // ```
+            //
+            // Here the captured lifetime is the intersection of `'a` and
+            // `'b`, which we can't quite express.
+
+            // We can at least report a really cryptic error for now.
+            note_and_explain_region(
+                tcx,
+                &mut err,
+                generic_param_scope,
+                &format!("hidden type `{hidden_ty}` captures "),
+                hidden_region,
+                "",
+                None,
+            );
+        }
+    }
+
+    err
+}