From d4fbb55c9c1eba39eca81b0d73fe9edf5e3869fd Mon Sep 17 00:00:00 2001 From: Ohad Ravid Date: Tue, 24 Dec 2019 19:14:20 +0100 Subject: [PATCH 1/2] Suggest adding a lifetime constraint when opaque type is responsible for "does not live long enough" error --- .../diagnostics/explain_borrow.rs | 43 ++++++++++++++++++- .../impl-trait/does-not-live-long-enough.rs | 11 +++++ .../does-not-live-long-enough.stderr | 21 +++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/impl-trait/does-not-live-long-enough.rs create mode 100644 src/test/ui/impl-trait/does-not-live-long-enough.stderr diff --git a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs index 04f025fcbead9..05bec59ad8926 100644 --- a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs +++ b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs @@ -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; @@ -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 constraint to the {}to make it last less than \ + `'static` and match `{}`", + category.description(), + region_name, + ), + format!("{} + {}", snippet, suggestable_name), + Applicability::Unspecified, + ); + } } _ => {} } diff --git a/src/test/ui/impl-trait/does-not-live-long-enough.rs b/src/test/ui/impl-trait/does-not-live-long-enough.rs new file mode 100644 index 0000000000000..6179132b3f608 --- /dev/null +++ b/src/test/ui/impl-trait/does-not-live-long-enough.rs @@ -0,0 +1,11 @@ +struct List { + data: Vec, +} +impl List { + fn started_with<'a>(&'a self, prefix: &'a str) -> impl Iterator { + self.data.iter().filter(|s| s.starts_with(prefix)).map(|s| s.as_ref()) + //~^ ERROR does not live long enough + } +} + +fn main() {} diff --git a/src/test/ui/impl-trait/does-not-live-long-enough.stderr b/src/test/ui/impl-trait/does-not-live-long-enough.stderr new file mode 100644 index 0000000000000..ddf81138dafe7 --- /dev/null +++ b/src/test/ui/impl-trait/does-not-live-long-enough.stderr @@ -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 { + | -- 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 constraint 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 + 'a { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. From 1a4f6b85a745e9855bbad4c5fdf0806200133f1d Mon Sep 17 00:00:00 2001 From: Ohad Ravid Date: Wed, 25 Dec 2019 09:26:25 +0100 Subject: [PATCH 2/2] Change wording for lifetime suggestion for opaque types from `constraint` to `bound` --- .../error_reporting/nice_region_error/static_impl_trait.rs | 2 +- src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs | 2 +- src/librustc_mir/borrow_check/diagnostics/region_errors.rs | 2 +- src/test/ui/impl-trait/does-not-live-long-enough.stderr | 2 +- .../ui/impl-trait/multiple-lifetimes/error-handling.stderr | 2 +- .../must_outlive_least_region_or_bound.nll.stderr | 4 ++-- .../ui/impl-trait/must_outlive_least_region_or_bound.stderr | 6 +++--- .../ui/impl-trait/static-return-lifetime-infered.nll.stderr | 4 ++-- .../ui/impl-trait/static-return-lifetime-infered.stderr | 4 ++-- ...rary_self_types_pin_lifetime_impl_trait-async.nll.stderr | 2 +- .../arbitrary_self_types_pin_lifetime_impl_trait.nll.stderr | 2 +- .../arbitrary_self_types_pin_lifetime_impl_trait.stderr | 2 +- 12 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs index 8f6fbd27a58af..69ebbe1fd3679 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -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, ), diff --git a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs index 05bec59ad8926..e66708b173152 100644 --- a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs +++ b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs @@ -238,7 +238,7 @@ impl BorrowExplanation { err.span_suggestion( span, &format!( - "you can add a constraint to the {}to make it last less than \ + "you can add a bound to the {}to make it last less than \ `'static` and match `{}`", category.description(), region_name, diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs index e61581336283c..a30b952bd0adb 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs @@ -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), diff --git a/src/test/ui/impl-trait/does-not-live-long-enough.stderr b/src/test/ui/impl-trait/does-not-live-long-enough.stderr index ddf81138dafe7..83d0f87015bf9 100644 --- a/src/test/ui/impl-trait/does-not-live-long-enough.stderr +++ b/src/test/ui/impl-trait/does-not-live-long-enough.stderr @@ -11,7 +11,7 @@ LL | LL | } | - `prefix` dropped here while still borrowed | -help: you can add a constraint to the opaque type to make it last less than `'static` and match `'a` +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 + 'a { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr index 45c5142d93f28..4c38f0a8a914d 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr @@ -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 | diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr index bb5a85aba9709..1806d2607a3ac 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr @@ -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 } | ^^^^^^^^^^^^^^ diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index a8341f62e1d14..7f92e709af556 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -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 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr index 22f081b79f157..123ea6af6b019 100644 --- a/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr +++ b/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr @@ -6,7 +6,7 @@ LL | fn iter_values_anon(&self) -> impl Iterator { | | | 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 + '_ { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | fn iter_values<'a>(&'a self) -> impl Iterator { | 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 + 'a { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr index 1d6b5f56aa0cf..e550be1917474 100644 --- a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr +++ b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr @@ -15,7 +15,7 @@ LL | / fn iter_values_anon(&self) -> impl Iterator { 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 + '_ { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -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 { | ^^ -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 + 'a { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.nll.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.nll.stderr index 5a63553adc5c8..f2e556c63cbf3 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.nll.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.nll.stderr @@ -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 } | ^^^^^^^^^^^^^^^ diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.nll.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.nll.stderr index b46c6b9b71309..b76966e8693f2 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.nll.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.nll.stderr @@ -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 } | ^^^^^^^^^^^^^^^ diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr index 5118280e7ec0c..9f5414995151b 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr @@ -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 } | ^^^^^^^^^^^^^^^