diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index b7071970a04..33cae96dd07 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -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,26 @@ 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, _) => 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>> { diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 04c11d30d26..4c903b6fe58 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -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); diff --git a/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.rs b/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.rs index 617de2c5dfe..04f90ea9ad3 100644 --- a/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.rs +++ b/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.rs @@ -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>) { } diff --git a/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr b/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr index b58dbd1e4d1..b530fea1e59 100644 --- a/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr +++ b/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr @@ -1,42 +1,51 @@ 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: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>) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -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: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>) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +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 @@ -44,7 +53,7 @@ LL | fn another_bound<'x: 'a>(self, x: Inv<'x>, y: Inv<'t>); 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`. diff --git a/src/test/ui/error-codes/E0195.stderr b/src/test/ui/error-codes/E0195.stderr index f2cf661830d..3860c93a45f 100644 --- a/src/test/ui/error-codes/E0195.stderr +++ b/src/test/ui/error-codes/E0195.stderr @@ -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