diff options
| author | bors <bors@rust-lang.org> | 2017-09-27 22:00:11 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2017-09-27 22:00:11 +0000 |
| commit | 44d5090a6dbfbcd698ec53ef38981d9747112e0a (patch) | |
| tree | 98ed0601b49109869a317e515d42629d3c5d1c9c /src | |
| parent | 0e6f4cf51cd3b799fb057956f8e733d16605d09b (diff) | |
| parent | ddee9fbc998e345e9a36f2066d51d389aa31a632 (diff) | |
| download | rust-44d5090a6dbfbcd698ec53ef38981d9747112e0a.tar.gz rust-44d5090a6dbfbcd698ec53ef38981d9747112e0a.zip | |
Auto merge of #44782 - estebank:issue-36700, r=GuillaumeGomez
Point at parameter type on E0301
On "the parameter type `T` may not live long enough" error, point to the
parameter type suggesting lifetime bindings:
```
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/lifetime-doesnt-live-long-enough.rs:28:5
|
27 | struct Foo<T> {
| - help: consider adding an explicit lifetime bound `T: 'static`...
28 | foo: &'static T
| ^^^^^^^^^^^^^^^
|
note: ...so that the reference type `&'static T` does not outlive the data it points at
--> $DIR/lifetime-doesnt-live-long-enough.rs:28:5
|
28 | foo: &'static T
| ^^^^^^^^^^^^^^^
```
Fix #36700.
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustc/infer/error_reporting/mod.rs | 70 | ||||
| -rw-r--r-- | src/librustc/middle/free_region.rs | 2 | ||||
| -rw-r--r-- | src/librustc/middle/region.rs | 2 | ||||
| -rw-r--r-- | src/librustc/ty/context.rs | 2 | ||||
| -rw-r--r-- | src/librustc_data_structures/bitvec.rs | 2 | ||||
| -rw-r--r-- | src/librustc_data_structures/transitive_relation.rs | 6 | ||||
| -rw-r--r-- | src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.rs (renamed from src/test/compile-fail/issue-16747.rs) | 8 | ||||
| -rw-r--r-- | src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr | 30 |
8 files changed, 102 insertions, 20 deletions
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index ead20b5eb5a..3f22950fc77 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -785,10 +785,44 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { bound_kind: GenericKind<'tcx>, sub: Region<'tcx>) { - // FIXME: it would be better to report the first error message - // with the span of the parameter itself, rather than the span - // where the error was detected. But that span is not readily - // accessible. + // Attempt to obtain the span of the parameter so we can + // suggest adding an explicit lifetime bound to it. + let type_param_span = match (self.in_progress_tables, bound_kind) { + (Some(ref table), GenericKind::Param(ref param)) => { + let table = table.borrow(); + table.local_id_root.and_then(|did| { + let generics = self.tcx.generics_of(did); + // Account for the case where `did` corresponds to `Self`, which doesn't have + // the expected type argument. + if generics.types.len() > 0 { + let type_param = generics.type_param(param); + let hir = &self.tcx.hir; + hir.as_local_node_id(type_param.def_id).map(|id| { + // Get the `hir::TyParam` to verify wether it already has any bounds. + // We do this to avoid suggesting code that ends up as `T: 'a'b`, + // instead we suggest `T: 'a + 'b` in that case. + let has_lifetimes = if let hir_map::NodeTyParam(ref p) = hir.get(id) { + p.bounds.len() > 0 + } else { + false + }; + let sp = hir.span(id); + // `sp` only covers `T`, change it so that it covers + // `T:` when appropriate + let sp = if has_lifetimes { + sp.to(sp.next_point().next_point()) + } else { + sp + }; + (sp, has_lifetimes) + }) + } else { + None + } + }) + } + _ => None, + }; let labeled_user_string = match bound_kind { GenericKind::Param(ref p) => @@ -810,6 +844,26 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { return; } + fn binding_suggestion<'tcx, S: fmt::Display>(err: &mut DiagnosticBuilder<'tcx>, + type_param_span: Option<(Span, bool)>, + bound_kind: GenericKind<'tcx>, + sub: S) { + let consider = &format!("consider adding an explicit lifetime bound `{}: {}`...", + bound_kind, + sub); + if let Some((sp, has_lifetimes)) = type_param_span { + let tail = if has_lifetimes { + " + " + } else { + "" + }; + let suggestion = format!("{}: {}{}", bound_kind, sub, tail); + err.span_suggestion_short(sp, consider, suggestion); + } else { + err.help(consider); + } + } + let mut err = match *sub { ty::ReEarlyBound(_) | ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => { @@ -819,9 +873,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { E0309, "{} may not live long enough", labeled_user_string); - err.help(&format!("consider adding an explicit lifetime bound `{}: {}`...", - bound_kind, - sub)); + binding_suggestion(&mut err, type_param_span, bound_kind, sub); err } @@ -832,9 +884,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { E0310, "{} may not live long enough", labeled_user_string); - err.help(&format!("consider adding an explicit lifetime \ - bound `{}: 'static`...", - bound_kind)); + binding_suggestion(&mut err, type_param_span, bound_kind, "'static"); err } diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index 4de86b66916..49a241b86e0 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -117,7 +117,7 @@ impl<'a, 'gcx, 'tcx> RegionRelations<'a, 'gcx, 'tcx> { } } -#[derive(Clone, RustcEncodable, RustcDecodable)] +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct FreeRegionMap<'tcx> { // Stores the relation `a < b`, where `a` and `b` are regions. // diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index cede0c2b9a2..59c9e8b4c43 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -293,7 +293,7 @@ impl Scope { } /// The region scope tree encodes information about region relationships. -#[derive(Default)] +#[derive(Default, Debug)] pub struct ScopeTree { /// If not empty, this body is the root of this region hierarchy. root_body: Option<hir::HirId>, diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 054c5e122df..315ba622ccf 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -315,7 +315,7 @@ impl<'a, V> LocalTableInContextMut<'a, V> { } } -#[derive(RustcEncodable, RustcDecodable)] +#[derive(RustcEncodable, RustcDecodable, Debug)] pub struct TypeckTables<'tcx> { /// The HirId::owner all ItemLocalIds in this table are relative to. pub local_id_root: Option<DefId>, diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index 7331016c2d2..e8f9a672087 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -138,7 +138,7 @@ impl FromIterator<bool> for BitVector { /// A "bit matrix" is basically a matrix of booleans represented as /// one gigantic bitvector. In other words, it is as if you have /// `rows` bitvectors, each of length `columns`. -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct BitMatrix { columns: usize, vector: Vec<u64>, diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs index 46463944043..7cb386b0197 100644 --- a/src/librustc_data_structures/transitive_relation.rs +++ b/src/librustc_data_structures/transitive_relation.rs @@ -18,7 +18,7 @@ use std::hash::Hash; use std::mem; -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct TransitiveRelation<T: Clone + Debug + Eq + Hash + Clone> { // List of elements. This is used to map from a T to a usize. elements: Vec<T>, @@ -42,10 +42,10 @@ pub struct TransitiveRelation<T: Clone + Debug + Eq + Hash + Clone> { closure: RefCell<Option<BitMatrix>>, } -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Debug)] struct Index(usize); -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)] +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)] struct Edge { source: Index, target: Index, diff --git a/src/test/compile-fail/issue-16747.rs b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.rs index dd7e8a869ec..465b4271035 100644 --- a/src/test/compile-fail/issue-16747.rs +++ b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.rs @@ -16,14 +16,16 @@ trait Collection { fn len(&self) -> usize; } struct List<'a, T: ListItem<'a>> { slice: &'a [T] -//~^ ERROR the parameter type `T` may not live long enough -//~| HELP consider adding an explicit lifetime bound -//~| NOTE ...so that the reference type `&'a [T]` does not outlive the data it points at } + impl<'a, T: ListItem<'a>> Collection for List<'a, T> { fn len(&self) -> usize { 0 } } +struct Foo<T> { + foo: &'static T +} + fn main() {} diff --git a/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr new file mode 100644 index 00000000000..e17a660c591 --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr @@ -0,0 +1,30 @@ +error[E0309]: the parameter type `T` may not live long enough + --> $DIR/lifetime-doesnt-live-long-enough.rs:18:5 + | +17 | struct List<'a, T: ListItem<'a>> { + | -- help: consider adding an explicit lifetime bound `T: 'a`... +18 | slice: &'a [T] + | ^^^^^^^^^^^^^^ + | +note: ...so that the reference type `&'a [T]` does not outlive the data it points at + --> $DIR/lifetime-doesnt-live-long-enough.rs:18:5 + | +18 | slice: &'a [T] + | ^^^^^^^^^^^^^^ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/lifetime-doesnt-live-long-enough.rs:28:5 + | +27 | struct Foo<T> { + | - help: consider adding an explicit lifetime bound `T: 'static`... +28 | foo: &'static T + | ^^^^^^^^^^^^^^^ + | +note: ...so that the reference type `&'static T` does not outlive the data it points at + --> $DIR/lifetime-doesnt-live-long-enough.rs:28:5 + | +28 | foo: &'static T + | ^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + |
