提交 44d5090a 编写于 作者: B bors

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.
......@@ -785,10 +785,44 @@ fn report_generic_bound_failure(&self,
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 @@ fn report_generic_bound_failure(&self,
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 @@ fn report_generic_bound_failure(&self,
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 @@ fn report_generic_bound_failure(&self,
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
}
......
......@@ -117,7 +117,7 @@ pub fn lub_free_regions(&self,
}
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct FreeRegionMap<'tcx> {
// Stores the relation `a < b`, where `a` and `b` are regions.
//
......
......@@ -293,7 +293,7 @@ pub fn span(&self, tcx: TyCtxt, scope_tree: &ScopeTree) -> Span {
}
/// 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>,
......
......@@ -315,7 +315,7 @@ pub fn remove(&mut self, id: hir::HirId) -> Option<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>,
......
......@@ -138,7 +138,7 @@ fn from_iter<I>(iter: I) -> BitVector where I: IntoIterator<Item=bool> {
/// 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>,
......
......@@ -18,7 +18,7 @@
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,
......
......@@ -16,14 +16,16 @@ trait ListItem<'a> {
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() {}
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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册