about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/mod.rs82
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs2
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-100013.rs19
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-100013.stderr60
4 files changed, 126 insertions, 37 deletions
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
index 06f6d840990..7bbfb70f2c3 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
@@ -15,9 +15,11 @@ 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::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;
 
@@ -226,6 +228,12 @@ pub fn resolve_interior<'a, 'tcx>(
             // 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 ty = fcx.tcx.fold_regions(ty, |region, current_depth| {
                 let br = match region.kind() {
@@ -233,25 +241,24 @@ pub fn resolve_interior<'a, 'tcx>(
                         let origin = fcx.region_var_origin(vid);
                         match origin {
                             RegionVariableOrigin::EarlyBoundRegion(span, _) => {
-                                let kind = ty::BrAnon(counter, Some(span));
-                                let var = ty::BoundVar::from_u32(counter);
-                                counter += 1;
-                                ty::BoundRegion { var, kind }
-                            }
-                            _ => {
-                                let kind = ty::BrAnon(counter, None);
-                                let var = ty::BoundVar::from_u32(counter);
-                                counter += 1;
-                                ty::BoundRegion { var, kind }
+                                mk_bound_region(Some(span))
                             }
+                            _ => mk_bound_region(None),
                         }
                     }
-                    _ => {
-                        let kind = ty::BrAnon(counter, None);
-                        let var = ty::BoundVar::from_u32(counter);
-                        counter += 1;
-                        ty::BoundRegion { var, kind }
+                    // 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
@@ -265,25 +272,34 @@ pub fn resolve_interior<'a, 'tcx>(
         })
         .collect();
 
-    let mut bound_vars: Vec<BoundVariableKind> = vec![];
+    let mut bound_vars: SmallVec<[BoundVariableKind; 4]> = smallvec![];
     let mut counter = 0;
-    let type_causes = fcx.tcx.fold_regions(type_causes, |region, current_depth| {
-        let br = match region.kind() {
-            ty::ReLateBound(_, 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;
-                ty::BoundRegion { var, kind }
-            }
-            _ => bug!("All regions should have been replaced by ReLateBound"),
-        };
-        let r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, br));
-        r
-    });
+    // 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));
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
index 7f39de1944f..d0813ccd3b4 100644
--- 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
@@ -61,7 +61,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
                         );
                     }
                     (Some(sub_span), Some(sup_span), _, _) => {
-                        err.span_note(sub_span, format!("the lifetime defined here, ..."));
+                        err.span_note(sub_span, format!("the lifetime defined here..."));
                         err.span_note(
                             sup_span,
                             format!("...must outlive the lifetime defined here"),
diff --git a/src/test/ui/generic-associated-types/bugs/issue-100013.rs b/src/test/ui/generic-associated-types/bugs/issue-100013.rs
index f995591d76c..fc4e47a3ba1 100644
--- a/src/test/ui/generic-associated-types/bugs/issue-100013.rs
+++ b/src/test/ui/generic-associated-types/bugs/issue-100013.rs
@@ -11,7 +11,7 @@ pub trait FutureIterator {
         's: 'cx;
 }
 
-fn call_2<I: FutureIterator>() -> impl Send {
+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
@@ -19,4 +19,21 @@ fn call_2<I: FutureIterator>() -> impl Send {
     }
 }
 
+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
index 11d149faa8f..d9fcf8c48e2 100644
--- a/src/test/ui/generic-associated-types/bugs/issue-100013.stderr
+++ b/src/test/ui/generic-associated-types/bugs/issue-100013.stderr
@@ -8,7 +8,7 @@ LL | |         async {}.await; // a yield point
 LL | |     }
    | |_____^
    |
-note: the lifetime defined here, ...
+note: the lifetime defined here...
   --> $DIR/issue-100013.rs:17:38
    |
 LL |         let x = None::<I::Future<'_, '_>>; // a type referencing GAT
@@ -19,5 +19,61 @@ note: ...must outlive the lifetime defined here
 LL |         let x = None::<I::Future<'_, '_>>; // a type referencing GAT
    |                                  ^^
 
-error: aborting due to previous error
+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 {
+   |          ^^
+
+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 {
+   |          ^^
+
+error: aborting due to 4 previous errors