Rollup merge of #67595 - ohadravid:impl-trait-does-not-live-long-enough, r=estebank
Suggest adding a lifetime constraint for opaque type Fixes #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
This commit is contained in:
commit
76c1454d27
13 changed files with 89 additions and 16 deletions
|
@ -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,
|
||||
),
|
||||
|
|
|
@ -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 rustc_span::symbol::Symbol;
|
||||
use rustc_span::Span;
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
@ -815,7 +815,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),
|
||||
|
|
11
src/test/ui/impl-trait/does-not-live-long-enough.rs
Normal file
11
src/test/ui/impl-trait/does-not-live-long-enough.rs
Normal file
|
@ -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
src/test/ui/impl-trait/does-not-live-long-enough.stderr
Normal file
21
src/test/ui/impl-trait/does-not-live-long-enough.stderr
Normal file
|
@ -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`.
|
|
@ -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
|
||||
|
|
||||
|
|
|
@ -6,7 +6,7 @@ LL | fn elided(x: &i32) -> impl Copy { x }
|
|||
| |
|
||||
| let's call the lifetime of this reference `'1`
|
||||
|
|
||||
help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a constraint
|
||||
help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound
|
||||
|
|
||||
LL | fn elided(x: &i32) -> impl Copy + '_ { x }
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
@ -20,7 +20,7 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
|
|||
| lifetime `'a` defined here
|
||||
|
|
||||
= 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 | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
|
@ -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 }
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
@ -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 }
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
@ -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 }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -6,7 +6,7 @@ LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
|
|||
| |
|
||||
| let's call the lifetime of this reference `'1`
|
||||
|
|
||||
help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a constraint
|
||||
help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound
|
||||
|
|
||||
LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -20,7 +20,7 @@ LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
|
|||
| lifetime `'a` defined here
|
||||
|
|
||||
= 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 | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -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> + '_ {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -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 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -6,7 +6,7 @@ LL | async fn f(self: Pin<&Self>) -> impl Clone { self }
|
|||
| |
|
||||
| let's call the lifetime of this reference `'1`
|
||||
|
|
||||
help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a constraint
|
||||
help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound
|
||||
|
|
||||
LL | async fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -6,7 +6,7 @@ LL | fn f(self: Pin<&Self>) -> impl Clone { self }
|
|||
| |
|
||||
| let's call the lifetime of this reference `'1`
|
||||
|
|
||||
help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a constraint
|
||||
help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound
|
||||
|
|
||||
LL | fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -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 }
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue