From fe2d7794ca189f9ec5e7f7fd9b059e7a2e785944 Mon Sep 17 00:00:00 2001
From: Boxy <supbscripter@gmail.com>
Date: Fri, 24 May 2024 01:57:06 +0100
Subject: [PATCH] Remove `DefId` from `EarlyParamRegion` (tedium/diagnostics)

---
 .../src/diagnostics/bound_region_errors.rs    |  36 ++++---
 .../src/diagnostics/region_errors.rs          |  39 ++++---
 .../src/diagnostics/region_name.rs            |   8 +-
 .../src/check/compare_impl_item.rs            |   1 -
 .../rustc_hir_analysis/src/check/wfcheck.rs   |  18 +---
 compiler/rustc_hir_analysis/src/collect.rs    |   1 -
 .../src/collect/predicates_of.rs              |   2 +-
 .../src/hir_ty_lowering/mod.rs                |   2 +-
 compiler/rustc_infer/src/errors/mod.rs        |   5 +-
 .../src/errors/note_and_explain.rs            |  20 +++-
 .../src/infer/error_reporting/mod.rs          | 100 +++++++++++++-----
 .../nice_region_error/different_lifetimes.rs  |  31 ++++--
 .../nice_region_error/find_anon_type.rs       |   4 +-
 .../mismatched_static_lifetime.rs             |   1 +
 .../error_reporting/nice_region_error/mod.rs  |  18 +++-
 .../nice_region_error/named_anon_conflict.rs  |   6 +-
 .../nice_region_error/static_impl_trait.rs    |   4 +-
 .../error_reporting/nice_region_error/util.rs |   8 +-
 .../src/infer/error_reporting/note.rs         |  45 +++++++-
 compiler/rustc_lint/src/builtin.rs            |  18 +++-
 compiler/rustc_middle/src/ty/context.rs       |  14 +--
 compiler/rustc_middle/src/ty/generics.rs      |   2 +-
 compiler/rustc_middle/src/ty/region.rs        |  27 -----
 .../rustc_smir/src/rustc_smir/convert/ty.rs   |   2 +-
 .../rustc_trait_selection/src/traits/mod.rs   |   1 +
 compiler/rustc_ty_utils/src/implied_bounds.rs |   6 +-
 .../ty-outlives/impl-trait-captures.stderr    |   4 +-
 27 files changed, 266 insertions(+), 157 deletions(-)

diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
index 9b8b7e8ddda..5e10f14f31b 100644
--- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
@@ -1,4 +1,5 @@
 use rustc_errors::Diag;
+use rustc_hir::def_id::LocalDefId;
 use rustc_infer::infer::canonical::Canonical;
 use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError;
 use rustc_infer::infer::region_constraints::Constraint;
@@ -241,7 +242,7 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
             mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
         let ocx = ObligationCtxt::new(&infcx);
         type_op_prove_predicate_with_cause(&ocx, key, cause);
-        try_extract_error_from_fulfill_cx(&ocx, placeholder_region, error_region)
+        try_extract_error_from_fulfill_cx(&ocx, mbcx.mir_def_id(), placeholder_region, error_region)
     }
 }
 
@@ -287,7 +288,7 @@ where
         let (param_env, value) = key.into_parts();
         let _ = ocx.normalize(&cause, param_env, value.value);
 
-        try_extract_error_from_fulfill_cx(&ocx, placeholder_region, error_region)
+        try_extract_error_from_fulfill_cx(&ocx, mbcx.mir_def_id(), placeholder_region, error_region)
     }
 }
 
@@ -318,7 +319,7 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
             mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
         let ocx = ObligationCtxt::new(&infcx);
         type_op_ascribe_user_type_with_span(&ocx, key, Some(cause.span)).ok()?;
-        try_extract_error_from_fulfill_cx(&ocx, placeholder_region, error_region)
+        try_extract_error_from_fulfill_cx(&ocx, mbcx.mir_def_id(), placeholder_region, error_region)
     }
 }
 
@@ -342,6 +343,7 @@ impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
     ) -> Option<Diag<'tcx>> {
         try_extract_error_from_region_constraints(
             mbcx.infcx,
+            mbcx.mir_def_id(),
             placeholder_region,
             error_region,
             self.region_constraints.as_ref().unwrap(),
@@ -358,6 +360,7 @@ impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
 #[instrument(skip(ocx), level = "debug")]
 fn try_extract_error_from_fulfill_cx<'tcx>(
     ocx: &ObligationCtxt<'_, 'tcx>,
+    generic_param_scope: LocalDefId,
     placeholder_region: ty::Region<'tcx>,
     error_region: Option<ty::Region<'tcx>>,
 ) -> Option<Diag<'tcx>> {
@@ -368,6 +371,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
     let region_constraints = ocx.infcx.with_region_constraints(|r| r.clone());
     try_extract_error_from_region_constraints(
         ocx.infcx,
+        generic_param_scope,
         placeholder_region,
         error_region,
         &region_constraints,
@@ -379,6 +383,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
 #[instrument(level = "debug", skip(infcx, region_var_origin, universe_of_region))]
 fn try_extract_error_from_region_constraints<'tcx>(
     infcx: &InferCtxt<'tcx>,
+    generic_param_scope: LocalDefId,
     placeholder_region: ty::Region<'tcx>,
     error_region: Option<ty::Region<'tcx>>,
     region_constraints: &RegionConstraintData<'tcx>,
@@ -452,15 +457,18 @@ fn try_extract_error_from_region_constraints<'tcx>(
             RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region)
         }
     };
-    NiceRegionError::new(&infcx.err_ctxt(), error).try_report_from_nll().or_else(|| {
-        if let SubregionOrigin::Subtype(trace) = cause {
-            Some(
-                infcx
-                    .err_ctxt()
-                    .report_and_explain_type_error(*trace, TypeError::RegionsPlaceholderMismatch),
-            )
-        } else {
-            None
-        }
-    })
+    NiceRegionError::new(&infcx.err_ctxt(), generic_param_scope, error)
+        .try_report_from_nll()
+        .or_else(|| {
+            if let SubregionOrigin::Subtype(trace) = cause {
+                Some(
+                    infcx.err_ctxt().report_and_explain_type_error(
+                        *trace,
+                        TypeError::RegionsPlaceholderMismatch,
+                    ),
+                )
+            } else {
+                None
+            }
+        })
 }
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 8112fb7b89c..e11e4a7247c 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -361,6 +361,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region);
                     let diag = unexpected_hidden_region_diagnostic(
                         self.infcx.tcx,
+                        self.mir_def_id(),
                         span,
                         named_ty,
                         named_region,
@@ -453,7 +454,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         // Check if we can use one of the "nice region errors".
         if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
             let infer_err = self.infcx.err_ctxt();
-            let nice = NiceRegionError::new_from_span(&infer_err, cause.span, o, f);
+            let nice =
+                NiceRegionError::new_from_span(&infer_err, self.mir_def_id(), cause.span, o, f);
             if let Some(diag) = nice.try_report_from_nll() {
                 self.buffer_error(diag);
                 return;
@@ -843,14 +845,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             if *outlived_f != ty::ReStatic {
                 return;
             }
-            let suitable_region = self.infcx.tcx.is_suitable_region(f);
+            let suitable_region = self.infcx.tcx.is_suitable_region(self.mir_def_id(), f);
             let Some(suitable_region) = suitable_region else {
                 return;
             };
 
             let fn_returns = self.infcx.tcx.return_type_impl_or_dyn_traits(suitable_region.def_id);
 
-            let param = if let Some(param) = find_param_with_region(self.infcx.tcx, f, outlived_f) {
+            let param = if let Some(param) =
+                find_param_with_region(self.infcx.tcx, self.mir_def_id(), f, outlived_f)
+            {
                 param
             } else {
                 return;
@@ -959,7 +963,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             return;
         };
 
-        let param = match find_param_with_region(tcx, f, o) {
+        let param = match find_param_with_region(tcx, self.mir_def_id(), f, o) {
             Some(param) => param,
             None => return,
         };
@@ -1022,25 +1026,30 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             return;
         };
 
-        let Some((ty_sub, _)) = self
-            .infcx
-            .tcx
-            .is_suitable_region(sub)
-            .and_then(|anon_reg| find_anon_type(self.infcx.tcx, sub, &anon_reg.bound_region))
+        let Some((ty_sub, _)) =
+            self.infcx.tcx.is_suitable_region(self.mir_def_id(), sub).and_then(|anon_reg| {
+                find_anon_type(self.infcx.tcx, self.mir_def_id(), sub, &anon_reg.bound_region)
+            })
         else {
             return;
         };
 
-        let Some((ty_sup, _)) = self
-            .infcx
-            .tcx
-            .is_suitable_region(sup)
-            .and_then(|anon_reg| find_anon_type(self.infcx.tcx, sup, &anon_reg.bound_region))
+        let Some((ty_sup, _)) =
+            self.infcx.tcx.is_suitable_region(self.mir_def_id(), sup).and_then(|anon_reg| {
+                find_anon_type(self.infcx.tcx, self.mir_def_id(), sup, &anon_reg.bound_region)
+            })
         else {
             return;
         };
 
-        suggest_adding_lifetime_params(self.infcx.tcx, sub, ty_sup, ty_sub, diag);
+        suggest_adding_lifetime_params(
+            self.infcx.tcx,
+            diag,
+            self.mir_def_id(),
+            sub,
+            ty_sup,
+            ty_sub,
+        );
     }
 
     #[allow(rustc::diagnostic_outside_of_impl)]
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 46011c1f43e..c2db64e7702 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -289,7 +289,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
         debug!("give_region_a_name: error_region = {:?}", error_region);
         match *error_region {
             ty::ReEarlyParam(ebr) => ebr.has_name().then(|| {
-                let span = tcx.hir().span_if_local(ebr.def_id).unwrap_or(DUMMY_SP);
+                let def_id = tcx.generics_of(self.mir_def_id()).region_param(ebr, tcx).def_id;
+                let span = tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP);
                 RegionName { name: ebr.name, source: RegionNameSource::NamedEarlyParamRegion(span) }
             }),
 
@@ -912,7 +913,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
         };
 
         let tcx = self.infcx.tcx;
-        let region_parent = tcx.parent(region.def_id);
+        let region_def = tcx.generics_of(self.mir_def_id()).region_param(region, tcx).def_id;
+        let region_parent = tcx.parent(region_def);
         let DefKind::Impl { .. } = tcx.def_kind(region_parent) else {
             return None;
         };
@@ -925,7 +927,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
         Some(RegionName {
             name: self.synthesize_region_name(),
             source: RegionNameSource::AnonRegionFromImplSignature(
-                tcx.def_span(region.def_id),
+                tcx.def_span(region_def),
                 // FIXME(compiler-errors): Does this ever actually show up
                 // anywhere other than the self type? I couldn't create an
                 // example of a `'_` in the impl's trait being referenceable.
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index fedaf326886..39ced1c803f 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -925,7 +925,6 @@ impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for RemapHiddenTyRegions<'tcx> {
         Ok(ty::Region::new_early_param(
             self.tcx,
             ty::EarlyParamRegion {
-                def_id: e.def_id,
                 name: e.name,
                 index: (e.index as usize - self.num_trait_args + self.num_impl_args) as u32,
             },
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 460269ae41f..81e3d8c7ece 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -675,11 +675,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
                 let region_param = gat_generics.param_at(*region_a_idx, tcx);
                 let region_param = ty::Region::new_early_param(
                     tcx,
-                    ty::EarlyParamRegion {
-                        def_id: region_param.def_id,
-                        index: region_param.index,
-                        name: region_param.name,
-                    },
+                    ty::EarlyParamRegion { index: region_param.index, name: region_param.name },
                 );
                 // The predicate we expect to see. (In our example,
                 // `Self: 'me`.)
@@ -708,21 +704,13 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
                 let region_a_param = gat_generics.param_at(*region_a_idx, tcx);
                 let region_a_param = ty::Region::new_early_param(
                     tcx,
-                    ty::EarlyParamRegion {
-                        def_id: region_a_param.def_id,
-                        index: region_a_param.index,
-                        name: region_a_param.name,
-                    },
+                    ty::EarlyParamRegion { index: region_a_param.index, name: region_a_param.name },
                 );
                 // Same for the region.
                 let region_b_param = gat_generics.param_at(*region_b_idx, tcx);
                 let region_b_param = ty::Region::new_early_param(
                     tcx,
-                    ty::EarlyParamRegion {
-                        def_id: region_b_param.def_id,
-                        index: region_b_param.index,
-                        name: region_b_param.name,
-                    },
+                    ty::EarlyParamRegion { index: region_b_param.index, name: region_b_param.name },
                 );
                 // The predicate we expect to see.
                 bounds.insert(
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index b760b86a7bf..40cd65b899e 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -453,7 +453,6 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
                                         poly_trait_ref,
                                         |_| {
                                             ty::Region::new_early_param(self.tcx, ty::EarlyParamRegion {
-                                                def_id: item_def_id,
                                                 index: 0,
                                                 name: Symbol::intern(&lt_name),
                                             })
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index db36aba7edf..45f06e59be8 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -323,7 +323,7 @@ fn compute_bidirectional_outlives_predicates<'tcx>(
         if let ty::ReEarlyParam(..) = *orig_lifetime {
             let dup_lifetime = ty::Region::new_early_param(
                 tcx,
-                ty::EarlyParamRegion { def_id: param.def_id, index: param.index, name: param.name },
+                ty::EarlyParamRegion { index: param.index, name: param.name },
             );
             let span = tcx.def_span(param.def_id);
             predicates.push((
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 4b1c0da6ce1..83a23de1654 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -280,7 +280,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local());
                 let generics = tcx.generics_of(item_def_id);
                 let index = generics.param_def_id_to_index[&def_id];
-                ty::Region::new_early_param(tcx, ty::EarlyParamRegion { def_id, index, name })
+                ty::Region::new_early_param(tcx, ty::EarlyParamRegion { index, name })
             }
 
             Some(rbv::ResolvedArg::Free(scope, id)) => {
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs
index 8bb0dc39143..a801001eaf9 100644
--- a/compiler/rustc_infer/src/errors/mod.rs
+++ b/compiler/rustc_infer/src/errors/mod.rs
@@ -5,6 +5,7 @@ use rustc_errors::{
     MultiSpan, SubdiagMessageOp, Subdiagnostic,
 };
 use rustc_hir as hir;
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{walk_ty, Visitor};
 use rustc_hir::FnRetTy;
 use rustc_macros::{Diagnostic, Subdiagnostic};
@@ -344,6 +345,7 @@ impl Subdiagnostic for LifetimeMismatchLabels {
 
 pub struct AddLifetimeParamsSuggestion<'a> {
     pub tcx: TyCtxt<'a>,
+    pub generic_param_scope: LocalDefId,
     pub sub: Region<'a>,
     pub ty_sup: &'a hir::Ty<'a>,
     pub ty_sub: &'a hir::Ty<'a>,
@@ -357,7 +359,8 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
         _f: &F,
     ) {
         let mut mk_suggestion = || {
-            let Some(anon_reg) = self.tcx.is_suitable_region(self.sub) else {
+            let Some(anon_reg) = self.tcx.is_suitable_region(self.generic_param_scope, self.sub)
+            else {
                 return false;
             };
 
diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs
index f0b336ca046..4fbeb0ec102 100644
--- a/compiler/rustc_infer/src/errors/note_and_explain.rs
+++ b/compiler/rustc_infer/src/errors/note_and_explain.rs
@@ -1,6 +1,7 @@
 use crate::fluent_generated as fluent;
 use crate::infer::error_reporting::nice_region_error::find_anon_type;
 use rustc_errors::{Diag, EmissionGuarantee, IntoDiagArg, SubdiagMessageOp, Subdiagnostic};
+use rustc_hir::def_id::LocalDefId;
 use rustc_middle::bug;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::{symbol::kw, Span};
@@ -14,12 +15,15 @@ struct DescriptionCtx<'a> {
 impl<'a> DescriptionCtx<'a> {
     fn new<'tcx>(
         tcx: TyCtxt<'tcx>,
+        generic_param_scope: LocalDefId,
         region: ty::Region<'tcx>,
         alt_span: Option<Span>,
     ) -> Option<Self> {
         let (span, kind, arg) = match *region {
-            ty::ReEarlyParam(ref br) => {
-                let scope = region.free_region_binding_scope(tcx).expect_local();
+            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))
                 {
@@ -35,11 +39,12 @@ impl<'a> DescriptionCtx<'a> {
             }
             ty::ReLateParam(ref fr) => {
                 if !fr.bound_region.is_named()
-                    && let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region)
+                    && let Some((ty, _)) =
+                        find_anon_type(tcx, generic_param_scope, region, &fr.bound_region)
                 {
                     (Some(ty.span), "defined_here", String::new())
                 } else {
-                    let scope = region.free_region_binding_scope(tcx).expect_local();
+                    let scope = fr.scope.expect_local();
                     match fr.bound_region {
                         ty::BoundRegionKind::BrNamed(_, name) => {
                             let span = if let Some(param) = tcx
@@ -143,12 +148,17 @@ pub struct RegionExplanation<'a> {
 impl RegionExplanation<'_> {
     pub fn new<'tcx>(
         tcx: TyCtxt<'tcx>,
+        generic_param_scope: LocalDefId,
         region: ty::Region<'tcx>,
         alt_span: Option<Span>,
         prefix: PrefixKind,
         suffix: SuffixKind,
     ) -> Option<Self> {
-        Some(Self { desc: DescriptionCtx::new(tcx, region, alt_span)?, prefix, suffix })
+        Some(Self {
+            desc: DescriptionCtx::new(tcx, generic_param_scope, region, alt_span)?,
+            prefix,
+            suffix,
+        })
     }
 }
 
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index e0894ed31bf..7ab148e70a1 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -161,6 +161,7 @@ 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,
@@ -168,7 +169,7 @@ pub(super) fn note_and_explain_region<'tcx>(
 ) {
     let (description, span) = match *region {
         ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::RePlaceholder(_) | ty::ReStatic => {
-            msg_span_from_named_region(tcx, region, alt_span)
+            msg_span_from_named_region(tcx, generic_param_scope, region, alt_span)
         }
 
         ty::ReError(_) => return,
@@ -187,23 +188,27 @@ pub(super) fn note_and_explain_region<'tcx>(
 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, region, None);
+    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(ref br) => {
-            let scope = region.free_region_binding_scope(tcx).expect_local();
+        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))
             {
@@ -220,21 +225,21 @@ fn msg_span_from_named_region<'tcx>(
         }
         ty::ReLateParam(ref fr) => {
             if !fr.bound_region.is_named()
-                && let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region)
+                && 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 {
-                let scope = region.free_region_binding_scope(tcx).expect_local();
                 match fr.bound_region {
                     ty::BoundRegionKind::BrNamed(_, name) => {
                         let span = if let Some(param) = tcx
                             .hir()
-                            .get_generics(scope)
+                            .get_generics(generic_param_scope)
                             .and_then(|generics| generics.get_named(name))
                         {
                             param.span
                         } else {
-                            tcx.def_span(scope)
+                            tcx.def_span(generic_param_scope)
                         };
                         let text = if name == kw::UnderscoreLifetime {
                             "the anonymous lifetime as defined here".to_string()
@@ -245,11 +250,11 @@ fn msg_span_from_named_region<'tcx>(
                     }
                     ty::BrAnon => (
                         "the anonymous lifetime as defined here".to_string(),
-                        Some(tcx.def_span(scope)),
+                        Some(tcx.def_span(generic_param_scope)),
                     ),
                     _ => (
                         format!("the lifetime `{region}` as defined here"),
-                        Some(tcx.def_span(scope)),
+                        Some(tcx.def_span(generic_param_scope)),
                     ),
                 }
             }
@@ -302,6 +307,7 @@ fn label_msg_span(
 #[instrument(level = "trace", skip(tcx))]
 pub fn unexpected_hidden_region_diagnostic<'tcx>(
     tcx: TyCtxt<'tcx>,
+    generic_param_scope: LocalDefId,
     span: Span,
     hidden_ty: Ty<'tcx>,
     hidden_region: ty::Region<'tcx>,
@@ -327,11 +333,12 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
             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(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,
@@ -349,6 +356,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
             explain_free_region(
                 tcx,
                 &mut err,
+                generic_param_scope,
                 &format!("hidden type `{}` captures ", hidden_ty),
                 hidden_region,
                 "",
@@ -376,6 +384,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
             note_and_explain_region(
                 tcx,
                 &mut err,
+                generic_param_scope,
                 &format!("hidden type `{hidden_ty}` captures "),
                 hidden_region,
                 "",
@@ -450,7 +459,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         for error in errors {
             debug!("report_region_errors: error = {:?}", error);
 
-            guar = Some(if let Some(guar) = self.try_report_nice_region_error(&error) {
+            let e = if let Some(guar) =
+                self.try_report_nice_region_error(generic_param_scope, &error)
+            {
                 guar
             } else {
                 match error.clone() {
@@ -463,9 +474,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     // 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(origin, sub, sup).emit()
+                            self.report_placeholder_failure(generic_param_scope, origin, sub, sup)
+                                .emit()
                         } else {
-                            self.report_concrete_failure(origin, sub, sup).emit()
+                            self.report_concrete_failure(generic_param_scope, origin, sub, sup)
+                                .emit()
                         }
                     }
 
@@ -488,12 +501,29 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         _,
                     ) => {
                         if sub_r.is_placeholder() {
-                            self.report_placeholder_failure(sub_origin, sub_r, sup_r).emit()
+                            self.report_placeholder_failure(
+                                generic_param_scope,
+                                sub_origin,
+                                sub_r,
+                                sup_r,
+                            )
+                            .emit()
                         } else if sup_r.is_placeholder() {
-                            self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit()
+                            self.report_placeholder_failure(
+                                generic_param_scope,
+                                sup_origin,
+                                sub_r,
+                                sup_r,
+                            )
+                            .emit()
                         } else {
                             self.report_sub_sup_conflict(
-                                var_origin, sub_origin, sub_r, sup_origin, sup_r,
+                                generic_param_scope,
+                                var_origin,
+                                sub_origin,
+                                sub_r,
+                                sup_origin,
+                                sup_r,
                             )
                         }
                     }
@@ -514,7 +544,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         // value.
                         let sub_r = self.tcx.lifetimes.re_erased;
 
-                        self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit()
+                        self.report_placeholder_failure(
+                            generic_param_scope,
+                            sup_origin,
+                            sub_r,
+                            sup_r,
+                        )
+                        .emit()
                     }
 
                     RegionResolutionError::CannotNormalize(clause, origin) => {
@@ -526,7 +562,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                             .emit()
                     }
                 }
-            })
+            };
+
+            guar = Some(e)
         }
 
         guar.unwrap()
@@ -2347,7 +2385,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         '_explain: {
             let (description, span) = match sub.kind() {
                 ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::ReStatic => {
-                    msg_span_from_named_region(self.tcx, sub, Some(span))
+                    msg_span_from_named_region(self.tcx, generic_param_scope, sub, Some(span))
                 }
                 _ => (format!("lifetime `{sub}`"), Some(span)),
             };
@@ -2398,7 +2436,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             let suggestion_scope = {
                 let lifetime_scope = match sub.kind() {
                     ty::ReStatic => hir::def_id::CRATE_DEF_ID,
-                    _ => match self.tcx.is_suitable_region(sub) {
+                    _ => match self.tcx.is_suitable_region(generic_param_scope, sub) {
                         Some(info) => info.def_id,
                         None => generic_param_scope,
                     },
@@ -2410,7 +2448,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             };
 
             let mut suggs = vec![];
-            let lt_name = self.suggest_name_region(sub, &mut suggs);
+            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
@@ -2455,6 +2493,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 
     pub fn suggest_name_region(
         &self,
+        generic_param_scope: LocalDefId,
         lifetime: Region<'tcx>,
         add_lt_suggs: &mut Vec<(Span, String)>,
     ) -> String {
@@ -2501,12 +2540,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             }
         }
 
-        let (lifetime_def_id, lifetime_scope) = match self.tcx.is_suitable_region(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 (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);
@@ -2557,6 +2597,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 
     fn report_sub_sup_conflict(
         &self,
+        generic_param_scope: LocalDefId,
         var_origin: RegionVariableOrigin,
         sub_origin: SubregionOrigin<'tcx>,
         sub_region: Region<'tcx>,
@@ -2568,6 +2609,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         note_and_explain_region(
             self.tcx,
             &mut err,
+            generic_param_scope,
             "first, the lifetime cannot outlive ",
             sup_region,
             "...",
@@ -2590,6 +2632,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             note_and_explain_region(
                 self.tcx,
                 &mut err,
+                generic_param_scope,
                 "...but the lifetime must also be valid for ",
                 sub_region,
                 "...",
@@ -2613,6 +2656,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         note_and_explain_region(
             self.tcx,
             &mut err,
+            generic_param_scope,
             "but, the lifetime must be valid for ",
             sub_region,
             "...",
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
index 84bfa5b5af7..cbeec591960 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
@@ -13,6 +13,7 @@ use crate::infer::TyCtxt;
 
 use rustc_errors::Subdiagnostic;
 use rustc_errors::{Diag, ErrorGuaranteed};
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::Ty;
 use rustc_middle::ty::Region;
 
@@ -66,17 +67,17 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         }
 
         // Determine whether the sub and sup consist of both anonymous (elided) regions.
-        let anon_reg_sup = self.tcx().is_suitable_region(sup)?;
+        let anon_reg_sup = self.tcx().is_suitable_region(self.generic_param_scope, sup)?;
 
-        let anon_reg_sub = self.tcx().is_suitable_region(sub)?;
+        let anon_reg_sub = self.tcx().is_suitable_region(self.generic_param_scope, sub)?;
         let scope_def_id_sup = anon_reg_sup.def_id;
         let bregion_sup = anon_reg_sup.bound_region;
         let scope_def_id_sub = anon_reg_sub.def_id;
         let bregion_sub = anon_reg_sub.bound_region;
 
-        let ty_sup = find_anon_type(self.tcx(), sup, &bregion_sup)?;
+        let ty_sup = find_anon_type(self.tcx(), self.generic_param_scope, sup, &bregion_sup)?;
 
-        let ty_sub = find_anon_type(self.tcx(), sub, &bregion_sub)?;
+        let ty_sub = find_anon_type(self.tcx(), self.generic_param_scope, sub, &bregion_sub)?;
 
         debug!(
             "try_report_anon_anon_conflict: found_param1={:?} sup={:?} br1={:?}",
@@ -127,8 +128,14 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             },
         };
 
-        let suggestion =
-            AddLifetimeParamsSuggestion { tcx: self.tcx(), sub, ty_sup, ty_sub, add_note: true };
+        let suggestion = AddLifetimeParamsSuggestion {
+            tcx: self.tcx(),
+            sub,
+            ty_sup,
+            ty_sub,
+            add_note: true,
+            generic_param_scope: self.generic_param_scope,
+        };
         let err = LifetimeMismatch { span, labels, suggestion };
         let reported = self.tcx().dcx().emit_err(err);
         Some(reported)
@@ -139,11 +146,19 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
 /// removed in favour of public_errors::AddLifetimeParamsSuggestion
 pub fn suggest_adding_lifetime_params<'tcx>(
     tcx: TyCtxt<'tcx>,
+    err: &mut Diag<'_>,
+    generic_param_scope: LocalDefId,
     sub: Region<'tcx>,
     ty_sup: &'tcx Ty<'_>,
     ty_sub: &'tcx Ty<'_>,
-    err: &mut Diag<'_>,
 ) {
-    let suggestion = AddLifetimeParamsSuggestion { tcx, sub, ty_sup, ty_sub, add_note: false };
+    let suggestion = AddLifetimeParamsSuggestion {
+        tcx,
+        sub,
+        ty_sup,
+        ty_sub,
+        add_note: false,
+        generic_param_scope,
+    };
     suggestion.add_to_diag(err);
 }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
index 265a315a559..b91b755d683 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
@@ -1,5 +1,6 @@
 use core::ops::ControlFlow;
 use rustc_hir as hir;
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter;
@@ -23,10 +24,11 @@ use rustc_middle::ty::{self, Region, TyCtxt};
 /// for e.g., `&u8` and `Vec<&u8>`.
 pub fn find_anon_type<'tcx>(
     tcx: TyCtxt<'tcx>,
+    generic_param_scope: LocalDefId,
     region: Region<'tcx>,
     br: &ty::BoundRegionKind,
 ) -> Option<(&'tcx hir::Ty<'tcx>, &'tcx hir::FnSig<'tcx>)> {
-    let anon_reg = tcx.is_suitable_region(region)?;
+    let anon_reg = tcx.is_suitable_region(generic_param_scope, region)?;
     let fn_sig = tcx.hir_node_by_def_id(anon_reg.def_id).fn_sig()?;
 
     fn_sig
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
index 45dce0a0e33..7996b4bf65b 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
@@ -57,6 +57,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
 
         let expl = note_and_explain::RegionExplanation::new(
             self.tcx(),
+            self.generic_param_scope,
             sup,
             Some(binding_span),
             note_and_explain::PrefixKind::Empty,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
index 62c163f0b7f..cffdfa88752 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
@@ -2,6 +2,7 @@ use crate::infer::error_reporting::TypeErrCtxt;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
 use crate::infer::lexical_region_resolve::RegionResolutionError::*;
 use rustc_errors::{Diag, ErrorGuaranteed};
+use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::Span;
 
@@ -23,30 +24,39 @@ pub use util::find_param_with_region;
 impl<'cx, 'tcx> TypeErrCtxt<'cx, 'tcx> {
     pub fn try_report_nice_region_error(
         &'cx self,
+        generic_param_scope: LocalDefId,
         error: &RegionResolutionError<'tcx>,
     ) -> Option<ErrorGuaranteed> {
-        NiceRegionError::new(self, error.clone()).try_report()
+        NiceRegionError::new(self, generic_param_scope, error.clone()).try_report()
     }
 }
 
 pub struct NiceRegionError<'cx, 'tcx> {
     cx: &'cx TypeErrCtxt<'cx, 'tcx>,
+    /// The innermost definition that introduces generic parameters that may be involved in
+    /// the region errors we are dealing with.
+    generic_param_scope: LocalDefId,
     error: Option<RegionResolutionError<'tcx>>,
     regions: Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)>,
 }
 
 impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> {
-    pub fn new(cx: &'cx TypeErrCtxt<'cx, 'tcx>, error: RegionResolutionError<'tcx>) -> Self {
-        Self { cx, error: Some(error), regions: None }
+    pub fn new(
+        cx: &'cx TypeErrCtxt<'cx, 'tcx>,
+        generic_param_scope: LocalDefId,
+        error: RegionResolutionError<'tcx>,
+    ) -> Self {
+        Self { cx, error: Some(error), regions: None, generic_param_scope }
     }
 
     pub fn new_from_span(
         cx: &'cx TypeErrCtxt<'cx, 'tcx>,
+        generic_param_scope: LocalDefId,
         span: Span,
         sub: ty::Region<'tcx>,
         sup: ty::Region<'tcx>,
     ) -> Self {
-        Self { cx, error: None, regions: Some((span, sub, sup)) }
+        Self { cx, error: None, regions: Some((span, sub, sup)), generic_param_scope }
     }
 
     fn tcx(&self) -> TyCtxt<'tcx> {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
index 239c2db30e2..29da12e7d15 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
@@ -27,12 +27,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         // version new_ty of its type where the anonymous region is replaced
         // with the named one.
         let (named, anon, anon_param_info, region_info) = if sub.has_name()
-            && let Some(region_info) = self.tcx().is_suitable_region(sup)
+            && let Some(region_info) = self.tcx().is_suitable_region(self.generic_param_scope, sup)
             && let Some(anon_param_info) = self.find_param_with_region(sup, sub)
         {
             (sub, sup, anon_param_info, region_info)
         } else if sup.has_name()
-            && let Some(region_info) = self.tcx().is_suitable_region(sub)
+            && let Some(region_info) = self.tcx().is_suitable_region(self.generic_param_scope, sub)
             && let Some(anon_param_info) = self.find_param_with_region(sub, sup)
         {
             (sup, sub, anon_param_info, region_info)
@@ -72,7 +72,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             return None;
         }
 
-        if find_anon_type(self.tcx(), anon, &br).is_some()
+        if find_anon_type(self.tcx(), self.generic_param_scope, anon, &br).is_some()
             && self.is_self_anon(is_first, scope_def_id)
         {
             return None;
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index 8a1e3a7ac71..71a86683c21 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -49,7 +49,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                 if let ObligationCauseCode::UnifyReceiver(ctxt) = cause.code() {
                     // This may have a closure and it would cause ICE
                     // through `find_param_with_region` (#78262).
-                    let anon_reg_sup = tcx.is_suitable_region(*sup_r)?;
+                    let anon_reg_sup = tcx.is_suitable_region(self.generic_param_scope, *sup_r)?;
                     let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
                     if fn_returns.is_empty() {
                         return None;
@@ -92,7 +92,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",
             var_origin, sub_origin, sub_r, sup_origin, sup_r
         );
-        let anon_reg_sup = tcx.is_suitable_region(*sup_r)?;
+        let anon_reg_sup = tcx.is_suitable_region(self.generic_param_scope, *sup_r)?;
         debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);
         let sp = var_origin.span();
         let return_sp = sub_origin.span();
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
index f1f8314661f..5f3f1081ca8 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
@@ -37,13 +37,15 @@ pub struct AnonymousParamInfo<'tcx> {
 #[instrument(skip(tcx), level = "debug")]
 pub fn find_param_with_region<'tcx>(
     tcx: TyCtxt<'tcx>,
+    generic_param_scope: LocalDefId,
     anon_region: Region<'tcx>,
     replace_region: Region<'tcx>,
 ) -> Option<AnonymousParamInfo<'tcx>> {
     let (id, bound_region) = match *anon_region {
         ty::ReLateParam(late_param) => (late_param.scope, late_param.bound_region),
         ty::ReEarlyParam(ebr) => {
-            (tcx.parent(ebr.def_id), ty::BoundRegionKind::BrNamed(ebr.def_id, ebr.name))
+            let region_def = tcx.generics_of(generic_param_scope).region_param(ebr, tcx).def_id;
+            (tcx.parent(region_def), ty::BoundRegionKind::BrNamed(region_def, ebr.name))
         }
         _ => return None, // not a free region
     };
@@ -53,7 +55,7 @@ pub fn find_param_with_region<'tcx>(
 
     // FIXME: use def_kind
     // Don't perform this on closures
-    match tcx.hir_node_by_def_id(def_id) {
+    match tcx.hir_node_by_def_id(generic_param_scope) {
         hir::Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
             return None;
         }
@@ -110,7 +112,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         anon_region: Region<'tcx>,
         replace_region: Region<'tcx>,
     ) -> Option<AnonymousParamInfo<'tcx>> {
-        find_param_with_region(self.tcx(), anon_region, replace_region)
+        find_param_with_region(self.tcx(), self.generic_param_scope, anon_region, replace_region)
     }
 
     // Here, we check for the case where the anonymous region
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index 00dd20a2cc2..acb74f8a82c 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -75,6 +75,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 
     pub(super) fn report_concrete_failure(
         &self,
+        generic_param_scope: LocalDefId,
         origin: SubregionOrigin<'tcx>,
         sub: Region<'tcx>,
         sup: Region<'tcx>,
@@ -89,6 +90,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         note_and_explain_region(
                             self.tcx,
                             &mut err,
+                            generic_param_scope,
                             "",
                             sup,
                             " doesn't meet the lifetime requirements",
@@ -99,6 +101,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         note_and_explain_region(
                             self.tcx,
                             &mut err,
+                            generic_param_scope,
                             "the required lifetime does not necessarily outlive ",
                             sub,
                             "",
@@ -106,10 +109,19 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         );
                     }
                     _ => {
-                        note_and_explain_region(self.tcx, &mut err, "", sup, "...", 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,
                             "",
@@ -122,6 +134,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             infer::Reborrow(span) => {
                 let reference_valid = note_and_explain::RegionExplanation::new(
                     self.tcx,
+                    generic_param_scope,
                     sub,
                     None,
                     note_and_explain::PrefixKind::RefValidFor,
@@ -129,6 +142,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 );
                 let content_valid = note_and_explain::RegionExplanation::new(
                     self.tcx,
+                    generic_param_scope,
                     sup,
                     None,
                     note_and_explain::PrefixKind::ContentValidFor,
@@ -142,6 +156,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             infer::RelateObjectBound(span) => {
                 let object_valid = note_and_explain::RegionExplanation::new(
                     self.tcx,
+                    generic_param_scope,
                     sub,
                     None,
                     note_and_explain::PrefixKind::TypeObjValidFor,
@@ -149,6 +164,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 );
                 let pointer_valid = note_and_explain::RegionExplanation::new(
                     self.tcx,
+                    generic_param_scope,
                     sup,
                     None,
                     note_and_explain::PrefixKind::SourcePointerValidFor,
@@ -170,7 +186,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     note_and_explain::SuffixKind::Empty
                 };
                 let note = note_and_explain::RegionExplanation::new(
-                    self.tcx, sub, opt_span, prefix, suffix,
+                    self.tcx,
+                    generic_param_scope,
+                    sub,
+                    opt_span,
+                    prefix,
+                    suffix,
                 );
                 self.dcx().create_err(FulfillReqLifetime {
                     span,
@@ -181,6 +202,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             infer::RelateRegionParamBound(span) => {
                 let param_instantiated = note_and_explain::RegionExplanation::new(
                     self.tcx,
+                    generic_param_scope,
                     sup,
                     None,
                     note_and_explain::PrefixKind::LfParamInstantiatedWith,
@@ -188,6 +210,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 );
                 let param_must_outlive = note_and_explain::RegionExplanation::new(
                     self.tcx,
+                    generic_param_scope,
                     sub,
                     None,
                     note_and_explain::PrefixKind::LfParamMustOutlive,
@@ -201,6 +224,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             infer::ReferenceOutlivesReferent(ty, span) => {
                 let pointer_valid = note_and_explain::RegionExplanation::new(
                     self.tcx,
+                    generic_param_scope,
                     sub,
                     None,
                     note_and_explain::PrefixKind::PointerValidFor,
@@ -208,6 +232,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 );
                 let data_valid = note_and_explain::RegionExplanation::new(
                     self.tcx,
+                    generic_param_scope,
                     sup,
                     None,
                     note_and_explain::PrefixKind::DataValidFor,
@@ -239,7 +264,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 err
             }
             infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
-                let mut err = self.report_concrete_failure(*parent, sub, sup);
+                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.
@@ -262,6 +287,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             infer::AscribeUserTypeProvePredicate(span) => {
                 let instantiated = note_and_explain::RegionExplanation::new(
                     self.tcx,
+                    generic_param_scope,
                     sup,
                     None,
                     note_and_explain::PrefixKind::LfInstantiatedWith,
@@ -269,6 +295,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 );
                 let must_outlive = note_and_explain::RegionExplanation::new(
                     self.tcx,
+                    generic_param_scope,
                     sub,
                     None,
                     note_and_explain::PrefixKind::LfMustOutlive,
@@ -347,6 +374,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 
     pub(super) fn report_placeholder_failure(
         &self,
+        generic_param_scope: LocalDefId,
         placeholder_origin: SubregionOrigin<'tcx>,
         sub: Region<'tcx>,
         sup: Region<'tcx>,
@@ -368,7 +396,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     && !span.is_dummy()
                 {
                     let span = *span;
-                    self.report_concrete_failure(placeholder_origin, sub, sup)
+                    self.report_concrete_failure(generic_param_scope, placeholder_origin, sub, sup)
                         .with_span_note(span, "the lifetime requirement is introduced here")
                 } else {
                     unreachable!(
@@ -380,7 +408,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 let terr = TypeError::RegionsPlaceholderMismatch;
                 return self.report_and_explain_type_error(trace, terr);
             }
-            _ => return self.report_concrete_failure(placeholder_origin, sub, sup),
+            _ => {
+                return self.report_concrete_failure(
+                    generic_param_scope,
+                    placeholder_origin,
+                    sub,
+                    sup,
+                );
+            }
         }
     }
 }
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 85d54ce563d..0129b8f842f 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1950,14 +1950,22 @@ declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMEN
 
 impl ExplicitOutlivesRequirements {
     fn lifetimes_outliving_lifetime<'tcx>(
+        tcx: TyCtxt<'tcx>,
         inferred_outlives: &'tcx [(ty::Clause<'tcx>, Span)],
-        def_id: DefId,
+        item: DefId,
+        lifetime: DefId,
     ) -> Vec<ty::Region<'tcx>> {
+        let item_generics = tcx.generics_of(item);
+
         inferred_outlives
             .iter()
             .filter_map(|(clause, _)| match clause.kind().skip_binder() {
                 ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a {
-                    ty::ReEarlyParam(ebr) if ebr.def_id == def_id => Some(b),
+                    ty::ReEarlyParam(ebr)
+                        if item_generics.region_param(ebr, tcx).def_id == lifetime =>
+                    {
+                        Some(b)
+                    }
                     _ => None,
                 },
                 _ => None,
@@ -1986,6 +1994,7 @@ impl ExplicitOutlivesRequirements {
         bounds: &hir::GenericBounds<'_>,
         inferred_outlives: &[ty::Region<'tcx>],
         predicate_span: Span,
+        item: DefId,
     ) -> Vec<(usize, Span)> {
         use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
 
@@ -2000,7 +2009,7 @@ impl ExplicitOutlivesRequirements {
                 let is_inferred = match tcx.named_bound_var(lifetime.hir_id) {
                     Some(ResolvedArg::EarlyBound(def_id)) => inferred_outlives
                         .iter()
-                        .any(|r| matches!(**r, ty::ReEarlyParam(ebr) if { ebr.def_id == def_id })),
+                        .any(|r| matches!(**r, ty::ReEarlyParam(ebr) if { tcx.generics_of(item).region_param(ebr, tcx).def_id == def_id })),
                     _ => false,
                 };
 
@@ -2109,7 +2118,9 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
                             {
                                 (
                                     Self::lifetimes_outliving_lifetime(
+                                        cx.tcx,
                                         inferred_outlives,
+                                        item.owner_id.to_def_id(),
                                         region_def_id,
                                     ),
                                     &predicate.bounds,
@@ -2152,6 +2163,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
                     bounds,
                     &relevant_lifetimes,
                     predicate_span,
+                    item.owner_id.to_def_id(),
                 );
                 bound_count += bound_spans.len();
 
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 6e53b5bb520..318a18715e4 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1488,13 +1488,14 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     /// Returns the `DefId` and the `BoundRegionKind` corresponding to the given region.
-    pub fn is_suitable_region(self, mut region: Region<'tcx>) -> Option<FreeRegionInfo> {
+    pub fn is_suitable_region(
+        self,
+        generic_param_scope: LocalDefId,
+        mut region: Region<'tcx>,
+    ) -> Option<FreeRegionInfo> {
         let (suitable_region_binding_scope, bound_region) = loop {
-            let def_id = match region.kind() {
-                ty::ReLateParam(fr) => fr.bound_region.get_id()?.as_local()?,
-                ty::ReEarlyParam(ebr) => ebr.def_id.as_local()?,
-                _ => return None, // not a free region
-            };
+            let def_id =
+                region.opt_param_def_id(self, generic_param_scope.to_def_id())?.as_local()?;
             let scope = self.local_parent(def_id);
             if self.def_kind(scope) == DefKind::OpaqueTy {
                 // Lifetime params of opaque types are synthetic and thus irrelevant to
@@ -2633,7 +2634,6 @@ impl<'tcx> TyCtxt<'tcx> {
                     return ty::Region::new_early_param(
                         self,
                         ty::EarlyParamRegion {
-                            def_id: ebv,
                             index: generics
                                 .param_def_id_to_index(self, ebv)
                                 .expect("early-bound var should be present in fn generics"),
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 870e4865aea..8fdff40024b 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -66,7 +66,7 @@ pub struct GenericParamDef {
 impl GenericParamDef {
     pub fn to_early_bound_region_data(&self) -> ty::EarlyParamRegion {
         if let GenericParamDefKind::Lifetime = self.kind {
-            ty::EarlyParamRegion { def_id: self.def_id, index: self.index, name: self.name }
+            ty::EarlyParamRegion { index: self.index, name: self.name }
         } else {
             bug!("cannot convert a non-lifetime parameter def to an early bound region")
         }
diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs
index 0e07ef31c26..0807cbf91d1 100644
--- a/compiler/rustc_middle/src/ty/region.rs
+++ b/compiler/rustc_middle/src/ty/region.rs
@@ -265,33 +265,6 @@ impl<'tcx> Region<'tcx> {
         flags
     }
 
-    /// Given an early-bound or free region, returns the `DefId` where it was bound.
-    /// For example, consider the regions in this snippet of code:
-    ///
-    /// ```ignore (illustrative)
-    /// impl<'a> Foo {
-    /// //   ^^ -- early bound, declared on an impl
-    ///
-    ///     fn bar<'b, 'c>(x: &self, y: &'b u32, z: &'c u64) where 'static: 'c
-    /// //         ^^  ^^     ^ anonymous, late-bound
-    /// //         |   early-bound, appears in where-clauses
-    /// //         late-bound, appears only in fn args
-    ///     {..}
-    /// }
-    /// ```
-    ///
-    /// Here, `free_region_binding_scope('a)` would return the `DefId`
-    /// of the impl, and for all the other highlighted regions, it
-    /// would return the `DefId` of the function. In other cases (not shown), this
-    /// function might return the `DefId` of a closure.
-    pub fn free_region_binding_scope(self, tcx: TyCtxt<'_>) -> DefId {
-        match *self {
-            ty::ReEarlyParam(br) => tcx.parent(br.def_id),
-            ty::ReLateParam(fr) => fr.scope,
-            _ => bug!("free_region_binding_scope invoked on inappropriate region: {:?}", self),
-        }
-    }
-
     /// True for free regions other than `'static`.
     pub fn is_param(self) -> bool {
         matches!(*self, ty::ReEarlyParam(_) | ty::ReLateParam(_))
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
index be20924670c..233cfd79288 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -771,7 +771,7 @@ impl<'tcx> Stable<'tcx> for ty::RegionKind<'tcx> {
         use stable_mir::ty::{BoundRegion, EarlyParamRegion, RegionKind};
         match self {
             ty::ReEarlyParam(early_reg) => RegionKind::ReEarlyParam(EarlyParamRegion {
-                def_id: tables.region_def(early_reg.def_id),
+                def_id: tables.region_def(todo!()),
                 index: early_reg.index,
                 name: early_reg.name.to_string(),
             }),
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 204bb487c86..e35b8e9fe7d 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -185,6 +185,7 @@ fn do_normalize_predicates<'tcx>(
     predicates: Vec<ty::Clause<'tcx>>,
 ) -> Result<Vec<ty::Clause<'tcx>>, ErrorGuaranteed> {
     let span = cause.span;
+
     // FIXME. We should really... do something with these region
     // obligations. But this call just continues the older
     // behavior (i.e., doesn't cause any new bugs), and it would
diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs
index e87058f9ba4..6f71951b516 100644
--- a/compiler/rustc_ty_utils/src/implied_bounds.rs
+++ b/compiler/rustc_ty_utils/src/implied_bounds.rs
@@ -79,11 +79,7 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<'
                                 orig_lt,
                                 ty::Region::new_early_param(
                                     tcx,
-                                    ty::EarlyParamRegion {
-                                        def_id: param.def_id,
-                                        index: param.index,
-                                        name: param.name,
-                                    },
+                                    ty::EarlyParamRegion { index: param.index, name: param.name },
                                 ),
                             );
                         }
diff --git a/tests/ui/nll/ty-outlives/impl-trait-captures.stderr b/tests/ui/nll/ty-outlives/impl-trait-captures.stderr
index 3893cdf482e..48569d1446d 100644
--- a/tests/ui/nll/ty-outlives/impl-trait-captures.stderr
+++ b/tests/ui/nll/ty-outlives/impl-trait-captures.stderr
@@ -1,4 +1,4 @@
-error[E0700]: hidden type for `Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), [DefId(0:9 ~ impl_trait_captures[aeb9]::foo::'a)_'a/#0, T, DefId(0:9 ~ impl_trait_captures[aeb9]::foo::'a)_'a/#0])` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), ['a/#0, T, 'a/#0])` captures lifetime that does not appear in bounds
   --> $DIR/impl-trait-captures.rs:11:5
    |
 LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
@@ -8,7 +8,7 @@ LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
 LL |     x
    |     ^
    |
-help: to declare that `Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), [DefId(0:9 ~ impl_trait_captures[aeb9]::foo::'a)_'a/#0, T, DefId(0:14 ~ impl_trait_captures[aeb9]::foo::{opaque#0}::'a)_'a/#2])` captures `ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))`, you can add an explicit `ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))` lifetime bound
+help: to declare that `Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), ['a/#0, T, 'a/#2])` captures `ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))`, you can add an explicit `ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))` lifetime bound
    |
 LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_)) {
    |                                      +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++