mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-10 23:06:23 +00:00
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.
This commit is contained in:
commit
44d5090a6d
@ -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
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
//
|
||||
|
@ -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>,
|
||||
|
@ -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>,
|
||||
|
@ -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>,
|
||||
|
@ -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,
|
||||
|
@ -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() {}
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user