Skip to content

Point to lifetime spans on lifetime errors #51862

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 30, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion src/librustc/hir/map/mod.rs
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ use rustc_target::spec::abi::Abi;
use syntax::ast::{self, Name, NodeId, CRATE_NODE_ID};
use syntax::codemap::Spanned;
use syntax::ext::base::MacroKind;
use syntax_pos::Span;
use syntax_pos::{Span, DUMMY_SP};

use hir::*;
use hir::print::Nested;
@@ -664,6 +664,33 @@ impl<'hir> Map<'hir> {
self.as_local_node_id(id).map(|id| self.get(id)) // read recorded by `get`
}

pub fn get_generics(&self, id: DefId) -> Option<&'hir Generics> {
self.get_if_local(id).and_then(|node| {
match node {
NodeImplItem(ref impl_item) => Some(&impl_item.generics),
NodeTraitItem(ref trait_item) => Some(&trait_item.generics),
NodeItem(ref item) => {
match item.node {
ItemFn(_, _, ref generics, _) |
ItemTy(_, ref generics) |
ItemEnum(_, ref generics) |
ItemStruct(_, ref generics) |
ItemUnion(_, ref generics) |
ItemTrait(_, _, ref generics, ..) |
ItemTraitAlias(ref generics, _) |
ItemImpl(_, _, _, ref generics, ..) => Some(generics),
_ => None,
}
}
_ => None,
}
})
}

pub fn get_generics_span(&self, id: DefId) -> Option<Span> {
self.get_generics(id).map(|generics| generics.span).filter(|sp| *sp != DUMMY_SP)
}

/// Retrieve the Node corresponding to `id`, returning None if
/// cannot be found.
pub fn find(&self, id: NodeId) -> Option<Node<'hir>> {
11 changes: 10 additions & 1 deletion src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
@@ -31,7 +31,7 @@ use hir::def_id::{DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX};
use util::nodemap::{NodeMap, FxHashSet};
use mir::mono::Linkage;

use syntax_pos::{Span, DUMMY_SP};
use syntax_pos::{Span, DUMMY_SP, symbol::InternedString};
use syntax::codemap::{self, Spanned};
use rustc_target::spec::abi::Abi;
use syntax::ast::{self, CrateSugar, Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect};
@@ -547,6 +547,15 @@ impl Generics {

own_counts
}

pub fn get_named(&self, name: &InternedString) -> Option<&GenericParam> {
for param in &self.params {
if *name == param.name.ident().as_interned_str() {
return Some(param);
}
}
None
}
}

/// Synthetic Type Parameters are converted to an other form during lowering, this allows
28 changes: 23 additions & 5 deletions src/librustc/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
@@ -189,6 +189,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self,
region: ty::Region<'tcx>,
) -> (String, Option<Span>) {
let cm = self.sess.codemap();

let scope = region.free_region_binding_scope(self);
let node = self.hir.as_local_node_id(scope).unwrap_or(DUMMY_NODE_ID);
let unknown;
@@ -219,10 +221,26 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}
};
let (prefix, span) = match *region {
ty::ReEarlyBound(ref br) => (
format!("the lifetime {} as defined on", br.name),
self.sess.codemap().def_span(self.hir.span(node)),
),
ty::ReEarlyBound(ref br) => {
let mut sp = cm.def_span(self.hir.span(node));
if let Some(param) = self.hir.get_generics(scope).and_then(|generics| {
generics.get_named(&br.name)
}) {
sp = param.span;
}
(format!("the lifetime {} as defined on", br.name), sp)
}
ty::ReFree(ty::FreeRegion {
bound_region: ty::BoundRegion::BrNamed(_, ref name), ..
}) => {
let mut sp = cm.def_span(self.hir.span(node));
if let Some(param) = self.hir.get_generics(scope).and_then(|generics| {
generics.get_named(&name)
}) {
sp = param.span;
}
(format!("the lifetime {} as defined on", name), sp)
}
ty::ReFree(ref fr) => match fr.bound_region {
ty::BrAnon(idx) => (
format!("the anonymous lifetime #{} defined on", idx + 1),
@@ -234,7 +252,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
),
_ => (
format!("the lifetime {} as defined on", fr.bound_region),
self.sess.codemap().def_span(self.hir.span(node)),
cm.def_span(self.hir.span(node)),
),
},
_ => bug!(),
21 changes: 12 additions & 9 deletions src/librustc_typeck/check/compare_method.rs
Original file line number Diff line number Diff line change
@@ -356,7 +356,6 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl_generics: &ty::Generics,
trait_to_skol_substs: &Substs<'tcx>)
-> Result<(), ErrorReported> {
let span = tcx.sess.codemap().def_span(span);
let trait_params = trait_generics.own_counts().lifetimes;
let impl_params = impl_generics.own_counts().lifetimes;

@@ -378,16 +377,20 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// are zero. Since I don't quite know how to phrase things at
// the moment, give a kind of vague error message.
if trait_params != impl_params {
let mut err = struct_span_err!(tcx.sess,
span,
E0195,
"lifetime parameters or bounds on method `{}` do not match \
the trait declaration",
impl_m.ident);
let def_span = tcx.sess.codemap().def_span(span);
let span = tcx.hir.get_generics_span(impl_m.def_id).unwrap_or(def_span);
let mut err = struct_span_err!(
tcx.sess,
span,
E0195,
"lifetime parameters or bounds on method `{}` do not match the trait declaration",
impl_m.ident,
);
err.span_label(span, "lifetimes do not match method in trait");
if let Some(sp) = tcx.hir.span_if_local(trait_m.def_id) {
err.span_label(tcx.sess.codemap().def_span(sp),
"lifetimes in impl do not match this method in trait");
let def_sp = tcx.sess.codemap().def_span(sp);
let sp = tcx.hir.get_generics_span(trait_m.def_id).unwrap_or(def_sp);
err.span_label(sp, "lifetimes in impl do not match this method in trait");
}
err.emit();
return Err(ErrorReported);
6 changes: 3 additions & 3 deletions src/test/ui/associated-const-impl-wrong-lifetime.stderr
Original file line number Diff line number Diff line change
@@ -6,11 +6,11 @@ LL | const NAME: &'a str = "unit";
|
= note: expected type `&'static str`
found type `&'a str`
note: the lifetime 'a as defined on the impl at 17:1...
--> $DIR/associated-const-impl-wrong-lifetime.rs:17:1
note: the lifetime 'a as defined on the impl at 17:6...
--> $DIR/associated-const-impl-wrong-lifetime.rs:17:6
|
LL | impl<'a> Foo for &'a () {
| ^^^^^^^^^^^^^^^^^^^^^^^
| ^^
= note: ...does not necessarily outlive the static lifetime

error: aborting due to previous error
Original file line number Diff line number Diff line change
@@ -7,11 +7,11 @@ LL | //~^ ERROR E0373
LL | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 19:1...
--> $DIR/borrowck-escaping-closure-error-2.rs:19:1
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 19:8...
--> $DIR/borrowck-escaping-closure-error-2.rs:19:8
|
LL | fn foo<'a>(x: &'a i32) -> Box<FnMut()+'a> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^

error: aborting due to previous error

5 changes: 5 additions & 0 deletions src/test/ui/borrowck/regions-bound-missing-bound-in-impl.rs
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@ pub trait Foo<'a, 't> {
fn no_bound<'b>(self, b: Inv<'b>);
fn has_bound<'b:'a>(self, b: Inv<'b>);
fn wrong_bound1<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
fn wrong_bound2<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
fn okay_bound<'b,'c,'d:'a+'b+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
fn another_bound<'x: 'a>(self, x: Inv<'x>, y: Inv<'t>);
}
@@ -47,6 +48,10 @@ impl<'a, 't> Foo<'a, 't> for &'a isize {
// cases.
}

fn wrong_bound2(self, b: Inv, c: Inv, d: Inv) {
//~^ ERROR lifetime parameters or bounds on method `wrong_bound2` do not match the trait
}

fn okay_bound<'b,'c,'e:'b+'c>(self, b: Inv<'b>, c: Inv<'c>, e: Inv<'e>) {
}

39 changes: 24 additions & 15 deletions src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr
Original file line number Diff line number Diff line change
@@ -1,50 +1,59 @@
error[E0195]: lifetime parameters or bounds on method `no_bound` do not match the trait declaration
--> $DIR/regions-bound-missing-bound-in-impl.rs:28:5
--> $DIR/regions-bound-missing-bound-in-impl.rs:29:16
|
LL | fn no_bound<'b>(self, b: Inv<'b>);
| ---------------------------------- lifetimes in impl do not match this method in trait
| ---- lifetimes in impl do not match this method in trait
...
LL | fn no_bound<'b:'a>(self, b: Inv<'b>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait
| ^^^^^^^ lifetimes do not match method in trait

error[E0195]: lifetime parameters or bounds on method `has_bound` do not match the trait declaration
--> $DIR/regions-bound-missing-bound-in-impl.rs:32:5
--> $DIR/regions-bound-missing-bound-in-impl.rs:33:17
|
LL | fn has_bound<'b:'a>(self, b: Inv<'b>);
| -------------------------------------- lifetimes in impl do not match this method in trait
| ------- lifetimes in impl do not match this method in trait
...
LL | fn has_bound<'b>(self, b: Inv<'b>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait
| ^^^^ lifetimes do not match method in trait

error[E0308]: method not compatible with trait
--> $DIR/regions-bound-missing-bound-in-impl.rs:36:5
--> $DIR/regions-bound-missing-bound-in-impl.rs:37:5
|
LL | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected type `fn(&'a isize, Inv<'c>, Inv<'c>, Inv<'d>)`
found type `fn(&'a isize, Inv<'_>, Inv<'c>, Inv<'d>)`
note: the lifetime 'c as defined on the method body at 36:5...
--> $DIR/regions-bound-missing-bound-in-impl.rs:36:5
note: the lifetime 'c as defined on the method body at 37:24...
--> $DIR/regions-bound-missing-bound-in-impl.rs:37:24
|
LL | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the lifetime 'c as defined on the method body at 36:5
--> $DIR/regions-bound-missing-bound-in-impl.rs:36:5
| ^^
note: ...does not necessarily outlive the lifetime 'c as defined on the method body at 37:24
--> $DIR/regions-bound-missing-bound-in-impl.rs:37:24
|
LL | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^

error[E0195]: lifetime parameters or bounds on method `wrong_bound2` do not match the trait declaration
--> $DIR/regions-bound-missing-bound-in-impl.rs:51:5
|
LL | fn wrong_bound2<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
| ---------------- lifetimes in impl do not match this method in trait
...
LL | fn wrong_bound2(self, b: Inv, c: Inv, d: Inv) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait

error[E0276]: impl has stricter requirements than trait
--> $DIR/regions-bound-missing-bound-in-impl.rs:53:5
--> $DIR/regions-bound-missing-bound-in-impl.rs:58:5
|
LL | fn another_bound<'x: 'a>(self, x: Inv<'x>, y: Inv<'t>);
| ------------------------------------------------------- definition of `another_bound` from trait
...
LL | fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `'x: 't`

error: aborting due to 4 previous errors
error: aborting due to 5 previous errors

Some errors occurred: E0195, E0276, E0308.
For more information about an error, try `rustc --explain E0195`.
Original file line number Diff line number Diff line change
@@ -38,11 +38,11 @@ LL | |
LL | | //~^ ERROR borrowed data cannot be stored outside of its closure
LL | | });
| |_____^
note: ...does not necessarily outlive the lifetime 'x as defined on the function body at 42:1
--> $DIR/expect-region-supply-region.rs:42:1
note: ...does not necessarily outlive the lifetime 'x as defined on the function body at 42:30
--> $DIR/expect-region-supply-region.rs:42:30
|
LL | fn expect_bound_supply_named<'x>() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^

error[E0308]: mismatched types
--> $DIR/expect-region-supply-region.rs:47:33
@@ -52,11 +52,11 @@ LL | closure_expecting_bound(|x: &'x u32| {
|
= note: expected type `&u32`
found type `&'x u32`
note: the lifetime 'x as defined on the function body at 42:1...
--> $DIR/expect-region-supply-region.rs:42:1
note: the lifetime 'x as defined on the function body at 42:30...
--> $DIR/expect-region-supply-region.rs:42:30
|
LL | fn expect_bound_supply_named<'x>() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^
note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 47:29
--> $DIR/expect-region-supply-region.rs:47:29
|
6 changes: 3 additions & 3 deletions src/test/ui/error-codes/E0195.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
error[E0195]: lifetime parameters or bounds on method `bar` do not match the trait declaration
--> $DIR/E0195.rs:19:5
--> $DIR/E0195.rs:19:11
|
LL | fn bar<'a,'b:'a>(x: &'a str, y: &'b str);
| ----------------------------------------- lifetimes in impl do not match this method in trait
| ---------- lifetimes in impl do not match this method in trait
...
LL | fn bar<'a,'b>(x: &'a str, y: &'b str) { //~ ERROR E0195
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait
| ^^^^^^^ lifetimes do not match method in trait

error: aborting due to previous error

12 changes: 6 additions & 6 deletions src/test/ui/error-codes/E0478.stderr
Original file line number Diff line number Diff line change
@@ -4,16 +4,16 @@ error[E0478]: lifetime bound not satisfied
LL | child: Box<Wedding<'kiss> + 'SnowWhite>, //~ ERROR E0478
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: lifetime parameter instantiated with the lifetime 'SnowWhite as defined on the struct at 13:1
--> $DIR/E0478.rs:13:1
note: lifetime parameter instantiated with the lifetime 'SnowWhite as defined on the struct at 13:22
--> $DIR/E0478.rs:13:22
|
LL | struct Prince<'kiss, 'SnowWhite> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: but lifetime parameter must outlive the lifetime 'kiss as defined on the struct at 13:1
--> $DIR/E0478.rs:13:1
| ^^^^^^^^^^
note: but lifetime parameter must outlive the lifetime 'kiss as defined on the struct at 13:15
--> $DIR/E0478.rs:13:15
|
LL | struct Prince<'kiss, 'SnowWhite> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^

error: aborting due to previous error

13 changes: 4 additions & 9 deletions src/test/ui/impl-trait/region-escape-via-bound.stderr
Original file line number Diff line number Diff line change
@@ -4,16 +4,11 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea
LL | fn foo(x: Cell<&'x u32>) -> impl Trait<'y>
| ^^^^^^^^^^^^^^
|
note: hidden type `std::cell::Cell<&'x u32>` captures the lifetime 'x as defined on the function body at 26:1
--> $DIR/region-escape-via-bound.rs:26:1
note: hidden type `std::cell::Cell<&'x u32>` captures the lifetime 'x as defined on the function body at 28:7
--> $DIR/region-escape-via-bound.rs:28:7
|
LL | / fn foo(x: Cell<&'x u32>) -> impl Trait<'y>
LL | | //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds [E0700]
LL | | where 'x: 'y
LL | | {
LL | | x
LL | | }
| |_^
LL | where 'x: 'y
| ^^

error: aborting due to previous error

8 changes: 4 additions & 4 deletions src/test/ui/impl-trait/static-return-lifetime-infered.stderr
Original file line number Diff line number Diff line change
@@ -30,12 +30,12 @@ LL | self.x.iter().map(|a| a.0)
| |
| ...but this borrow...
|
note: ...can't outlive the lifetime 'a as defined on the method body at 20:5
--> $DIR/static-return-lifetime-infered.rs:20:5
note: ...can't outlive the lifetime 'a as defined on the method body at 20:20
--> $DIR/static-return-lifetime-infered.rs:20:20
|
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: you can add a constraint to the return type to make it last less than `'static` and match the lifetime 'a as defined on the method body at 20:5
| ^^
help: you can add a constraint to the return type to make it last less than `'static` and match the lifetime 'a as defined on the method body at 20:20
|
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6 changes: 3 additions & 3 deletions src/test/ui/in-band-lifetimes/impl/dyn-trait.stderr
Original file line number Diff line number Diff line change
@@ -4,11 +4,11 @@ error[E0495]: cannot infer an appropriate lifetime due to conflicting requiremen
LL | static_val(x); //~ ERROR cannot infer
| ^
|
note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 31:1...
--> $DIR/dyn-trait.rs:31:1
note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 31:26...
--> $DIR/dyn-trait.rs:31:26
|
LL | fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^
= note: ...so that the expression is assignable:
expected std::boxed::Box<dyn std::fmt::Debug>
found std::boxed::Box<(dyn std::fmt::Debug + 'a)>
Loading