From d4fbb55c9c1eba39eca81b0d73fe9edf5e3869fd Mon Sep 17 00:00:00 2001 From: Ohad Ravid Date: Tue, 24 Dec 2019 19:14:20 +0100 Subject: [PATCH] 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 04f025fcbea..05bec59ad89 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 00000000000..6179132b3f6 --- /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 00000000000..ddf81138daf --- /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`.