From 00e314d5edb735baef84c314c8c1a53587911887 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Mon, 17 Oct 2022 22:08:15 -0400 Subject: Add an optional Span to BrAnon and use it to print better error for HRTB error from generator interior --- .../generic-associated-types/bugs/issue-100013.rs | 22 +++++++++++++++++++++ .../bugs/issue-100013.stderr | 23 ++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 src/test/ui/generic-associated-types/bugs/issue-100013.rs create mode 100644 src/test/ui/generic-associated-types/bugs/issue-100013.stderr (limited to 'src/test/ui') 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..f995591d76c --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/issue-100013.rs @@ -0,0 +1,22 @@ +// 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_2() -> impl Send { + async { // a generator checked for autotrait impl `Send` + //~^ lifetime bound not satisfied + let x = None::>; // 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..11d149faa8f --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/issue-100013.stderr @@ -0,0 +1,23 @@ +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::>; // 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::>; // a type referencing GAT + | ^^ +note: ...must outlive the lifetime defined here + --> $DIR/issue-100013.rs:17:34 + | +LL | let x = None::>; // a type referencing GAT + | ^^ + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From cececca7c7fdae8730027615c2e89120e40bac66 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Tue, 18 Oct 2022 20:08:13 -0400 Subject: Get spans for a couple more region types, add some optimizations, and extend test --- .../rustc_hir_typeck/src/generator_interior/mod.rs | 82 +++++++++++++--------- .../nice_region_error/placeholder_relation.rs | 2 +- .../generic-associated-types/bugs/issue-100013.rs | 19 ++++- .../bugs/issue-100013.stderr | 60 +++++++++++++++- 4 files changed, 126 insertions(+), 37 deletions(-) (limited to 'src/test/ui') 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 = 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() -> impl Send { +fn call() -> impl Send { async { // a generator checked for autotrait impl `Send` //~^ lifetime bound not satisfied let x = None::>; // a type referencing GAT @@ -19,4 +19,21 @@ fn call_2() -> 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::>; // 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::>; // 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::>; // a type referencing GAT @@ -19,5 +19,61 @@ note: ...must outlive the lifetime defined here LL | let x = None::>; // 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::>; // 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::>; // 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::>; // 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 -- cgit 1.4.1-3-g733a5 From 3c71fafd6d515004ebfd041d125338b6b82fddf9 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Mon, 7 Nov 2022 17:52:08 -0500 Subject: Add a known that this is a known limitation --- .../infer/error_reporting/nice_region_error/placeholder_relation.rs | 1 + src/test/ui/generic-associated-types/bugs/issue-100013.stderr | 3 +++ 2 files changed, 4 insertions(+) (limited to 'src/test/ui') 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 d0813ccd3b4..c42240f2172 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 @@ -69,6 +69,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { } _ => {} } + err.note("this is a known limitation that will be removed in the future (see issue #100013 for more information)"); Some(err) } 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 d9fcf8c48e2..72ae288dcab 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-100013.stderr +++ b/src/test/ui/generic-associated-types/bugs/issue-100013.stderr @@ -18,6 +18,7 @@ note: ...must outlive the lifetime defined here | LL | let x = None::>; // a type referencing GAT | ^^ + = note: this is a known limitation that will be removed in the future (see issue #100013 for more information) error: lifetime bound not satisfied --> $DIR/issue-100013.rs:23:5 @@ -40,6 +41,7 @@ note: ...must outlive the lifetime defined here | 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 for more information) error: lifetime may not live long enough --> $DIR/issue-100013.rs:25:17 @@ -74,6 +76,7 @@ note: ...must outlive the lifetime defined here | 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 for more information) error: aborting due to 4 previous errors -- cgit 1.4.1-3-g733a5