Skip to content

Commit

Permalink
Point at capture points for non-'static reference crossing a `yield…
Browse files Browse the repository at this point in the history
…` point

```
error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
  --> $DIR/issue-72312.rs:10:24
   |
LL |     pub async fn start(&self) {
   |                        ^^^^^ this data with an anonymous lifetime `'_`...
...
LL |         require_static(async move {
   |         -------------- ...is required to live as long as `'static` here...
LL |             &self;
   |             ----- ...and is captured here
   |
note: `'static` lifetime requirement introduced by this trait bound
  --> $DIR/issue-72312.rs:2:22
   |
LL | fn require_static<T: 'static>(val: T) -> T {
   |                      ^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0759`.
```

Fix #72312.
  • Loading branch information
estebank committed Dec 10, 2021
1 parent e6b883c commit d10fe26
Show file tree
Hide file tree
Showing 12 changed files with 212 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
error_region,
cause.clone(),
placeholder_region,
vec![],
),
),
(Some(error_region), _) => NiceRegionError::new(
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
sub_r,
sup_origin,
sup_r,
_,
) => {
if sub_r.is_placeholder() {
self.report_placeholder_failure(sub_origin, sub_r, sup_r).emit();
Expand Down Expand Up @@ -464,7 +465,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
errors.sort_by_key(|u| match *u {
RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(),
RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(),
RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _) => rvo.span(),
RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _, _) => rvo.span(),
RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(),
});
errors
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> {
pub fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> {
match (&self.error, self.regions) {
(Some(ConcreteFailure(origin, sub, sup)), None) => Some((origin.span(), sub, sup)),
(Some(SubSupConflict(_, _, origin, sub, _, sup)), None) => {
(Some(SubSupConflict(_, _, origin, sub, _, sup, _)), None) => {
Some((origin.span(), sub, sup))
}
(None, Some((span, sub, sup))) => Some((span, sub, sup)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ impl NiceRegionError<'me, 'tcx> {
sub_placeholder @ ty::RePlaceholder(_),
_,
sup_placeholder @ ty::RePlaceholder(_),
_,
)) => self.try_report_trait_placeholder_mismatch(
Some(self.tcx().mk_region(ty::ReVar(*vid))),
cause,
Expand All @@ -49,6 +50,7 @@ impl NiceRegionError<'me, 'tcx> {
sub_placeholder @ ty::RePlaceholder(_),
_,
_,
_,
)) => self.try_report_trait_placeholder_mismatch(
Some(self.tcx().mk_region(ty::ReVar(*vid))),
cause,
Expand All @@ -64,6 +66,7 @@ impl NiceRegionError<'me, 'tcx> {
_,
_,
sup_placeholder @ ty::RePlaceholder(_),
_,
)) => self.try_report_trait_placeholder_mismatch(
Some(self.tcx().mk_region(ty::ReVar(*vid))),
cause,
Expand All @@ -79,6 +82,7 @@ impl NiceRegionError<'me, 'tcx> {
_,
SubregionOrigin::Subtype(box TypeTrace { cause, values }),
sup_placeholder @ ty::RePlaceholder(_),
_,
)) => self.try_report_trait_placeholder_mismatch(
Some(self.tcx().mk_region(ty::ReVar(*vid))),
cause,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,17 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
debug!("try_report_static_impl_trait(error={:?})", self.error);
let tcx = self.tcx();
let (var_origin, sub_origin, sub_r, sup_origin, sup_r) = match self.error.as_ref()? {
let (var_origin, sub_origin, sub_r, sup_origin, sup_r, spans) = match self.error.as_ref()? {
RegionResolutionError::SubSupConflict(
_,
var_origin,
sub_origin,
sub_r,
sup_origin,
sup_r,
spans,
) if **sub_r == RegionKind::ReStatic => {
(var_origin, sub_origin, sub_r, sup_origin, sup_r)
(var_origin, sub_origin, sub_r, sup_origin, sup_r, spans)
}
RegionResolutionError::ConcreteFailure(
SubregionOrigin::Subtype(box TypeTrace { cause, .. }),
Expand Down Expand Up @@ -123,15 +124,31 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
param_name,
lifetime,
);
err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));

let (mention_capture, capture_point) = if sup_origin.span().overlaps(param.param_ty_span) {
// Account for `async fn` like in `async-await/issues/issue-62097.rs`.
// The desugaring of `async `fn`s causes `sup_origin` and `param` to point at the same
// place (but with different `ctxt`, hence `overlaps` instead of `==` above).
//
// This avoids the following:
//
// LL | pub async fn run_dummy_fn(&self) {
// | ^^^^^
// | |
// | this data with an anonymous lifetime `'_`...
// | ...is captured here...
(false, sup_origin.span())
} else {
(true, param.param_ty_span)
};
err.span_label(capture_point, &format!("this data with {}...", lifetime));

debug!("try_report_static_impl_trait: param_info={:?}", param);

// We try to make the output have fewer overlapping spans if possible.
if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
&& sup_origin.span() != return_sp
{
// FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`

// Customize the spans and labels depending on their relative order so
// that split sentences flow correctly.
if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {
Expand All @@ -152,29 +169,61 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
// | ---- ^
err.span_label(
sup_origin.span(),
"...is captured here, requiring it to live as long as `'static`",
&format!(
"...is captured here, requiring it to live as long as `'static`{}",
if spans.is_empty() { "" } else { "..." },
),
);
} else {
err.span_label(sup_origin.span(), "...is captured here...");
if return_sp < sup_origin.span() {
if return_sp < sup_origin.span() && mention_capture {
err.span_label(sup_origin.span(), "...is captured here...");
err.span_note(
return_sp,
"...and is required to live as long as `'static` here",
);
} else {
err.span_label(
return_sp,
"...and is required to live as long as `'static` here",
&format!(
"...is required to live as long as `'static` here{}",
if spans.is_empty() { "" } else { "..." },
),
);
if mention_capture {
let span = sup_origin.span();
let msg = if spans.iter().any(|sp| *sp > span) {
"...is captured here..."
} else {
"...and is captured here"
};
err.span_label(span, msg);
}
}
}
} else {
err.span_label(
return_sp,
"...is captured and required to live as long as `'static` here",
&format!(
"...is captured and required to live as long as `'static` here{}",
if spans.is_empty() { "" } else { "..." },
),
);
}

for span in spans {
let msg =
format!("...and is captured here{}", if mention_capture { " too" } else { "" });
if span.overlaps(return_sp) {
err.span_note(*span, &msg);
} else {
err.span_label(*span, &msg);
}
}

if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin {
err.span_note(*bound, "`'static` lifetime requirement introduced by this trait bound");
}

let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id);

let mut override_error_code = None;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
_sub,
sup_origin,
_sup,
_,
) = error.clone()
{
if let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) = (&sup_origin, &sub_origin) {
Expand Down
32 changes: 28 additions & 4 deletions compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
use rustc_middle::ty::{ReLateBound, RePlaceholder, ReVar};
use rustc_middle::ty::{Region, RegionVid};
use rustc_span::Span;
use std::fmt;

/// This function performs lexical region resolution given a complete
Expand Down Expand Up @@ -96,6 +97,7 @@ pub enum RegionResolutionError<'tcx> {
Region<'tcx>,
SubregionOrigin<'tcx>,
Region<'tcx>,
Vec<Span>,
),

/// Indicates a `'b: 'a` constraint where `'a` is in a universe that
Expand Down Expand Up @@ -144,8 +146,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
let graph = self.construct_graph();
self.expand_givens(&graph);
self.expansion(&mut var_data);
self.collect_errors(&mut var_data, errors);
self.collect_var_errors(&var_data, &graph, errors);
let captures = self.collect_errors(&mut var_data, errors);
self.collect_var_errors(&var_data, &graph, errors, captures);
var_data
}

Expand Down Expand Up @@ -443,9 +445,16 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
&self,
var_data: &mut LexicalRegionResolutions<'tcx>,
errors: &mut Vec<RegionResolutionError<'tcx>>,
) {
) -> Vec<Span> {
let mut captures = vec![];

for (constraint, origin) in &self.data.constraints {
debug!(?constraint, ?origin);
if let (Constraint::VarSubVar(_, _), SubregionOrigin::DataBorrowed(_, sp)) =
(constraint, origin)
{
captures.push(*sp);
}
match *constraint {
Constraint::RegSubVar(..) | Constraint::VarSubVar(..) => {
// Expansion will ensure that these constraints hold. Ignore.
Expand Down Expand Up @@ -515,6 +524,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
sub,
));
}
captures
}

/// Go over the variables that were declared to be error variables
Expand All @@ -524,6 +534,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
var_data: &LexicalRegionResolutions<'tcx>,
graph: &RegionGraph<'tcx>,
errors: &mut Vec<RegionResolutionError<'tcx>>,
captures: Vec<Span>,
) {
debug!("collect_var_errors, var_data = {:#?}", var_data.values);

Expand Down Expand Up @@ -567,7 +578,13 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
// if this rule starts to create problems we'll
// have to revisit this portion of the code and
// think hard about it. =) -- nikomatsakis
self.collect_error_for_expanding_node(graph, &mut dup_vec, node_vid, errors);
self.collect_error_for_expanding_node(
graph,
&mut dup_vec,
node_vid,
errors,
&captures,
);
}
}
}
Expand Down Expand Up @@ -621,6 +638,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
dup_vec: &mut IndexVec<RegionVid, Option<RegionVid>>,
node_idx: RegionVid,
errors: &mut Vec<RegionResolutionError<'tcx>>,
captures: &[Span],
) {
// Errors in expanding nodes result from a lower-bound that is
// not contained by an upper-bound.
Expand Down Expand Up @@ -667,13 +685,19 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
sup: {:?}",
origin, node_idx, lower_bound.region, upper_bound.region
);

let mut capture_spans: Vec<Span> = captures.iter().cloned().collect();
// Below, one span expects `&Span` and the other `&mut Span`, hence the dupes.
capture_spans.sort_by_key(|span| (span.lo(), span.hi()));
capture_spans.dedup_by_key(|span| (span.lo(), span.hi()));
errors.push(RegionResolutionError::SubSupConflict(
node_idx,
origin,
lower_bound.origin.clone(),
lower_bound.region,
upper_bound.origin.clone(),
upper_bound.region,
capture_spans,
));
return;
}
Expand Down
18 changes: 13 additions & 5 deletions src/test/ui/async-await/issues/issue-62097.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,20 @@ error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'
--> $DIR/issue-62097.rs:12:31
|
LL | pub async fn run_dummy_fn(&self) {
| ^^^^^
| |
| this data with an anonymous lifetime `'_`...
| ...is captured here...
| ^^^^^ this data with an anonymous lifetime `'_`...
LL | foo(|| self.bar()).await;
| --- ...and is required to live as long as `'static` here
| --- ...is required to live as long as `'static` here...
|
note: ...and is captured here
--> $DIR/issue-62097.rs:13:9
|
LL | foo(|| self.bar()).await;
| ^^^^^^^^^^^^^^^^^^^^^^^^
note: `'static` lifetime requirement introduced by this trait bound
--> $DIR/issue-62097.rs:4:19
|
LL | F: FnOnce() + 'static
| ^^^^^^^

error: aborting due to previous error

Expand Down
19 changes: 19 additions & 0 deletions src/test/ui/async-await/issues/issue-72312.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// edition:2018
fn require_static<T: 'static>(val: T) -> T {
//~^ NOTE 'static` lifetime requirement introduced by this trait bound
val
}

struct Problem;

impl Problem {
pub async fn start(&self) { //~ ERROR E0759
//~^ NOTE this data with an anonymous lifetime `'_`
//~| NOTE in this expansion of desugaring of `async` block or function
require_static(async move { //~ NOTE ...is required to live as long as `'static` here
&self; //~ NOTE ...and is captured here
});
}
}

fn main() {}
20 changes: 20 additions & 0 deletions src/test/ui/async-await/issues/issue-72312.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/issue-72312.rs:10:24
|
LL | pub async fn start(&self) {
| ^^^^^ this data with an anonymous lifetime `'_`...
...
LL | require_static(async move {
| -------------- ...is required to live as long as `'static` here...
LL | &self;
| ----- ...and is captured here
|
note: `'static` lifetime requirement introduced by this trait bound
--> $DIR/issue-72312.rs:2:22
|
LL | fn require_static<T: 'static>(val: T) -> T {
| ^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0759`.
18 changes: 18 additions & 0 deletions src/test/ui/traits/trait-upcasting/type-checking-test-4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,22 @@ fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
y.get_b() // ERROR
}

fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
<_ as Bar>::get_b(x) // ERROR
//~^ ERROR `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
}

fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
<_ as Bar<'_, '_>>::get_b(x) // ERROR
//~^ ERROR `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
}

fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
let y = x as &dyn Bar<'_, '_>;
//~^ ERROR `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
y.get_b(); // ERROR
let z = y;
z.get_b() // ERROR
}

fn main() {}
Loading

0 comments on commit d10fe26

Please sign in to comment.