Skip to content

Commit

Permalink
Rollup merge of rust-lang#67595 - ohadravid:impl-trait-does-not-live-…
Browse files Browse the repository at this point in the history
…long-enough, r=estebank

Suggest adding a lifetime constraint for opaque type

Fixes rust-lang#67577, where code like this:

```
struct List {
  data: Vec<String>,
}
impl List {
  fn started_with<'a>(&'a self, prefix: &'a str) -> impl Iterator<Item=&'a str> {
    self.data.iter().filter(|s| s.starts_with(prefix)).map(|s| s.as_ref())
  }
}
```

will show this error:
```
   Compiling playground v0.0.1 (/playground)
error[E0597]: `prefix` does not live long enough
 --> src/lib.rs:6:47
  |
5 |   fn started_with<'a>(&'a self, prefix: &'a str) -> impl Iterator<Item=&'a str> {
  |                   -- lifetime `'a` defined here     --------------------------- opaque type requires that `prefix` is borrowed for `'a`
...
```

but without suggesting the lovely `help: you can add a constraint..`.

r? @estebank
  • Loading branch information
Mark-Simulacrum authored Dec 26, 2019
2 parents 5fc61ef + 3e9d1cc commit d755d79
Show file tree
Hide file tree
Showing 9 changed files with 83 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
err.span_suggestion(
fn_return_span,
&format!(
"you can add a constraint to the return type to make it last \
"you can add a bound to the return type to make it last \
less than `'static` and match {}",
lifetime,
),
Expand Down
43 changes: 42 additions & 1 deletion src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use rustc::mir::{
use rustc::ty::adjustment::PointerCast;
use rustc::ty::{self, TyCtxt};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::DiagnosticBuilder;
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_index::vec::IndexVec;
use syntax_pos::symbol::Symbol;
use syntax_pos::Span;
Expand Down Expand Up @@ -206,6 +206,47 @@ impl BorrowExplanation {
),
);
};

self.add_lifetime_bound_suggestion_to_diagnostic(
tcx,
err,
&category,
span,
region_name,
);
}
_ => {}
}
}
pub(in crate::borrow_check) fn add_lifetime_bound_suggestion_to_diagnostic<'tcx>(
&self,
tcx: TyCtxt<'tcx>,
err: &mut DiagnosticBuilder<'_>,
category: &ConstraintCategory,
span: Span,
region_name: &RegionName,
) {
match category {
ConstraintCategory::OpaqueType => {
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) {
let suggestable_name = if region_name.was_named() {
region_name.to_string()
} else {
"'_".to_string()
};

err.span_suggestion(
span,
&format!(
"you can add a bound to the {}to make it last less than \
`'static` and match `{}`",
category.description(),
region_name,
),
format!("{} + {}", snippet, suggestable_name),
Applicability::Unspecified,
);
}
}
_ => {}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/borrow_check/diagnostics/region_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -840,7 +840,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
span,
&format!(
"to allow this `impl Trait` to capture borrowed data with lifetime \
`{}`, add `{}` as a constraint",
`{}`, add `{}` as a bound",
fr_name, suggestable_fr_name,
),
format!("{} + {}", snippet, suggestable_fr_name),
Expand Down
11 changes: 11 additions & 0 deletions src/test/ui/impl-trait/does-not-live-long-enough.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
struct List {
data: Vec<String>,
}
impl List {
fn started_with<'a>(&'a self, prefix: &'a str) -> impl Iterator<Item=&'a str> {
self.data.iter().filter(|s| s.starts_with(prefix)).map(|s| s.as_ref())
//~^ ERROR does not live long enough
}
}

fn main() {}
21 changes: 21 additions & 0 deletions src/test/ui/impl-trait/does-not-live-long-enough.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error[E0597]: `prefix` does not live long enough
--> $DIR/does-not-live-long-enough.rs:6:51
|
LL | fn started_with<'a>(&'a self, prefix: &'a str) -> impl Iterator<Item=&'a str> {
| -- lifetime `'a` defined here --------------------------- opaque type requires that `prefix` is borrowed for `'a`
LL | self.data.iter().filter(|s| s.starts_with(prefix)).map(|s| s.as_ref())
| --- ^^^^^^ borrowed value does not live long enough
| |
| value captured here
LL |
LL | }
| - `prefix` dropped here while still borrowed
|
help: you can add a bound to the opaque type to make it last less than `'static` and match `'a`
|
LL | fn started_with<'a>(&'a self, prefix: &'a str) -> impl Iterator<Item=&'a str> + 'a {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0597`.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ LL | fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
| -- lifetime `'a` defined here ^^^^^^^^^ opaque type requires that `'a` must outlive `'static`
|
= help: consider replacing `'a` with `'static`
help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a constraint
help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a bound
|
LL | type E<'a, 'b> = impl Sized; + 'a
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ note: ...can't outlive the anonymous lifetime #1 defined on the function body at
|
LL | fn elided(x: &i32) -> impl Copy { x }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: you can add a constraint to the return type to make it last less than `'static` and match the anonymous lifetime #1 defined on the function body at 3:1
help: you can add a bound to the return type to make it last less than `'static` and match the anonymous lifetime #1 defined on the function body at 3:1
|
LL | fn elided(x: &i32) -> impl Copy + '_ { x }
| ^^^^^^^^^^^^^^
Expand All @@ -29,7 +29,7 @@ note: ...can't outlive the lifetime `'a` as defined on the function body at 6:13
|
LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
| ^^
help: you can add a constraint to the return type to make it last less than `'static` and match the lifetime `'a` as defined on the function body at 6:13
help: you can add a bound to the return type to make it last less than `'static` and match the lifetime `'a` as defined on the function body at 6:13
|
LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
| ^^^^^^^^^^^^^^
Expand All @@ -47,7 +47,7 @@ note: ...can't outlive the lifetime `'a` as defined on the function body at 12:1
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
| ^^
help: you can add a constraint to the return type to make it last less than `'static` and match the lifetime `'a` as defined on the function body at 12:15
help: you can add a bound to the return type to make it last less than `'static` and match the lifetime `'a` as defined on the function body at 12:15
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static + 'a { x }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/impl-trait/static-return-lifetime-infered.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ LL | / fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
LL | | self.x.iter().map(|a| a.0)
LL | | }
| |_____^
help: you can add a constraint to the return type to make it last less than `'static` and match the anonymous lifetime #1 defined on the method body at 6:5
help: you can add a bound to the return type to make it last less than `'static` and match the anonymous lifetime #1 defined on the method body at 6:5
|
LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -35,7 +35,7 @@ note: ...can't outlive the lifetime `'a` as defined on the method body at 10:20
|
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
| ^^
help: you can add a constraint to the return type to make it last less than `'static` and match the lifetime `'a` as defined on the method body at 10:20
help: you can add a bound to the return type to make it last less than `'static` and match the lifetime `'a` as defined on the method body at 10:20
|
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ note: ...can't outlive the anonymous lifetime #1 defined on the method body at 8
|
LL | fn f(self: Pin<&Self>) -> impl Clone { self }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: you can add a constraint to the return type to make it last less than `'static` and match the anonymous lifetime #1 defined on the method body at 8:5
help: you can add a bound to the return type to make it last less than `'static` and match the anonymous lifetime #1 defined on the method body at 8:5
|
LL | fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
| ^^^^^^^^^^^^^^^
Expand Down

0 comments on commit d755d79

Please sign in to comment.