about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-11-09 02:02:28 +0000
committerbors <bors@rust-lang.org>2022-11-09 02:02:28 +0000
commitbc2504a83ca6ee8f6717dedd0721b90ffcbe1300 (patch)
treecfd1232fd2173c2caded2006c6919a99b88bf526
parent8d36948b1519c77a54867523453fef3e0c3a648b (diff)
parent3c71fafd6d515004ebfd041d125338b6b82fddf9 (diff)
downloadrust-bc2504a83ca6ee8f6717dedd0721b90ffcbe1300.tar.gz
rust-bc2504a83ca6ee8f6717dedd0721b90ffcbe1300.zip
Auto merge of #103171 - jackh726:gen-interior-hrtb-error, r=cjgillot
Better error for HRTB error from generator interior

cc #100013

This is just a first pass at an error. It could be better, and shouldn't really be emitted in the first place. But this is better than what was being emitted before.
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs3
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs17
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/mod.rs104
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs1
-rw-r--r--compiler/rustc_infer/src/errors/note_and_explain.rs7
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs7
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs5
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs79
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs6
-rw-r--r--compiler/rustc_middle/src/ty/fold.rs8
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs8
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs2
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs2
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs1
-rw-r--r--compiler/rustc_traits/src/chalk/db.rs2
-rw-r--r--compiler/rustc_traits/src/chalk/lowering.rs20
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-100013.rs39
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-100013.stderr82
23 files changed, 344 insertions, 63 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
index dac6abe37f5..897a161f785 100644
--- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
@@ -158,6 +158,7 @@ trait TypeOpInfo<'tcx> {
         error_region: Option<ty::Region<'tcx>>,
     ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>;
 
+    #[instrument(level = "debug", skip(self, mbcx))]
     fn report_error(
         &self,
         mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
@@ -167,6 +168,7 @@ trait TypeOpInfo<'tcx> {
     ) {
         let tcx = mbcx.infcx.tcx;
         let base_universe = self.base_universe();
+        debug!(?base_universe);
 
         let Some(adjusted_universe) =
             placeholder.universe.as_u32().checked_sub(base_universe.as_u32())
@@ -389,6 +391,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>,
     placeholder_region: ty::Region<'tcx>,
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index c044dbaba47..f9741bacd17 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -355,7 +355,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                     })
                 }
 
-                ty::BoundRegionKind::BrAnon(_) => None,
+                ty::BoundRegionKind::BrAnon(..) => None,
             },
 
             ty::ReLateBound(..) | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReErased => None,
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 2665813478c..4518cf30acd 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -2980,7 +2980,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     ) {
         for br in referenced_regions.difference(&constrained_regions) {
             let br_name = match *br {
-                ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) | ty::BrEnv => {
+                ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) | ty::BrEnv => {
                     "an anonymous lifetime".to_string()
                 }
                 ty::BrNamed(_, name) => format!("lifetime `{}`", name),
@@ -2988,7 +2988,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
             let mut err = generate_err(&br_name);
 
-            if let ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) = *br {
+            if let ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) = *br {
                 // The only way for an anonymous lifetime to wind up
                 // in the return type but **also** be unconstrained is
                 // if it only appears in "associated types" in the
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 609095c9cea..69e54b41d4c 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -134,15 +134,18 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
     let name_str = intrinsic_name.as_str();
 
     let bound_vars = tcx.mk_bound_variable_kinds(
-        [ty::BoundVariableKind::Region(ty::BrAnon(0)), ty::BoundVariableKind::Region(ty::BrEnv)]
-            .iter()
-            .copied(),
+        [
+            ty::BoundVariableKind::Region(ty::BrAnon(0, None)),
+            ty::BoundVariableKind::Region(ty::BrEnv),
+        ]
+        .iter()
+        .copied(),
     );
     let mk_va_list_ty = |mutbl| {
         tcx.lang_items().va_list().map(|did| {
             let region = tcx.mk_region(ty::ReLateBound(
                 ty::INNERMOST,
-                ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) },
+                ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) },
             ));
             let env_region = tcx.mk_region(ty::ReLateBound(
                 ty::INNERMOST,
@@ -364,7 +367,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
                 );
                 let discriminant_def_id = assoc_items[0];
 
-                let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) };
+                let br =
+                    ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) };
                 (
                     1,
                     vec![
@@ -418,7 +422,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             sym::nontemporal_store => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
 
             sym::raw_eq => {
-                let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) };
+                let br =
+                    ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) };
                 let param_ty =
                     tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)), param(0));
                 (1, vec![param_ty; 2], tcx.types.bool)
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
index b7dd599cd43..7bbfb70f2c3 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
@@ -13,10 +13,13 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::hir_id::HirIdSet;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
+use rustc_infer::infer::RegionVariableOrigin;
 use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData};
-use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::fold::FnMutDelegate;
+use rustc_middle::ty::{self, BoundVariableKind, RvalueScopes, Ty, TyCtxt, TypeVisitable};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
+use smallvec::{smallvec, SmallVec};
 
 mod drop_ranges;
 
@@ -211,31 +214,57 @@ pub fn resolve_interior<'a, 'tcx>(
 
     debug!("types in generator {:?}, span = {:?}", types, body.value.span);
 
-    let mut counter = 0;
+    // We want to deduplicate if the lifetimes are the same modulo some non-informative counter.
+    // So, we need to actually do two passes: first by type to anonymize (preserving information
+    // required for diagnostics), then a second pass over all captured types to reassign disjoint
+    // region indices.
     let mut captured_tys = FxHashSet::default();
     let type_causes: Vec<_> = types
         .into_iter()
         .filter_map(|mut cause| {
-            // Erase regions and canonicalize late-bound regions to deduplicate as many types as we
-            // can.
+            // Replace all regions inside the generator interior with late bound regions.
+            // Note that each region slot in the types gets a new fresh late bound region,
+            // which means that none of the regions inside relate to any other, even if
+            // typeck had previously found constraints that would cause them to be related.
+
+            let mut counter = 0;
+            let mut mk_bound_region = |span| {
+                let kind = ty::BrAnon(counter, span);
+                let var = ty::BoundVar::from_u32(counter);
+                counter += 1;
+                ty::BoundRegion { var, kind }
+            };
             let ty = fcx.normalize_associated_types_in(cause.span, cause.ty);
-            let erased = fcx.tcx.erase_regions(ty);
-            if captured_tys.insert(erased) {
-                // Replace all regions inside the generator interior with late bound regions.
-                // Note that each region slot in the types gets a new fresh late bound region,
-                // which means that none of the regions inside relate to any other, even if
-                // typeck had previously found constraints that would cause them to be related.
-                let folded = fcx.tcx.fold_regions(erased, |_, current_depth| {
-                    let br = ty::BoundRegion {
-                        var: ty::BoundVar::from_u32(counter),
-                        kind: ty::BrAnon(counter),
-                    };
-                    let r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, br));
-                    counter += 1;
-                    r
-                });
-
-                cause.ty = folded;
+            let ty = fcx.tcx.fold_regions(ty, |region, current_depth| {
+                let br = match region.kind() {
+                    ty::ReVar(vid) => {
+                        let origin = fcx.region_var_origin(vid);
+                        match origin {
+                            RegionVariableOrigin::EarlyBoundRegion(span, _) => {
+                                mk_bound_region(Some(span))
+                            }
+                            _ => mk_bound_region(None),
+                        }
+                    }
+                    // FIXME: these should use `BrNamed`
+                    ty::ReEarlyBound(region) => {
+                        mk_bound_region(Some(fcx.tcx.def_span(region.def_id)))
+                    }
+                    ty::ReLateBound(_, ty::BoundRegion { kind, .. })
+                    | ty::ReFree(ty::FreeRegion { bound_region: kind, .. }) => match kind {
+                        ty::BoundRegionKind::BrAnon(_, span) => mk_bound_region(span),
+                        ty::BoundRegionKind::BrNamed(def_id, _) => {
+                            mk_bound_region(Some(fcx.tcx.def_span(def_id)))
+                        }
+                        ty::BoundRegionKind::BrEnv => mk_bound_region(None),
+                    },
+                    _ => mk_bound_region(None),
+                };
+                let r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, br));
+                r
+            });
+            if captured_tys.insert(ty) {
+                cause.ty = ty;
                 Some(cause)
             } else {
                 None
@@ -243,11 +272,38 @@ pub fn resolve_interior<'a, 'tcx>(
         })
         .collect();
 
+    let mut bound_vars: SmallVec<[BoundVariableKind; 4]> = smallvec![];
+    let mut counter = 0;
+    // Optimization: If there is only one captured type, then we don't actually
+    // need to fold and reindex (since the first type doesn't change).
+    let type_causes = if captured_tys.len() > 0 {
+        // Optimization: Use `replace_escaping_bound_vars_uncached` instead of
+        // `fold_regions`, since we only have late bound regions, and it skips
+        // types without bound regions.
+        fcx.tcx.replace_escaping_bound_vars_uncached(
+            type_causes,
+            FnMutDelegate {
+                regions: &mut |br| {
+                    let kind = match br.kind {
+                        ty::BrAnon(_, span) => ty::BrAnon(counter, span),
+                        _ => br.kind,
+                    };
+                    let var = ty::BoundVar::from_usize(bound_vars.len());
+                    bound_vars.push(ty::BoundVariableKind::Region(kind));
+                    counter += 1;
+                    fcx.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var, kind }))
+                },
+                types: &mut |b| bug!("unexpected bound ty in binder: {b:?}"),
+                consts: &mut |b, ty| bug!("unexpected bound ct in binder: {b:?} {ty}"),
+            },
+        )
+    } else {
+        type_causes
+    };
+
     // Extract type components to build the witness type.
     let type_list = fcx.tcx.mk_type_list(type_causes.iter().map(|cause| cause.ty));
-    let bound_vars = fcx.tcx.mk_bound_variable_kinds(
-        (0..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i))),
-    );
+    let bound_vars = fcx.tcx.mk_bound_variable_kinds(bound_vars.iter());
     let witness =
         fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars.clone()));
 
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 052fdef2fc5..183e80f2e08 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -209,6 +209,7 @@ fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::T
     typeck_with_fallback(tcx, def_id, fallback)
 }
 
+#[instrument(level = "debug", skip(tcx, fallback), ret)]
 fn typeck_with_fallback<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: LocalDefId,
diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs
index 6a29d85627a..7aaa5ce2f42 100644
--- a/compiler/rustc_infer/src/errors/note_and_explain.rs
+++ b/compiler/rustc_infer/src/errors/note_and_explain.rs
@@ -89,10 +89,13 @@ impl<'a> DescriptionCtx<'a> {
                             };
                             me.span = Some(sp);
                         }
-                        ty::BrAnon(idx) => {
+                        ty::BrAnon(idx, span) => {
                             me.kind = "anon_num_here";
                             me.num_arg = idx+1;
-                            me.span = Some(tcx.def_span(scope));
+                            me.span = match span {
+                                Some(_) => span,
+                                None => Some(tcx.def_span(scope)),
+                            }
                         },
                         _ => {
                             me.kind = "defined_here_reg";
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index aa44d582fd6..3dc0d60b1eb 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -738,7 +738,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
         r: ty::Region<'tcx>,
     ) -> ty::Region<'tcx> {
         let var = self.canonical_var(info, r.into());
-        let br = ty::BoundRegion { var, kind: ty::BrAnon(var.as_u32()) };
+        let br = ty::BoundRegion { var, kind: ty::BrAnon(var.as_u32(), None) };
         let region = ty::ReLateBound(self.binder_index, br);
         self.tcx().mk_region(region)
     }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 3dbc9b9f3f9..61519454a2c 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -207,9 +207,12 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>(
                         };
                         (text, sp)
                     }
-                    ty::BrAnon(idx) => (
+                    ty::BrAnon(idx, span) => (
                         format!("the anonymous lifetime #{} defined here", idx + 1),
-                        tcx.def_span(scope)
+                        match span {
+                            Some(span) => span,
+                            None => tcx.def_span(scope)
+                        }
                     ),
                     _ => (
                         format!("the lifetime `{}` as defined here", region),
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 aaf5a7af00a..8a0e332f9c7 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
@@ -10,6 +10,7 @@ pub mod find_anon_type;
 mod mismatched_static_lifetime;
 mod named_anon_conflict;
 mod placeholder_error;
+mod placeholder_relation;
 mod static_impl_trait;
 mod trait_impl_difference;
 mod util;
@@ -52,7 +53,9 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> {
     pub fn try_report_from_nll(&self) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
         // Due to the improved diagnostics returned by the MIR borrow checker, only a subset of
         // the nice region errors are required when running under the MIR borrow checker.
-        self.try_report_named_anon_conflict().or_else(|| self.try_report_placeholder_conflict())
+        self.try_report_named_anon_conflict()
+            .or_else(|| self.try_report_placeholder_conflict())
+            .or_else(|| self.try_report_placeholder_relation())
     }
 
     pub fn try_report(&self) -> Option<ErrorGuaranteed> {
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 76cb76d9ff4..3fe7c1598fc 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
@@ -68,7 +68,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         let is_impl_item = region_info.is_impl_item;
 
         match br {
-            ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) => {}
+            ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) => {}
             _ => {
                 /* not an anonymous region */
                 debug!("try_report_named_anon_conflict: not an anonymous region");
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs
new file mode 100644
index 00000000000..c42240f2172
--- /dev/null
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs
@@ -0,0 +1,79 @@
+use crate::infer::{
+    error_reporting::nice_region_error::NiceRegionError, RegionResolutionError, SubregionOrigin,
+};
+use rustc_data_structures::intern::Interned;
+use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
+use rustc_middle::ty::{self, RePlaceholder, Region};
+
+impl<'tcx> NiceRegionError<'_, 'tcx> {
+    /// Emitted wwhen given a `ConcreteFailure` when relating two placeholders.
+    pub(super) fn try_report_placeholder_relation(
+        &self,
+    ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
+        match &self.error {
+            Some(RegionResolutionError::ConcreteFailure(
+                SubregionOrigin::RelateRegionParamBound(span),
+                Region(Interned(RePlaceholder(ty::Placeholder { name: sub_name, .. }), _)),
+                Region(Interned(RePlaceholder(ty::Placeholder { name: sup_name, .. }), _)),
+            )) => {
+                let msg = "lifetime bound not satisfied";
+                let mut err = self.tcx().sess.struct_span_err(*span, msg);
+                let (sub_span, sub_symbol) = match sub_name {
+                    ty::BrNamed(def_id, symbol) => {
+                        (Some(self.tcx().def_span(def_id)), Some(symbol))
+                    }
+                    ty::BrAnon(_, span) => (*span, None),
+                    ty::BrEnv => (None, None),
+                };
+                let (sup_span, sup_symbol) = match sup_name {
+                    ty::BrNamed(def_id, symbol) => {
+                        (Some(self.tcx().def_span(def_id)), Some(symbol))
+                    }
+                    ty::BrAnon(_, span) => (*span, None),
+                    ty::BrEnv => (None, None),
+                };
+                match (sub_span, sup_span, sub_symbol, sup_symbol) {
+                    (Some(sub_span), Some(sup_span), Some(sub_symbol), Some(sup_symbol)) => {
+                        err.span_note(
+                            sub_span,
+                            format!("the lifetime `{sub_symbol}` defined here..."),
+                        );
+                        err.span_note(
+                            sup_span,
+                            format!("...must outlive the lifetime `{sup_symbol}` defined here"),
+                        );
+                    }
+                    (Some(sub_span), Some(sup_span), _, Some(sup_symbol)) => {
+                        err.span_note(sub_span, format!("the lifetime defined here..."));
+                        err.span_note(
+                            sup_span,
+                            format!("...must outlive the lifetime `{sup_symbol}` defined here"),
+                        );
+                    }
+                    (Some(sub_span), Some(sup_span), Some(sub_symbol), _) => {
+                        err.span_note(
+                            sub_span,
+                            format!("the lifetime `{sub_symbol}` defined here..."),
+                        );
+                        err.span_note(
+                            sup_span,
+                            format!("...must outlive the lifetime defined here"),
+                        );
+                    }
+                    (Some(sub_span), Some(sup_span), _, _) => {
+                        err.span_note(sub_span, format!("the lifetime defined here..."));
+                        err.span_note(
+                            sup_span,
+                            format!("...must outlive the lifetime defined here"),
+                        );
+                    }
+                    _ => {}
+                }
+                err.note("this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)");
+                Some(err)
+            }
+
+            _ => None,
+        }
+    }
+}
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index 8d1ed4b2a52..0331d764b38 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -336,8 +336,10 @@ impl<'tcx> CanonicalVarValues<'tcx> {
                         tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i).into())).into()
                     }
                     GenericArgKind::Lifetime(..) => {
-                        let br =
-                            ty::BoundRegion { var: ty::BoundVar::from_u32(i), kind: ty::BrAnon(i) };
+                        let br = ty::BoundRegion {
+                            var: ty::BoundVar::from_u32(i),
+                            kind: ty::BrAnon(i, None),
+                        };
                         tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
                     }
                     GenericArgKind::Const(ct) => tcx
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index a329753726e..2842b3c3102 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -598,7 +598,7 @@ impl<'tcx> TyCtxt<'tcx> {
             .replace_late_bound_regions(sig, |_| {
                 let br = ty::BoundRegion {
                     var: ty::BoundVar::from_u32(counter),
-                    kind: ty::BrAnon(counter),
+                    kind: ty::BrAnon(counter, None),
                 };
                 let r = self.mk_region(ty::ReLateBound(ty::INNERMOST, br));
                 counter += 1;
@@ -606,7 +606,7 @@ impl<'tcx> TyCtxt<'tcx> {
             })
             .0;
         let bound_vars = self.mk_bound_variable_kinds(
-            (0..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i))),
+            (0..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i, None))),
         );
         Binder::bind_with_vars(inner, bound_vars)
     }
@@ -626,7 +626,9 @@ impl<'tcx> TyCtxt<'tcx> {
                 let index = entry.index();
                 let var = ty::BoundVar::from_usize(index);
                 let kind = entry
-                    .or_insert_with(|| ty::BoundVariableKind::Region(ty::BrAnon(index as u32)))
+                    .or_insert_with(|| {
+                        ty::BoundVariableKind::Region(ty::BrAnon(index as u32, None))
+                    })
                     .expect_region();
                 let br = ty::BoundRegion { var, kind };
                 self.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br))
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index fab85c39d25..c8815537835 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -2115,7 +2115,7 @@ impl<'a, 'tcx> ty::TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
                 // If this is an anonymous placeholder, don't rename. Otherwise, in some
                 // async fns, we get a `for<'r> Send` bound
                 match kind {
-                    ty::BrAnon(_) | ty::BrEnv => r,
+                    ty::BrAnon(..) | ty::BrEnv => r,
                     _ => {
                         // Index doesn't matter, since this is just for naming and these never get bound
                         let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind };
@@ -2226,10 +2226,10 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
                     let ty::BoundVariableKind::Region(var) = var else {
                     // This doesn't really matter because it doesn't get used,
                     // it's just an empty value
-                    return ty::BrAnon(0);
+                    return ty::BrAnon(0, None);
                 };
                     match var {
-                        ty::BrAnon(_) | ty::BrEnv => {
+                        ty::BrAnon(..) | ty::BrEnv => {
                             start_or_continue(&mut self, "for<", ", ");
                             let name = next_name(&self);
                             debug!(?name);
@@ -2271,7 +2271,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
                             binder_level_idx: ty::DebruijnIndex,
                             br: ty::BoundRegion| {
                 let (name, kind) = match br.kind {
-                    ty::BrAnon(_) | ty::BrEnv => {
+                    ty::BrAnon(..) | ty::BrEnv => {
                         let name = next_name(&self);
 
                         if let Some(lt_idx) = lifetime_idx {
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index f2070869ce0..9f0598d0ba8 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -68,7 +68,7 @@ impl<'tcx> fmt::Debug for ty::adjustment::Adjustment<'tcx> {
 impl fmt::Debug for ty::BoundRegionKind {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
-            ty::BrAnon(n) => write!(f, "BrAnon({:?})", n),
+            ty::BrAnon(n, span) => write!(f, "BrAnon({n:?}, {span:?})"),
             ty::BrNamed(did, name) => {
                 if did.is_crate_root() {
                     write!(f, "BrNamed({})", name)
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 5f108bf0ef3..49d82b503a4 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -59,7 +59,7 @@ pub struct FreeRegion {
 #[derive(HashStable)]
 pub enum BoundRegionKind {
     /// An anonymous region parameter for a given fn (&T)
-    BrAnon(u32),
+    BrAnon(u32, Option<Span>),
 
     /// Named region parameters for functions (a in &'a T)
     ///
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 2109b3c2496..e540e2f2a21 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -218,7 +218,7 @@ impl<'tcx> SymbolMangler<'tcx> {
         let lifetimes = regions
             .into_iter()
             .map(|br| match br {
-                ty::BrAnon(i) => i,
+                ty::BrAnon(i, _) => i,
                 _ => bug!("symbol_names: non-anonymized region `{:?}` in `{:?}`", br, value),
             })
             .max()
@@ -335,7 +335,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
 
             // Late-bound lifetimes use indices starting at 1,
             // see `BinderLevel` for more details.
-            ty::ReLateBound(debruijn, ty::BoundRegion { kind: ty::BrAnon(i), .. }) => {
+            ty::ReLateBound(debruijn, ty::BoundRegion { kind: ty::BrAnon(i, _), .. }) => {
                 let binder = &self.binders[self.binders.len() - 1 - debruijn.index()];
                 let depth = binder.lifetime_depths.start + i;
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 2954a2c163f..c6ff83120a7 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1971,6 +1971,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     /// Bar<i32> where struct Bar<T> { x: T, y: u32 } -> [i32, u32]
     /// Zed<i32> where enum Zed { A(T), B(u32) } -> [i32, u32]
     /// ```
+    #[instrument(level = "debug", skip(self), ret)]
     fn constituent_types_for_ty(
         &self,
         t: ty::Binder<'tcx, Ty<'tcx>>,
diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs
index 2035252fe39..07f92299f72 100644
--- a/compiler/rustc_traits/src/chalk/db.rs
+++ b/compiler/rustc_traits/src/chalk/db.rs
@@ -728,7 +728,7 @@ fn bound_vars_for_item<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx
         ty::GenericParamDefKind::Lifetime => {
             let br = ty::BoundRegion {
                 var: ty::BoundVar::from_usize(substs.len()),
-                kind: ty::BrAnon(substs.len() as u32),
+                kind: ty::BrAnon(substs.len() as u32, None),
             };
             tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
         }
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index 0492e94b94e..b64d53e60de 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -498,13 +498,13 @@ impl<'tcx> LowerInto<'tcx, Region<'tcx>> for &chalk_ir::Lifetime<RustInterner<'t
                 ty::DebruijnIndex::from_u32(var.debruijn.depth()),
                 ty::BoundRegion {
                     var: ty::BoundVar::from_usize(var.index),
-                    kind: ty::BrAnon(var.index as u32),
+                    kind: ty::BrAnon(var.index as u32, None),
                 },
             ),
             chalk_ir::LifetimeData::InferenceVar(_var) => unimplemented!(),
             chalk_ir::LifetimeData::Placeholder(p) => ty::RePlaceholder(ty::Placeholder {
                 universe: ty::UniverseIndex::from_usize(p.ui.counter),
-                name: ty::BoundRegionKind::BrAnon(p.idx as u32),
+                name: ty::BoundRegionKind::BrAnon(p.idx as u32, None),
             }),
             chalk_ir::LifetimeData::Static => return interner.tcx.lifetimes.re_static,
             chalk_ir::LifetimeData::Empty(_) => {
@@ -933,7 +933,7 @@ impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
                     }
                 }
 
-                ty::BoundRegionKind::BrAnon(var) => match self.parameters.entry(var) {
+                ty::BoundRegionKind::BrAnon(var, _) => match self.parameters.entry(var) {
                     Entry::Vacant(entry) => {
                         entry.insert(chalk_ir::VariableKind::Lifetime);
                     }
@@ -991,13 +991,13 @@ impl<'a, 'tcx> TypeFolder<'tcx> for NamedBoundVarSubstitutor<'a, 'tcx> {
             ty::ReLateBound(index, br) if index == self.binder_index => match br.kind {
                 ty::BrNamed(def_id, _name) => match self.named_parameters.get(&def_id) {
                     Some(idx) => {
-                        let new_br = ty::BoundRegion { var: br.var, kind: ty::BrAnon(*idx) };
+                        let new_br = ty::BoundRegion { var: br.var, kind: ty::BrAnon(*idx, None) };
                         return self.tcx.mk_region(ty::ReLateBound(index, new_br));
                     }
                     None => panic!("Missing `BrNamed`."),
                 },
                 ty::BrEnv => unimplemented!(),
-                ty::BrAnon(_) => {}
+                ty::BrAnon(..) => {}
             },
             _ => (),
         };
@@ -1072,14 +1072,16 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> {
                 Some(idx) => {
                     let br = ty::BoundRegion {
                         var: ty::BoundVar::from_u32(*idx),
-                        kind: ty::BrAnon(*idx),
+                        kind: ty::BrAnon(*idx, None),
                     };
                     self.tcx.mk_region(ty::ReLateBound(self.binder_index, br))
                 }
                 None => {
                     let idx = self.named_regions.len() as u32;
-                    let br =
-                        ty::BoundRegion { var: ty::BoundVar::from_u32(idx), kind: ty::BrAnon(idx) };
+                    let br = ty::BoundRegion {
+                        var: ty::BoundVar::from_u32(idx),
+                        kind: ty::BrAnon(idx, None),
+                    };
                     self.named_regions.insert(_re.def_id, idx);
                     self.tcx.mk_region(ty::ReLateBound(self.binder_index, br))
                 }
@@ -1156,7 +1158,7 @@ impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector {
     fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         match *r {
             ty::RePlaceholder(p) if p.universe == self.universe_index => {
-                if let ty::BoundRegionKind::BrAnon(anon) = p.name {
+                if let ty::BoundRegionKind::BrAnon(anon, _) = p.name {
                     self.next_anon_region_placeholder = self.next_anon_region_placeholder.max(anon);
                 }
             }
diff --git a/src/test/ui/generic-associated-types/bugs/issue-100013.rs b/src/test/ui/generic-associated-types/bugs/issue-100013.rs
new file mode 100644
index 00000000000..fc4e47a3ba1
--- /dev/null
+++ b/src/test/ui/generic-associated-types/bugs/issue-100013.rs
@@ -0,0 +1,39 @@
+// check-fail
+// known-bug
+// edition: 2021
+
+// We really should accept this, but we need implied bounds between the regions
+// in a generator interior.
+
+pub trait FutureIterator {
+    type Future<'s, 'cx>: Send
+    where
+        's: 'cx;
+}
+
+fn call<I: FutureIterator>() -> impl Send {
+    async { // a generator checked for autotrait impl `Send`
+        //~^ lifetime bound not satisfied
+        let x = None::<I::Future<'_, '_>>; // a type referencing GAT
+        async {}.await; // a yield point
+    }
+}
+
+fn call2<'a, 'b, I: FutureIterator>() -> impl Send {
+    async { // a generator checked for autotrait impl `Send`
+        //~^ lifetime bound not satisfied
+        let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
+        //~^ lifetime may not live long enough
+        async {}.await; // a yield point
+    }
+}
+
+fn call3<'a: 'b, 'b, I: FutureIterator>() -> impl Send {
+    async { // a generator checked for autotrait impl `Send`
+        //~^ lifetime bound not satisfied
+        let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
+        async {}.await; // a yield point
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-100013.stderr b/src/test/ui/generic-associated-types/bugs/issue-100013.stderr
new file mode 100644
index 00000000000..72ae288dcab
--- /dev/null
+++ b/src/test/ui/generic-associated-types/bugs/issue-100013.stderr
@@ -0,0 +1,82 @@
+error: lifetime bound not satisfied
+  --> $DIR/issue-100013.rs:15:5
+   |
+LL | /     async { // a generator checked for autotrait impl `Send`
+LL | |
+LL | |         let x = None::<I::Future<'_, '_>>; // a type referencing GAT
+LL | |         async {}.await; // a yield point
+LL | |     }
+   | |_____^
+   |
+note: the lifetime defined here...
+  --> $DIR/issue-100013.rs:17:38
+   |
+LL |         let x = None::<I::Future<'_, '_>>; // a type referencing GAT
+   |                                      ^^
+note: ...must outlive the lifetime defined here
+  --> $DIR/issue-100013.rs:17:34
+   |
+LL |         let x = None::<I::Future<'_, '_>>; // a type referencing GAT
+   |                                  ^^
+   = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
+
+error: lifetime bound not satisfied
+  --> $DIR/issue-100013.rs:23:5
+   |
+LL | /     async { // a generator checked for autotrait impl `Send`
+LL | |
+LL | |         let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
+LL | |
+LL | |         async {}.await; // a yield point
+LL | |     }
+   | |_____^
+   |
+note: the lifetime defined here...
+  --> $DIR/issue-100013.rs:22:14
+   |
+LL | fn call2<'a, 'b, I: FutureIterator>() -> impl Send {
+   |              ^^
+note: ...must outlive the lifetime defined here
+  --> $DIR/issue-100013.rs:22:10
+   |
+LL | fn call2<'a, 'b, I: FutureIterator>() -> impl Send {
+   |          ^^
+   = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
+
+error: lifetime may not live long enough
+  --> $DIR/issue-100013.rs:25:17
+   |
+LL | fn call2<'a, 'b, I: FutureIterator>() -> impl Send {
+   |          --  -- lifetime `'b` defined here
+   |          |
+   |          lifetime `'a` defined here
+...
+LL |         let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'b`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+
+error: lifetime bound not satisfied
+  --> $DIR/issue-100013.rs:32:5
+   |
+LL | /     async { // a generator checked for autotrait impl `Send`
+LL | |
+LL | |         let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
+LL | |         async {}.await; // a yield point
+LL | |     }
+   | |_____^
+   |
+note: the lifetime defined here...
+  --> $DIR/issue-100013.rs:31:18
+   |
+LL | fn call3<'a: 'b, 'b, I: FutureIterator>() -> impl Send {
+   |                  ^^
+note: ...must outlive the lifetime defined here
+  --> $DIR/issue-100013.rs:31:10
+   |
+LL | fn call3<'a: 'b, 'b, I: FutureIterator>() -> impl Send {
+   |          ^^
+   = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
+
+error: aborting due to 4 previous errors
+