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 00302ec831cef..5addedd661b0b 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -2,9 +2,7 @@ use super::potentially_plural_count; use crate::errors::LifetimesOrBoundsMismatchOnTrait; use hir::def_id::{DefId, LocalDefId}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; -use rustc_errors::{ - pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed, MultiSpan, -}; +use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit; @@ -50,13 +48,7 @@ pub(super) fn compare_impl_method<'tcx>( let _: Result<_, ErrorGuaranteed> = try { check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, false)?; - compare_method_predicate_entailment( - tcx, - impl_m, - trait_m, - impl_trait_ref, - CheckImpliedWfMode::Check, - )?; + compare_method_predicate_entailment(tcx, impl_m, trait_m, impl_trait_ref)?; refine::check_refining_return_position_impl_trait_in_trait( tcx, impl_m, @@ -170,7 +162,6 @@ fn compare_method_predicate_entailment<'tcx>( impl_m: ty::AssocItem, trait_m: ty::AssocItem, impl_trait_ref: ty::TraitRef<'tcx>, - check_implied_wf: CheckImpliedWfMode, ) -> Result<(), ErrorGuaranteed> { let trait_to_impl_args = impl_trait_ref.args; @@ -317,7 +308,7 @@ fn compare_method_predicate_entailment<'tcx>( return Err(emitted); } - if check_implied_wf == CheckImpliedWfMode::Check && !(impl_sig, trait_sig).references_error() { + if !(impl_sig, trait_sig).references_error() { // Select obligations to make progress on inference before processing // the wf obligation below. // FIXME(-Znext-solver): Not needed when the hack below is removed. @@ -333,8 +324,9 @@ fn compare_method_predicate_entailment<'tcx>( // trigger the lint. Instead, let's only consider type outlives and // region outlives obligations. // - // FIXME(-Znext-solver): Try removing this hack again once - // the new solver is stable. + // FIXME(-Znext-solver): Try removing this hack again once the new + // solver is stable. We should just be able to register a WF pred for + // the fn sig. let mut wf_args: smallvec::SmallVec<[_; 4]> = unnormalized_impl_sig.inputs_and_output.iter().map(|ty| ty.into()).collect(); // Annoyingly, asking for the WF predicates of an array (with an unevaluated const (only?)) @@ -357,7 +349,7 @@ fn compare_method_predicate_entailment<'tcx>( // We need to register Projection oblgiations too, because we may end up with // an implied `X::Item: 'a`, which gets desugared into `X::Item = ?0`, `?0: 'a`. // If we only register the region outlives obligation, this leads to an unconstrained var. - // See `implied_bounds_entailment_alias_var` test. + // See `implied_bounds_entailment_alias_var.rs` test. ty::PredicateKind::Clause( ty::ClauseKind::RegionOutlives(..) | ty::ClauseKind::TypeOutlives(..) @@ -378,26 +370,8 @@ fn compare_method_predicate_entailment<'tcx>( // version. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - match check_implied_wf { - CheckImpliedWfMode::Check => { - let impl_m_hir_id = tcx.local_def_id_to_hir_id(impl_m_def_id); - return compare_method_predicate_entailment( - tcx, - impl_m, - trait_m, - impl_trait_ref, - CheckImpliedWfMode::Skip, - ) - .map(|()| { - // If the skip-mode was successful, emit a lint. - emit_implied_wf_lint(infcx.tcx, impl_m, impl_m_hir_id, vec![]); - }); - } - CheckImpliedWfMode::Skip => { - let reported = infcx.err_ctxt().report_fulfillment_errors(errors); - return Err(reported); - } - } + let reported = infcx.err_ctxt().report_fulfillment_errors(errors); + return Err(reported); } // Finally, resolve all regions. This catches wily misuses of @@ -408,119 +382,14 @@ fn compare_method_predicate_entailment<'tcx>( ); let errors = infcx.resolve_regions(&outlives_env); if !errors.is_empty() { - // FIXME(compiler-errors): This can be simplified when IMPLIED_BOUNDS_ENTAILMENT - // becomes a hard error (i.e. ideally we'd just call `resolve_regions_and_report_errors` - let impl_m_hir_id = tcx.local_def_id_to_hir_id(impl_m_def_id); - match check_implied_wf { - CheckImpliedWfMode::Check => { - return compare_method_predicate_entailment( - tcx, - impl_m, - trait_m, - impl_trait_ref, - CheckImpliedWfMode::Skip, - ) - .map(|()| { - let bad_args = extract_bad_args_for_implies_lint( - tcx, - &errors, - (trait_m, trait_sig), - // Unnormalized impl sig corresponds to the HIR types written - (impl_m, unnormalized_impl_sig), - impl_m_hir_id, - ); - // If the skip-mode was successful, emit a lint. - emit_implied_wf_lint(tcx, impl_m, impl_m_hir_id, bad_args); - }); - } - CheckImpliedWfMode::Skip => { - if infcx.tainted_by_errors().is_none() { - infcx.err_ctxt().report_region_errors(impl_m_def_id, &errors); - } - return Err(tcx - .sess - .span_delayed_bug(rustc_span::DUMMY_SP, "error should have been emitted")); - } - } + return Err(infcx + .tainted_by_errors() + .unwrap_or_else(|| infcx.err_ctxt().report_region_errors(impl_m_def_id, &errors))); } Ok(()) } -fn extract_bad_args_for_implies_lint<'tcx>( - tcx: TyCtxt<'tcx>, - errors: &[infer::RegionResolutionError<'tcx>], - (trait_m, trait_sig): (ty::AssocItem, ty::FnSig<'tcx>), - (impl_m, impl_sig): (ty::AssocItem, ty::FnSig<'tcx>), - hir_id: hir::HirId, -) -> Vec<(Span, Option)> { - let mut blame_generics = vec![]; - for error in errors { - // Look for the subregion origin that contains an input/output type - let origin = match error { - infer::RegionResolutionError::ConcreteFailure(o, ..) => o, - infer::RegionResolutionError::GenericBoundFailure(o, ..) => o, - infer::RegionResolutionError::SubSupConflict(_, _, o, ..) => o, - infer::RegionResolutionError::UpperBoundUniverseConflict(.., o, _) => o, - }; - // Extract (possible) input/output types from origin - match origin { - infer::SubregionOrigin::Subtype(trace) => { - if let Some((a, b)) = trace.values.ty() { - blame_generics.extend([a, b]); - } - } - infer::SubregionOrigin::RelateParamBound(_, ty, _) => blame_generics.push(*ty), - infer::SubregionOrigin::ReferenceOutlivesReferent(ty, _) => blame_generics.push(*ty), - _ => {} - } - } - - let fn_decl = tcx.hir().fn_decl_by_hir_id(hir_id).unwrap(); - let opt_ret_ty = match fn_decl.output { - hir::FnRetTy::DefaultReturn(_) => None, - hir::FnRetTy::Return(ty) => Some(ty), - }; - - // Map late-bound regions from trait to impl, so the names are right. - let mapping = std::iter::zip( - tcx.fn_sig(trait_m.def_id).skip_binder().bound_vars(), - tcx.fn_sig(impl_m.def_id).skip_binder().bound_vars(), - ) - .filter_map(|(impl_bv, trait_bv)| { - if let ty::BoundVariableKind::Region(impl_bv) = impl_bv - && let ty::BoundVariableKind::Region(trait_bv) = trait_bv - { - Some((impl_bv, trait_bv)) - } else { - None - } - }) - .collect(); - - // For each arg, see if it was in the "blame" of any of the region errors. - // If so, then try to produce a suggestion to replace the argument type with - // one from the trait. - let mut bad_args = vec![]; - for (idx, (ty, hir_ty)) in - std::iter::zip(impl_sig.inputs_and_output, fn_decl.inputs.iter().chain(opt_ret_ty)) - .enumerate() - { - let expected_ty = trait_sig.inputs_and_output[idx] - .fold_with(&mut RemapLateBound { tcx, mapping: &mapping }); - if blame_generics.iter().any(|blame| ty.contains(*blame)) { - let expected_ty_sugg = expected_ty.to_string(); - bad_args.push(( - hir_ty.span, - // Only suggest something if it actually changed. - (expected_ty_sugg != ty.to_string()).then_some(expected_ty_sugg), - )); - } - } - - bad_args -} - struct RemapLateBound<'a, 'tcx> { tcx: TyCtxt<'tcx>, mapping: &'a FxHashMap, @@ -544,53 +413,6 @@ impl<'tcx> TypeFolder> for RemapLateBound<'_, 'tcx> { } } -fn emit_implied_wf_lint<'tcx>( - tcx: TyCtxt<'tcx>, - impl_m: ty::AssocItem, - hir_id: hir::HirId, - bad_args: Vec<(Span, Option)>, -) { - let span: MultiSpan = if bad_args.is_empty() { - tcx.def_span(impl_m.def_id).into() - } else { - bad_args.iter().map(|(span, _)| *span).collect::>().into() - }; - tcx.struct_span_lint_hir( - rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT, - hir_id, - span, - "impl method assumes more implied bounds than the corresponding trait method", - |lint| { - let bad_args: Vec<_> = - bad_args.into_iter().filter_map(|(span, sugg)| Some((span, sugg?))).collect(); - if !bad_args.is_empty() { - lint.multipart_suggestion( - format!( - "replace {} type{} to make the impl signature compatible", - pluralize!("this", bad_args.len()), - pluralize!(bad_args.len()) - ), - bad_args, - Applicability::MaybeIncorrect, - ); - } - lint - }, - ); -} - -#[derive(Debug, PartialEq, Eq)] -enum CheckImpliedWfMode { - /// Checks implied well-formedness of the impl method. If it fails, we will - /// re-check with `Skip`, and emit a lint if it succeeds. - Check, - /// Skips checking implied well-formedness of the impl method, but will emit - /// a lint if the `compare_method_predicate_entailment` succeeded. This means that - /// the reason that we had failed earlier during `Check` was due to the impl - /// having stronger requirements than the trait. - Skip, -} - fn compare_asyncness<'tcx>( tcx: TyCtxt<'tcx>, impl_m: ty::AssocItem, diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index e6e445c54b1e3..a18d9e4576ed0 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -4236,44 +4236,10 @@ declare_lint! { } declare_lint! { - /// The `implied_bounds_entailment` lint detects cases where the arguments of an impl method - /// have stronger implied bounds than those from the trait method it's implementing. - /// - /// ### Example - /// - /// ```rust,compile_fail - /// #![deny(implied_bounds_entailment)] - /// - /// trait Trait { - /// fn get<'s>(s: &'s str, _: &'static &'static ()) -> &'static str; - /// } - /// - /// impl Trait for () { - /// fn get<'s>(s: &'s str, _: &'static &'s ()) -> &'static str { - /// s - /// } - /// } - /// - /// let val = <() as Trait>::get(&String::from("blah blah blah"), &&()); - /// println!("{}", val); - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// Neither the trait method, which provides no implied bounds about `'s`, nor the impl, - /// requires the main function to prove that 's: 'static, but the impl method is allowed - /// to assume that `'s: 'static` within its own body. - /// - /// This can be used to implement an unsound API if used incorrectly. + /// This lint has been removed in favor of a hard error. pub IMPLIED_BOUNDS_ENTAILMENT, Deny, "impl method assumes more implied bounds than its corresponding trait method", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, - reference: "issue #105572 ", - }; } declare_lint! { diff --git a/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.rs b/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.rs index 6ccbb5bb26651..280856805e551 100644 --- a/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.rs +++ b/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.rs @@ -1,5 +1,3 @@ -#![deny(implied_bounds_entailment)] - trait Project { type Ty; } @@ -11,8 +9,7 @@ trait Trait { } impl Trait for () { fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str { - //~^ ERROR impl method assumes more implied bounds than the corresponding trait method - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~^ ERROR cannot infer an appropriate lifetime for lifetime parameter 's in generic type due to conflicting requirements s } } diff --git a/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr b/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr index 86b12cf8fa291..b9515fdc1ce6c 100644 --- a/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr +++ b/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr @@ -1,31 +1,28 @@ -error: impl method assumes more implied bounds than the corresponding trait method - --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:13:31 +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 's in generic type due to conflicting requirements + --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:11:5 | LL | fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #105572 -note: the lint level is defined here - --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:1:9 - | -LL | #![deny(implied_bounds_entailment)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - -Future incompatibility report: Future breakage diagnostic: -error: impl method assumes more implied bounds than the corresponding trait method - --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:13:31 +note: first, the lifetime cannot outlive the lifetime `'s` as defined here... + --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:11:12 | LL | fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `()` + | ^^ +note: ...so that the method type is compatible with trait + --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:11:5 | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #105572 -note: the lint level is defined here - --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:1:9 +LL | fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: expected `fn(&'s str, ()) -> &'static str` + found `fn(&str, ()) -> &'static str` + = note: but, the lifetime must be valid for the static lifetime... +note: ...so that the reference type `&'static &()` does not outlive the data it points at + --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:11:5 | -LL | #![deny(implied_bounds_entailment)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/tests/ui/implied-bounds/impl-implied-bounds-compatibility.rs b/tests/ui/implied-bounds/impl-implied-bounds-compatibility.rs index d097bc16a2214..7f3817b326adc 100644 --- a/tests/ui/implied-bounds/impl-implied-bounds-compatibility.rs +++ b/tests/ui/implied-bounds/impl-implied-bounds-compatibility.rs @@ -1,5 +1,3 @@ -#![deny(implied_bounds_entailment)] - use std::cell::RefCell; pub struct MessageListeners<'a> { @@ -12,8 +10,7 @@ pub trait MessageListenersInterface { impl<'a> MessageListenersInterface for MessageListeners<'a> { fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> { - //~^ ERROR impl method assumes more implied bounds than the corresponding trait method - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~^ ERROR cannot infer an appropriate lifetime for lifetime parameter 'b in generic type due to conflicting requirements self } } diff --git a/tests/ui/implied-bounds/impl-implied-bounds-compatibility.stderr b/tests/ui/implied-bounds/impl-implied-bounds-compatibility.stderr index a89645c128bfe..f7a8c3e98be49 100644 --- a/tests/ui/implied-bounds/impl-implied-bounds-compatibility.stderr +++ b/tests/ui/implied-bounds/impl-implied-bounds-compatibility.stderr @@ -1,31 +1,32 @@ -error: impl method assumes more implied bounds than the corresponding trait method - --> $DIR/impl-implied-bounds-compatibility.rs:14:35 +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'b in generic type due to conflicting requirements + --> $DIR/impl-implied-bounds-compatibility.rs:12:5 | LL | fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> { - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `&'b MessageListeners<'b>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #105572 -note: the lint level is defined here - --> $DIR/impl-implied-bounds-compatibility.rs:1:9 +note: first, the lifetime cannot outlive the lifetime `'c` as defined here... + --> $DIR/impl-implied-bounds-compatibility.rs:12:5 | -LL | #![deny(implied_bounds_entailment)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - -Future incompatibility report: Future breakage diagnostic: -error: impl method assumes more implied bounds than the corresponding trait method - --> $DIR/impl-implied-bounds-compatibility.rs:14:35 +LL | fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...so that the method type is compatible with trait + --> $DIR/impl-implied-bounds-compatibility.rs:12:5 | LL | fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> { - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `&'b MessageListeners<'b>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: expected `fn(&'c MessageListeners<'a>) -> &'c MessageListeners<'c>` + found `fn(&MessageListeners<'a>) -> &'a MessageListeners<'_>` +note: but, the lifetime must be valid for the lifetime `'a` as defined here... + --> $DIR/impl-implied-bounds-compatibility.rs:11:6 | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #105572 -note: the lint level is defined here - --> $DIR/impl-implied-bounds-compatibility.rs:1:9 +LL | impl<'a> MessageListenersInterface for MessageListeners<'a> { + | ^^ +note: ...so that the reference type `&'a MessageListeners<'_>` does not outlive the data it points at + --> $DIR/impl-implied-bounds-compatibility.rs:12:5 | -LL | #![deny(implied_bounds_entailment)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/tests/ui/regions/resolve-re-error-ice.rs b/tests/ui/regions/resolve-re-error-ice.rs index f37b27a82b363..bf6defb9bae36 100644 --- a/tests/ui/regions/resolve-re-error-ice.rs +++ b/tests/ui/regions/resolve-re-error-ice.rs @@ -1,8 +1,3 @@ -// check-pass - -// Allow this for now, can remove this UI test when this becomes a hard error. -#![allow(implied_bounds_entailment)] - use std::collections::hash_map::{Keys, HashMap}; use std::marker::PhantomData; @@ -15,6 +10,7 @@ struct Subject<'a, T, V, R>(PhantomData<(&'a T, V, R)>); impl<'a, K, V, R> MapAssertion<'a, K, V, R> for Subject<'a, HashMap, (), R> { fn key_set(&self) -> Subject<'a, Keys, (), R> { + //~^ ERROR cannot infer an appropriate lifetime for lifetime parameter '_ in generic type due to conflicting requirements todo!() } } diff --git a/tests/ui/regions/resolve-re-error-ice.stderr b/tests/ui/regions/resolve-re-error-ice.stderr index e7003e1c32f64..796f408ec19b2 100644 --- a/tests/ui/regions/resolve-re-error-ice.stderr +++ b/tests/ui/regions/resolve-re-error-ice.stderr @@ -1,15 +1,37 @@ -Future incompatibility report: Future breakage diagnostic: -warning: impl method assumes more implied bounds than the corresponding trait method - --> $DIR/resolve-re-error-ice.rs:17:16 +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter '_ in generic type due to conflicting requirements + --> $DIR/resolve-re-error-ice.rs:12:5 | LL | fn key_set(&self) -> Subject<'a, Keys, (), R> { - | ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `Subject<'_, std::collections::hash_map::Keys<'_, K, V>, (), R>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #105572 -note: the lint level is defined here - --> $DIR/resolve-re-error-ice.rs:4:10 +note: first, the lifetime cannot outlive the anonymous lifetime defined here... + --> $DIR/resolve-re-error-ice.rs:5:16 | -LL | #![allow(implied_bounds_entailment)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn key_set(&self) -> Subject, (), R>; + | ^^^^^ +note: ...so that the method type is compatible with trait + --> $DIR/resolve-re-error-ice.rs:12:5 + | +LL | fn key_set(&self) -> Subject<'a, Keys, (), R> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: expected `fn(&Subject<'a, HashMap, (), R>) -> Subject<'_, std::collections::hash_map::Keys<'_, _, _>, _, _>` + found `fn(&Subject<'a, HashMap, (), R>) -> Subject<'a, std::collections::hash_map::Keys<'_, _, _>, _, _>` +note: but, the lifetime must be valid for the lifetime `'a` as defined here... + --> $DIR/resolve-re-error-ice.rs:10:6 + | +LL | impl<'a, K, V, R> MapAssertion<'a, K, V, R> for Subject<'a, HashMap, (), R> + | ^^ +note: ...so that the type `std::collections::hash_map::Keys<'_, K, V>` will meet its required lifetime bounds... + --> $DIR/resolve-re-error-ice.rs:12:5 + | +LL | fn key_set(&self) -> Subject<'a, Keys, (), R> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...that is required by this bound + --> $DIR/resolve-re-error-ice.rs:8:29 + | +LL | struct Subject<'a, T, V, R>(PhantomData<(&'a T, V, R)>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error +For more information about this error, try `rustc --explain E0495`.