about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOhad Ravid <ohad.rv@gmail.com>2019-12-24 19:14:20 +0100
committerOhad Ravid <ohad.rv@gmail.com>2019-12-30 18:10:46 +0100
commitd4fbb55c9c1eba39eca81b0d73fe9edf5e3869fd (patch)
tree27efd367dd70d87b94b84ae5ba27da6e23b7cb2f
parent0fb43801368ae8b5931583f813071120bed55c35 (diff)
downloadrust-d4fbb55c9c1eba39eca81b0d73fe9edf5e3869fd.tar.gz
rust-d4fbb55c9c1eba39eca81b0d73fe9edf5e3869fd.zip
Suggest adding a lifetime constraint when opaque type is responsible for "does not live long enough" error
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs43
-rw-r--r--src/test/ui/impl-trait/does-not-live-long-enough.rs11
-rw-r--r--src/test/ui/impl-trait/does-not-live-long-enough.stderr21
3 files changed, 74 insertions, 1 deletions
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<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() {}
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<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 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<Item=&'a str> + 'a {
+   |                                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.