mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-22 12:43:36 +00:00
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 | ^^^^^^^^^^^^^^^ ```
This commit is contained in:
parent
14039a42ac
commit
ddee9fbc99
@ -774,10 +774,44 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||||||
bound_kind: GenericKind<'tcx>,
|
bound_kind: GenericKind<'tcx>,
|
||||||
sub: Region<'tcx>)
|
sub: Region<'tcx>)
|
||||||
{
|
{
|
||||||
// FIXME: it would be better to report the first error message
|
// Attempt to obtain the span of the parameter so we can
|
||||||
// with the span of the parameter itself, rather than the span
|
// suggest adding an explicit lifetime bound to it.
|
||||||
// where the error was detected. But that span is not readily
|
let type_param_span = match (self.in_progress_tables, bound_kind) {
|
||||||
// accessible.
|
(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 {
|
let labeled_user_string = match bound_kind {
|
||||||
GenericKind::Param(ref p) =>
|
GenericKind::Param(ref p) =>
|
||||||
@ -799,6 +833,26 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||||||
return;
|
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 {
|
let mut err = match *sub {
|
||||||
ty::ReEarlyBound(_) |
|
ty::ReEarlyBound(_) |
|
||||||
ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => {
|
ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => {
|
||||||
@ -808,9 +862,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||||||
E0309,
|
E0309,
|
||||||
"{} may not live long enough",
|
"{} may not live long enough",
|
||||||
labeled_user_string);
|
labeled_user_string);
|
||||||
err.help(&format!("consider adding an explicit lifetime bound `{}: {}`...",
|
binding_suggestion(&mut err, type_param_span, bound_kind, sub);
|
||||||
bound_kind,
|
|
||||||
sub));
|
|
||||||
err
|
err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -821,9 +873,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||||||
E0310,
|
E0310,
|
||||||
"{} may not live long enough",
|
"{} may not live long enough",
|
||||||
labeled_user_string);
|
labeled_user_string);
|
||||||
err.help(&format!("consider adding an explicit lifetime \
|
binding_suggestion(&mut err, type_param_span, bound_kind, "'static");
|
||||||
bound `{}: 'static`...",
|
|
||||||
bound_kind));
|
|
||||||
err
|
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> {
|
pub struct FreeRegionMap<'tcx> {
|
||||||
// Stores the relation `a < b`, where `a` and `b` are regions.
|
// Stores the relation `a < b`, where `a` and `b` are regions.
|
||||||
//
|
//
|
||||||
|
@ -201,7 +201,7 @@ impl Scope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The region scope tree encodes information about region relationships.
|
/// The region scope tree encodes information about region relationships.
|
||||||
#[derive(Default)]
|
#[derive(Default, Debug)]
|
||||||
pub struct ScopeTree {
|
pub struct ScopeTree {
|
||||||
/// If not empty, this body is the root of this region hierarchy.
|
/// If not empty, this body is the root of this region hierarchy.
|
||||||
root_body: Option<hir::HirId>,
|
root_body: Option<hir::HirId>,
|
||||||
|
@ -314,7 +314,7 @@ impl<'a, V> LocalTableInContextMut<'a, V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(RustcEncodable, RustcDecodable)]
|
#[derive(RustcEncodable, RustcDecodable, Debug)]
|
||||||
pub struct TypeckTables<'tcx> {
|
pub struct TypeckTables<'tcx> {
|
||||||
/// The HirId::owner all ItemLocalIds in this table are relative to.
|
/// The HirId::owner all ItemLocalIds in this table are relative to.
|
||||||
pub local_id_root: Option<DefId>,
|
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
|
/// A "bit matrix" is basically a matrix of booleans represented as
|
||||||
/// one gigantic bitvector. In other words, it is as if you have
|
/// one gigantic bitvector. In other words, it is as if you have
|
||||||
/// `rows` bitvectors, each of length `columns`.
|
/// `rows` bitvectors, each of length `columns`.
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct BitMatrix {
|
pub struct BitMatrix {
|
||||||
columns: usize,
|
columns: usize,
|
||||||
vector: Vec<u64>,
|
vector: Vec<u64>,
|
||||||
|
@ -18,7 +18,7 @@ use std::hash::Hash;
|
|||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct TransitiveRelation<T: Clone + Debug + Eq + Hash + Clone> {
|
pub struct TransitiveRelation<T: Clone + Debug + Eq + Hash + Clone> {
|
||||||
// List of elements. This is used to map from a T to a usize.
|
// List of elements. This is used to map from a T to a usize.
|
||||||
elements: Vec<T>,
|
elements: Vec<T>,
|
||||||
@ -42,10 +42,10 @@ pub struct TransitiveRelation<T: Clone + Debug + Eq + Hash + Clone> {
|
|||||||
closure: RefCell<Option<BitMatrix>>,
|
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);
|
struct Index(usize);
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)]
|
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)]
|
||||||
struct Edge {
|
struct Edge {
|
||||||
source: Index,
|
source: Index,
|
||||||
target: Index,
|
target: Index,
|
||||||
|
@ -16,14 +16,16 @@ trait Collection { fn len(&self) -> usize; }
|
|||||||
|
|
||||||
struct List<'a, T: ListItem<'a>> {
|
struct List<'a, T: ListItem<'a>> {
|
||||||
slice: &'a [T]
|
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> {
|
impl<'a, T: ListItem<'a>> Collection for List<'a, T> {
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Foo<T> {
|
||||||
|
foo: &'static T
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {}
|
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