diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index bbf36fef1ddbe..fb67f2fd22350 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -5,7 +5,7 @@ use std::iter; use hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; -use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err}; +use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, pluralize, struct_span_code_err}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::VisitorExt; use rustc_hir::{self as hir, AmbigArg, GenericParamKind, ImplItemKind, intravisit}; @@ -14,10 +14,10 @@ use rustc_infer::traits::util; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{ self, BottomUpFolder, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, TypeFolder, - TypeSuperFoldable, TypeVisitableExt, TypingMode, Upcast, + TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast, }; use rustc_middle::{bug, span_bug}; -use rustc_span::Span; +use rustc_span::{DUMMY_SP, Span}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::regions::InferCtxtRegionExt; @@ -1137,65 +1137,319 @@ fn check_region_bounds_on_impl_item<'tcx>( // but found 0" it's confusing, because it looks like there // 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 span = tcx - .hir_get_generics(impl_m.def_id.expect_local()) - .expect("expected impl item to have generics or else we can't compare them") - .span; - - let mut generics_span = None; - let mut bounds_span = vec![]; - let mut where_span = None; - if let Some(trait_node) = tcx.hir_get_if_local(trait_m.def_id) - && let Some(trait_generics) = trait_node.generics() - { - generics_span = Some(trait_generics.span); - // FIXME: we could potentially look at the impl's bounds to not point at bounds that - // *are* present in the impl. - for p in trait_generics.predicates { - if let hir::WherePredicateKind::BoundPredicate(pred) = p.kind { - for b in pred.bounds { + if trait_params == impl_params { + return Ok(()); + } + + if !delay && let Some(guar) = check_region_late_boundedness(tcx, impl_m, trait_m) { + return Err(guar); + } + + let span = tcx + .hir_get_generics(impl_m.def_id.expect_local()) + .expect("expected impl item to have generics or else we can't compare them") + .span; + + let mut generics_span = None; + let mut bounds_span = vec![]; + let mut where_span = None; + + if let Some(trait_node) = tcx.hir_get_if_local(trait_m.def_id) + && let Some(trait_generics) = trait_node.generics() + { + generics_span = Some(trait_generics.span); + // FIXME: we could potentially look at the impl's bounds to not point at bounds that + // *are* present in the impl. + for p in trait_generics.predicates { + match p.kind { + hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate { + bounds, + .. + }) + | hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate { + bounds, + .. + }) => { + for b in *bounds { if let hir::GenericBound::Outlives(lt) = b { bounds_span.push(lt.ident.span); } } } + _ => {} } - if let Some(impl_node) = tcx.hir_get_if_local(impl_m.def_id) - && let Some(impl_generics) = impl_node.generics() - { - let mut impl_bounds = 0; - for p in impl_generics.predicates { - if let hir::WherePredicateKind::BoundPredicate(pred) = p.kind { - for b in pred.bounds { + } + if let Some(impl_node) = tcx.hir_get_if_local(impl_m.def_id) + && let Some(impl_generics) = impl_node.generics() + { + let mut impl_bounds = 0; + for p in impl_generics.predicates { + match p.kind { + hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate { + bounds, + .. + }) + | hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate { + bounds, + .. + }) => { + for b in *bounds { if let hir::GenericBound::Outlives(_) = b { impl_bounds += 1; } } } + _ => {} + } + } + if impl_bounds == bounds_span.len() { + bounds_span = vec![]; + } else if impl_generics.has_where_clause_predicates { + where_span = Some(impl_generics.where_clause_span); + } + } + } + + let reported = tcx + .dcx() + .create_err(LifetimesOrBoundsMismatchOnTrait { + span, + item_kind: impl_m.descr(), + ident: impl_m.ident(tcx), + generics_span, + bounds_span, + where_span, + }) + .emit_unless(delay); + + Err(reported) +} + +#[allow(unused)] +enum LateEarlyMismatch<'tcx> { + EarlyInImpl(DefId, DefId, ty::Region<'tcx>), + LateInImpl(DefId, DefId, ty::Region<'tcx>), +} + +fn check_region_late_boundedness<'tcx>( + tcx: TyCtxt<'tcx>, + impl_m: ty::AssocItem, + trait_m: ty::AssocItem, +) -> Option { + if !impl_m.is_fn() { + return None; + } + + let (infcx, param_env) = tcx + .infer_ctxt() + .build_with_typing_env(ty::TypingEnv::non_body_analysis(tcx, impl_m.def_id)); + + let impl_m_args = infcx.fresh_args_for_item(DUMMY_SP, impl_m.def_id); + let impl_m_sig = tcx.fn_sig(impl_m.def_id).instantiate(tcx, impl_m_args); + let impl_m_sig = tcx.liberate_late_bound_regions(impl_m.def_id, impl_m_sig); + + let trait_m_args = infcx.fresh_args_for_item(DUMMY_SP, trait_m.def_id); + let trait_m_sig = tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_m_args); + let trait_m_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_m_sig); + + let ocx = ObligationCtxt::new(&infcx); + + // Equate the signatures so that we can infer whether a late-bound param was present where + // an early-bound param was expected, since we replace the late-bound lifetimes with + // `ReLateParam`, and early-bound lifetimes with infer vars, so the early-bound args will + // resolve to `ReLateParam` if there is a mismatch. + let Ok(()) = ocx.eq( + &ObligationCause::dummy(), + param_env, + ty::Binder::dummy(trait_m_sig), + ty::Binder::dummy(impl_m_sig), + ) else { + return None; + }; + + let errors = ocx.select_where_possible(); + if !errors.is_empty() { + return None; + } + + let mut mismatched = vec![]; + + let impl_generics = tcx.generics_of(impl_m.def_id); + for (id_arg, arg) in + std::iter::zip(ty::GenericArgs::identity_for_item(tcx, impl_m.def_id), impl_m_args) + { + if let ty::GenericArgKind::Lifetime(r) = arg.unpack() + && let ty::ReVar(vid) = r.kind() + && let r = infcx + .inner + .borrow_mut() + .unwrap_region_constraints() + .opportunistic_resolve_var(tcx, vid) + && let ty::ReLateParam(ty::LateParamRegion { + kind: ty::LateParamRegionKind::Named(trait_param_def_id, _), + .. + }) = r.kind() + && let ty::ReEarlyParam(ebr) = id_arg.expect_region().kind() + { + mismatched.push(LateEarlyMismatch::EarlyInImpl( + impl_generics.region_param(ebr, tcx).def_id, + trait_param_def_id, + id_arg.expect_region(), + )); + } + } + + let trait_generics = tcx.generics_of(trait_m.def_id); + for (id_arg, arg) in + std::iter::zip(ty::GenericArgs::identity_for_item(tcx, trait_m.def_id), trait_m_args) + { + if let ty::GenericArgKind::Lifetime(r) = arg.unpack() + && let ty::ReVar(vid) = r.kind() + && let r = infcx + .inner + .borrow_mut() + .unwrap_region_constraints() + .opportunistic_resolve_var(tcx, vid) + && let ty::ReLateParam(ty::LateParamRegion { + kind: ty::LateParamRegionKind::Named(impl_param_def_id, _), + .. + }) = r.kind() + && let ty::ReEarlyParam(ebr) = id_arg.expect_region().kind() + { + mismatched.push(LateEarlyMismatch::LateInImpl( + impl_param_def_id, + trait_generics.region_param(ebr, tcx).def_id, + id_arg.expect_region(), + )); + } + } + + if mismatched.is_empty() { + return None; + } + + let spans: Vec<_> = mismatched + .iter() + .map(|param| { + let (LateEarlyMismatch::EarlyInImpl(impl_param_def_id, ..) + | LateEarlyMismatch::LateInImpl(impl_param_def_id, ..)) = param; + tcx.def_span(impl_param_def_id) + }) + .collect(); + + let mut diag = tcx + .dcx() + .struct_span_err(spans, "lifetime parameters do not match the trait definition") + .with_note("lifetime parameters differ in whether they are early- or late-bound") + .with_code(E0195); + for mismatch in mismatched { + match mismatch { + LateEarlyMismatch::EarlyInImpl( + impl_param_def_id, + trait_param_def_id, + early_bound_region, + ) => { + let mut multispan = MultiSpan::from_spans(vec![ + tcx.def_span(impl_param_def_id), + tcx.def_span(trait_param_def_id), + ]); + multispan + .push_span_label(tcx.def_span(tcx.parent(impl_m.def_id)), "in this impl..."); + multispan + .push_span_label(tcx.def_span(tcx.parent(trait_m.def_id)), "in this trait..."); + multispan.push_span_label( + tcx.def_span(impl_param_def_id), + format!("`{}` is early-bound", tcx.item_name(impl_param_def_id)), + ); + multispan.push_span_label( + tcx.def_span(trait_param_def_id), + format!("`{}` is late-bound", tcx.item_name(trait_param_def_id)), + ); + if let Some(span) = + find_region_in_predicates(tcx, impl_m.def_id, early_bound_region) + { + multispan.push_span_label( + span, + format!( + "this lifetime bound makes `{}` early-bound", + tcx.item_name(impl_param_def_id) + ), + ); } - if impl_bounds == bounds_span.len() { - bounds_span = vec![]; - } else if impl_generics.has_where_clause_predicates { - where_span = Some(impl_generics.where_clause_span); + diag.span_note( + multispan, + format!( + "`{}` differs between the trait and impl", + tcx.item_name(impl_param_def_id) + ), + ); + } + LateEarlyMismatch::LateInImpl( + impl_param_def_id, + trait_param_def_id, + early_bound_region, + ) => { + let mut multispan = MultiSpan::from_spans(vec![ + tcx.def_span(impl_param_def_id), + tcx.def_span(trait_param_def_id), + ]); + multispan + .push_span_label(tcx.def_span(tcx.parent(impl_m.def_id)), "in this impl..."); + multispan + .push_span_label(tcx.def_span(tcx.parent(trait_m.def_id)), "in this trait..."); + multispan.push_span_label( + tcx.def_span(impl_param_def_id), + format!("`{}` is late-bound", tcx.item_name(impl_param_def_id)), + ); + multispan.push_span_label( + tcx.def_span(trait_param_def_id), + format!("`{}` is early-bound", tcx.item_name(trait_param_def_id)), + ); + if let Some(span) = + find_region_in_predicates(tcx, trait_m.def_id, early_bound_region) + { + multispan.push_span_label( + span, + format!( + "this lifetime bound makes `{}` early-bound", + tcx.item_name(trait_param_def_id) + ), + ); } + diag.span_note( + multispan, + format!( + "`{}` differs between the trait and impl", + tcx.item_name(impl_param_def_id) + ), + ); } } - let reported = tcx - .dcx() - .create_err(LifetimesOrBoundsMismatchOnTrait { - span, - item_kind: impl_m.descr(), - ident: impl_m.ident(tcx), - generics_span, - bounds_span, - where_span, - }) - .emit_unless(delay); - return Err(reported); } - Ok(()) + Some(diag.emit()) +} + +fn find_region_in_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + early_bound_region: ty::Region<'tcx>, +) -> Option { + for (pred, span) in tcx.explicit_predicates_of(def_id).instantiate_identity(tcx) { + if pred.visit_with(&mut FindRegion(early_bound_region)).is_break() { + return Some(span); + } + } + + struct FindRegion<'tcx>(ty::Region<'tcx>); + impl<'tcx> TypeVisitor> for FindRegion<'tcx> { + type Result = ControlFlow<()>; + fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result { + if r == self.0 { ControlFlow::Break(()) } else { ControlFlow::Continue(()) } + } + } + + None } #[instrument(level = "debug", skip(infcx))] diff --git a/tests/ui/borrowck/regions-bound-missing-bound-in-impl.rs b/tests/ui/borrowck/regions-bound-missing-bound-in-impl.rs index 141ad5bd2c482..7c0378e068be4 100644 --- a/tests/ui/borrowck/regions-bound-missing-bound-in-impl.rs +++ b/tests/ui/borrowck/regions-bound-missing-bound-in-impl.rs @@ -17,11 +17,11 @@ pub trait Foo<'a, 't> { impl<'a, 't> Foo<'a, 't> for &'a isize { fn no_bound<'b:'a>(self, b: Inv<'b>) { - //~^ ERROR lifetime parameters or bounds on method `no_bound` do not match + //~^ ERROR lifetime parameters do not match the trait definition } fn has_bound<'b>(self, b: Inv<'b>) { - //~^ ERROR lifetime parameters or bounds on method `has_bound` do not match + //~^ ERROR lifetime parameters do not match the trait definition } fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) { @@ -40,7 +40,7 @@ impl<'a, 't> Foo<'a, 't> for &'a isize { } fn wrong_bound2(self, b: Inv, c: Inv, d: Inv) { - //~^ ERROR lifetime parameters or bounds on method `wrong_bound2` do not match the trait + //~^ ERROR lifetime parameters do not match the trait definition } fn okay_bound<'b,'c,'e:'b+'c>(self, b: Inv<'b>, c: Inv<'c>, e: Inv<'e>) { diff --git a/tests/ui/borrowck/regions-bound-missing-bound-in-impl.stderr b/tests/ui/borrowck/regions-bound-missing-bound-in-impl.stderr index 5f0347bdb4d49..207ca57af38b5 100644 --- a/tests/ui/borrowck/regions-bound-missing-bound-in-impl.stderr +++ b/tests/ui/borrowck/regions-bound-missing-bound-in-impl.stderr @@ -1,20 +1,48 @@ -error[E0195]: lifetime parameters or bounds on method `no_bound` do not match the trait declaration - --> $DIR/regions-bound-missing-bound-in-impl.rs:19:16 +error[E0195]: lifetime parameters do not match the trait definition + --> $DIR/regions-bound-missing-bound-in-impl.rs:19:17 | +LL | fn no_bound<'b:'a>(self, b: Inv<'b>) { + | ^^ + | + = note: lifetime parameters differ in whether they are early- or late-bound +note: `'b` differs between the trait and impl + --> $DIR/regions-bound-missing-bound-in-impl.rs:10:17 + | +LL | pub trait Foo<'a, 't> { + | --------------------- in this trait... LL | fn no_bound<'b>(self, b: Inv<'b>); - | ---- lifetimes in impl do not match this method in trait + | ^^ `'b` is late-bound ... +LL | impl<'a, 't> Foo<'a, 't> for &'a isize { + | -------------------------------------- in this impl... LL | fn no_bound<'b:'a>(self, b: Inv<'b>) { - | ^^^^^^^ lifetimes do not match method in trait + | ^^ -- this lifetime bound makes `'b` early-bound + | | + | `'b` is early-bound -error[E0195]: lifetime parameters or bounds on method `has_bound` do not match the trait declaration - --> $DIR/regions-bound-missing-bound-in-impl.rs:23:17 +error[E0195]: lifetime parameters do not match the trait definition + --> $DIR/regions-bound-missing-bound-in-impl.rs:23:18 + | +LL | fn has_bound<'b>(self, b: Inv<'b>) { + | ^^ | + = note: lifetime parameters differ in whether they are early- or late-bound +note: `'b` differs between the trait and impl + --> $DIR/regions-bound-missing-bound-in-impl.rs:11:18 + | +LL | pub trait Foo<'a, 't> { + | --------------------- in this trait... +LL | fn no_bound<'b>(self, b: Inv<'b>); LL | fn has_bound<'b:'a>(self, b: Inv<'b>); - | ------- lifetimes in impl do not match this method in trait + | ^^ -- this lifetime bound makes `'b` early-bound + | | + | `'b` is early-bound +... +LL | impl<'a, 't> Foo<'a, 't> for &'a isize { + | -------------------------------------- in this impl... ... LL | fn has_bound<'b>(self, b: Inv<'b>) { - | ^^^^ lifetimes do not match method in trait + | ^^ `'b` is late-bound error[E0308]: method not compatible with trait --> $DIR/regions-bound-missing-bound-in-impl.rs:27:5 @@ -54,14 +82,45 @@ note: ...does not necessarily outlive the lifetime `'c` as defined here 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:42:20 +error[E0195]: lifetime parameters do not match the trait definition + --> $DIR/regions-bound-missing-bound-in-impl.rs:42:30 + | +LL | fn wrong_bound2(self, b: Inv, c: Inv, d: Inv) { + | ^^^ ^^^ | + = note: lifetime parameters differ in whether they are early- or late-bound +note: `'_` differs between the trait and impl + --> $DIR/regions-bound-missing-bound-in-impl.rs:13:21 + | +LL | pub trait Foo<'a, 't> { + | --------------------- in this trait... +... 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 + | ^^ -- this lifetime bound makes `'b` early-bound + | | + | `'b` is early-bound +... +LL | impl<'a, 't> Foo<'a, 't> for &'a isize { + | -------------------------------------- in this impl... +... +LL | fn wrong_bound2(self, b: Inv, c: Inv, d: Inv) { + | ^^^ `'_` is late-bound +note: `'_` differs between the trait and impl + --> $DIR/regions-bound-missing-bound-in-impl.rs:13:27 + | +LL | pub trait Foo<'a, 't> { + | --------------------- in this trait... +... +LL | fn wrong_bound2<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>); + | ^^ -- this lifetime bound makes `'d` early-bound + | | + | `'d` is early-bound +... +LL | impl<'a, 't> Foo<'a, 't> for &'a isize { + | -------------------------------------- in this impl... ... LL | fn wrong_bound2(self, b: Inv, c: Inv, d: Inv) { - | ^ lifetimes do not match method in trait + | ^^^ `'_` is late-bound error[E0276]: impl has stricter requirements than trait --> $DIR/regions-bound-missing-bound-in-impl.rs:49:26 diff --git a/tests/ui/error-codes/E0195.rs b/tests/ui/error-codes/E0195.rs index a7e51dff2f3fd..66968f70bd9e0 100644 --- a/tests/ui/error-codes/E0195.rs +++ b/tests/ui/error-codes/E0195.rs @@ -1,13 +1,25 @@ trait Trait { +//~^ NOTE in this trait... +//~| NOTE in this trait... fn bar<'a,'b:'a>(x: &'a str, y: &'b str); - //~^ NOTE lifetimes in impl do not match this associated function in trait + //~^ NOTE `'a` is early-bound + //~| NOTE this lifetime bound makes `'a` early-bound + //~| NOTE `'b` is early-bound + //~| NOTE this lifetime bound makes `'b` early-bound } struct Foo; impl Trait for Foo { - fn bar<'a,'b>(x: &'a str, y: &'b str) { //~ ERROR E0195 - //~^ NOTE lifetimes do not match associated function in trait +//~^ NOTE in this impl... +//~| NOTE in this impl... + fn bar<'a,'b>(x: &'a str, y: &'b str) { + //~^ ERROR E0195 + //~| NOTE `'a` differs between the trait and impl + //~| NOTE `'a` is late-bound + //~| NOTE `'b` differs between the trait and impl + //~| NOTE `'b` is late-bound + //~| NOTE lifetime parameters differ in whether they are early- or late-bound } } diff --git a/tests/ui/error-codes/E0195.stderr b/tests/ui/error-codes/E0195.stderr index 9767dee9aecd1..d0295b3643477 100644 --- a/tests/ui/error-codes/E0195.stderr +++ b/tests/ui/error-codes/E0195.stderr @@ -1,11 +1,42 @@ -error[E0195]: lifetime parameters or bounds on associated function `bar` do not match the trait declaration - --> $DIR/E0195.rs:9:11 +error[E0195]: lifetime parameters do not match the trait definition + --> $DIR/E0195.rs:16:12 | +LL | fn bar<'a,'b>(x: &'a str, y: &'b str) { + | ^^ ^^ + | + = note: lifetime parameters differ in whether they are early- or late-bound +note: `'a` differs between the trait and impl + --> $DIR/E0195.rs:4:12 + | +LL | trait Trait { + | ----------- in this trait... +... LL | fn bar<'a,'b:'a>(x: &'a str, y: &'b str); - | ---------- lifetimes in impl do not match this associated function in trait + | ^^ -- this lifetime bound makes `'a` early-bound + | | + | `'a` is early-bound +... +LL | impl Trait for Foo { + | ------------------ in this impl... +... +LL | fn bar<'a,'b>(x: &'a str, y: &'b str) { + | ^^ `'a` is late-bound +note: `'b` differs between the trait and impl + --> $DIR/E0195.rs:4:15 + | +LL | trait Trait { + | ----------- in this trait... +... +LL | fn bar<'a,'b:'a>(x: &'a str, y: &'b str); + | ^^ -- this lifetime bound makes `'b` early-bound + | | + | `'b` is early-bound +... +LL | impl Trait for Foo { + | ------------------ in this impl... ... LL | fn bar<'a,'b>(x: &'a str, y: &'b str) { - | ^^^^^^^ lifetimes do not match associated function in trait + | ^^ `'b` is late-bound error: aborting due to 1 previous error diff --git a/tests/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.stderr b/tests/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.stderr index e26cb22163f1e..f8a6252f991ea 100644 --- a/tests/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.stderr +++ b/tests/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.stderr @@ -10,26 +10,53 @@ LL | fn foo<'a, K>(self, _: T, _: K) where T: 'a, K: 'a; LL | fn foo<'a, K>(self, _: (), _: K) where { | ^^^^^^^ lifetimes do not match method in trait -error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration - --> $DIR/impl-missing-where-clause-lifetimes-from-trait.rs:23:11 +error[E0195]: lifetime parameters do not match the trait definition + --> $DIR/impl-missing-where-clause-lifetimes-from-trait.rs:23:12 | -LL | fn foo<'a>(&self, state: &'a State) -> &'a T - | ---- lifetimes in impl do not match this method in trait -LL | where -LL | T: 'a; - | -- this bound might be missing in the impl -... LL | fn foo<'a>(&self, state: &'a State) -> &'a T { - | ^^^^ lifetimes do not match method in trait + | ^^ + | + = note: lifetime parameters differ in whether they are early- or late-bound +note: `'a` differs between the trait and impl + --> $DIR/impl-missing-where-clause-lifetimes-from-trait.rs:14:12 + | +LL | trait Foo { + | ------------ in this trait... +LL | fn foo<'a>(&self, state: &'a State) -> &'a T + | ^^ `'a` is early-bound +LL | where +LL | T: 'a; + | -- this lifetime bound makes `'a` early-bound +... +LL | / impl Foo for F +LL | | where +LL | | F: Fn(&State) -> &T, + | |________________________- in this impl... +LL | { +LL | fn foo<'a>(&self, state: &'a State) -> &'a T { + | ^^ `'a` is late-bound -error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration - --> $DIR/impl-missing-where-clause-lifetimes-from-trait.rs:33:11 +error[E0195]: lifetime parameters do not match the trait definition + --> $DIR/impl-missing-where-clause-lifetimes-from-trait.rs:33:12 + | +LL | fn foo<'a: 'a>(&'a self) {} + | ^^ + | + = note: lifetime parameters differ in whether they are early- or late-bound +note: `'a` differs between the trait and impl + --> $DIR/impl-missing-where-clause-lifetimes-from-trait.rs:29:12 | +LL | trait Bar { + | --------- in this trait... LL | fn foo<'a>(&'a self) {} - | ---- lifetimes in impl do not match this method in trait + | ^^ `'a` is late-bound ... +LL | impl Bar for () { + | --------------- in this impl... LL | fn foo<'a: 'a>(&'a self) {} - | ^^^^^^^^ lifetimes do not match method in trait + | ^^ -- this lifetime bound makes `'a` early-bound + | | + | `'a` is early-bound error: aborting due to 3 previous errors