Make IMPLIED_BOUNDS_ENTAILMENT into a hard error from a lint
This commit is contained in:
parent
ca5c68a110
commit
629d3511b7
8 changed files with 94 additions and 295 deletions
|
@ -2,9 +2,7 @@ use super::potentially_plural_count;
|
||||||
use crate::errors::LifetimesOrBoundsMismatchOnTrait;
|
use crate::errors::LifetimesOrBoundsMismatchOnTrait;
|
||||||
use hir::def_id::{DefId, LocalDefId};
|
use hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
|
||||||
use rustc_errors::{
|
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
|
||||||
pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed, MultiSpan,
|
|
||||||
};
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::intravisit;
|
use rustc_hir::intravisit;
|
||||||
|
@ -50,13 +48,7 @@ pub(super) fn compare_impl_method<'tcx>(
|
||||||
|
|
||||||
let _: Result<_, ErrorGuaranteed> = try {
|
let _: Result<_, ErrorGuaranteed> = try {
|
||||||
check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, false)?;
|
check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, false)?;
|
||||||
compare_method_predicate_entailment(
|
compare_method_predicate_entailment(tcx, impl_m, trait_m, impl_trait_ref)?;
|
||||||
tcx,
|
|
||||||
impl_m,
|
|
||||||
trait_m,
|
|
||||||
impl_trait_ref,
|
|
||||||
CheckImpliedWfMode::Check,
|
|
||||||
)?;
|
|
||||||
refine::check_refining_return_position_impl_trait_in_trait(
|
refine::check_refining_return_position_impl_trait_in_trait(
|
||||||
tcx,
|
tcx,
|
||||||
impl_m,
|
impl_m,
|
||||||
|
@ -170,7 +162,6 @@ fn compare_method_predicate_entailment<'tcx>(
|
||||||
impl_m: ty::AssocItem,
|
impl_m: ty::AssocItem,
|
||||||
trait_m: ty::AssocItem,
|
trait_m: ty::AssocItem,
|
||||||
impl_trait_ref: ty::TraitRef<'tcx>,
|
impl_trait_ref: ty::TraitRef<'tcx>,
|
||||||
check_implied_wf: CheckImpliedWfMode,
|
|
||||||
) -> Result<(), ErrorGuaranteed> {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
let trait_to_impl_args = impl_trait_ref.args;
|
let trait_to_impl_args = impl_trait_ref.args;
|
||||||
|
|
||||||
|
@ -317,7 +308,7 @@ fn compare_method_predicate_entailment<'tcx>(
|
||||||
return Err(emitted);
|
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
|
// Select obligations to make progress on inference before processing
|
||||||
// the wf obligation below.
|
// the wf obligation below.
|
||||||
// FIXME(-Znext-solver): Not needed when the hack below is removed.
|
// 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
|
// trigger the lint. Instead, let's only consider type outlives and
|
||||||
// region outlives obligations.
|
// region outlives obligations.
|
||||||
//
|
//
|
||||||
// FIXME(-Znext-solver): Try removing this hack again once
|
// FIXME(-Znext-solver): Try removing this hack again once the new
|
||||||
// the new solver is stable.
|
// solver is stable. We should just be able to register a WF pred for
|
||||||
|
// the fn sig.
|
||||||
let mut wf_args: smallvec::SmallVec<[_; 4]> =
|
let mut wf_args: smallvec::SmallVec<[_; 4]> =
|
||||||
unnormalized_impl_sig.inputs_and_output.iter().map(|ty| ty.into()).collect();
|
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?))
|
// 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
|
// 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`.
|
// 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.
|
// 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::PredicateKind::Clause(
|
||||||
ty::ClauseKind::RegionOutlives(..)
|
ty::ClauseKind::RegionOutlives(..)
|
||||||
| ty::ClauseKind::TypeOutlives(..)
|
| ty::ClauseKind::TypeOutlives(..)
|
||||||
|
@ -378,27 +370,9 @@ fn compare_method_predicate_entailment<'tcx>(
|
||||||
// version.
|
// version.
|
||||||
let errors = ocx.select_all_or_error();
|
let errors = ocx.select_all_or_error();
|
||||||
if !errors.is_empty() {
|
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);
|
let reported = infcx.err_ctxt().report_fulfillment_errors(errors);
|
||||||
return Err(reported);
|
return Err(reported);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, resolve all regions. This catches wily misuses of
|
// Finally, resolve all regions. This catches wily misuses of
|
||||||
// lifetime parameters.
|
// lifetime parameters.
|
||||||
|
@ -408,119 +382,14 @@ fn compare_method_predicate_entailment<'tcx>(
|
||||||
);
|
);
|
||||||
let errors = infcx.resolve_regions(&outlives_env);
|
let errors = infcx.resolve_regions(&outlives_env);
|
||||||
if !errors.is_empty() {
|
if !errors.is_empty() {
|
||||||
// FIXME(compiler-errors): This can be simplified when IMPLIED_BOUNDS_ENTAILMENT
|
return Err(infcx
|
||||||
// becomes a hard error (i.e. ideally we'd just call `resolve_regions_and_report_errors`
|
.tainted_by_errors()
|
||||||
let impl_m_hir_id = tcx.local_def_id_to_hir_id(impl_m_def_id);
|
.unwrap_or_else(|| infcx.err_ctxt().report_region_errors(impl_m_def_id, &errors)));
|
||||||
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"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
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<String>)> {
|
|
||||||
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> {
|
struct RemapLateBound<'a, 'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
mapping: &'a FxHashMap<ty::BoundRegionKind, ty::BoundRegionKind>,
|
mapping: &'a FxHashMap<ty::BoundRegionKind, ty::BoundRegionKind>,
|
||||||
|
@ -544,52 +413,6 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> 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<String>)>,
|
|
||||||
) {
|
|
||||||
let span: MultiSpan = if bad_args.is_empty() {
|
|
||||||
tcx.def_span(impl_m.def_id).into()
|
|
||||||
} else {
|
|
||||||
bad_args.iter().map(|(span, _)| *span).collect::<Vec<_>>().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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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>(
|
fn compare_asyncness<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
impl_m: ty::AssocItem,
|
impl_m: ty::AssocItem,
|
||||||
|
|
|
@ -4236,44 +4236,10 @@ declare_lint! {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
/// The `implied_bounds_entailment` lint detects cases where the arguments of an impl method
|
/// This lint has been removed in favor of a hard error.
|
||||||
/// 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.
|
|
||||||
pub IMPLIED_BOUNDS_ENTAILMENT,
|
pub IMPLIED_BOUNDS_ENTAILMENT,
|
||||||
Deny,
|
Deny,
|
||||||
"impl method assumes more implied bounds than its corresponding trait method",
|
"impl method assumes more implied bounds than its corresponding trait method",
|
||||||
@future_incompatible = FutureIncompatibleInfo {
|
|
||||||
reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
|
|
||||||
reference: "issue #105572 <https://github.com/rust-lang/rust/issues/105572>",
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
#![deny(implied_bounds_entailment)]
|
|
||||||
|
|
||||||
trait Project {
|
trait Project {
|
||||||
type Ty;
|
type Ty;
|
||||||
}
|
}
|
||||||
|
@ -11,8 +9,7 @@ trait Trait {
|
||||||
}
|
}
|
||||||
impl Trait for () {
|
impl Trait for () {
|
||||||
fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str {
|
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
|
//~^ ERROR cannot infer an appropriate lifetime for lifetime parameter 's in generic type due to conflicting requirements
|
||||||
//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +1,28 @@
|
||||||
error: impl method assumes more implied bounds than the corresponding trait method
|
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:13:31
|
--> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:11:5
|
||||||
|
|
|
|
||||||
LL | fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str {
|
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: first, the lifetime cannot outlive the lifetime `'s` as defined here...
|
||||||
= note: for more information, see issue #105572 <https://github.com/rust-lang/rust/issues/105572>
|
--> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:11:12
|
||||||
note: the lint level is defined here
|
|
||||||
--> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:1:9
|
|
||||||
|
|
|
|
||||||
LL | #![deny(implied_bounds_entailment)]
|
LL | fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^
|
||||||
|
note: ...so that the method type is compatible with trait
|
||||||
|
--> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:11:5
|
||||||
|
|
|
||||||
|
LL | fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
= note: expected `fn(&'s _, ()) -> &'static _`
|
||||||
|
found `fn(&_, ()) -> &'static _`
|
||||||
|
= 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 | fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
Future incompatibility report: Future breakage diagnostic:
|
For more information about this error, try `rustc --explain E0495`.
|
||||||
error: impl method assumes more implied bounds than the corresponding trait method
|
|
||||||
--> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:13:31
|
|
||||||
|
|
|
||||||
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 <https://github.com/rust-lang/rust/issues/105572>
|
|
||||||
note: the lint level is defined here
|
|
||||||
--> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:1:9
|
|
||||||
|
|
|
||||||
LL | #![deny(implied_bounds_entailment)]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
#![deny(implied_bounds_entailment)]
|
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
pub struct MessageListeners<'a> {
|
pub struct MessageListeners<'a> {
|
||||||
|
@ -12,8 +10,7 @@ pub trait MessageListenersInterface {
|
||||||
|
|
||||||
impl<'a> MessageListenersInterface for MessageListeners<'a> {
|
impl<'a> MessageListenersInterface for MessageListeners<'a> {
|
||||||
fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> {
|
fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> {
|
||||||
//~^ ERROR impl method assumes more implied bounds than the corresponding trait method
|
//~^ ERROR cannot infer an appropriate lifetime for lifetime parameter 'b in generic type due to conflicting requirements
|
||||||
//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +1,32 @@
|
||||||
error: impl method assumes more implied bounds than the corresponding trait method
|
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'b in generic type due to conflicting requirements
|
||||||
--> $DIR/impl-implied-bounds-compatibility.rs:14:35
|
--> $DIR/impl-implied-bounds-compatibility.rs:12:5
|
||||||
|
|
|
|
||||||
LL | fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> {
|
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: first, the lifetime cannot outlive the lifetime `'c` as defined here...
|
||||||
= note: for more information, see issue #105572 <https://github.com/rust-lang/rust/issues/105572>
|
--> $DIR/impl-implied-bounds-compatibility.rs:12:5
|
||||||
note: the lint level is defined here
|
|
||||||
--> $DIR/impl-implied-bounds-compatibility.rs:1:9
|
|
||||||
|
|
|
|
||||||
LL | #![deny(implied_bounds_entailment)]
|
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> {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
= note: expected `fn(&'c MessageListeners<'_>) -> &'c MessageListeners<'c>`
|
||||||
|
found `fn(&MessageListeners<'_>) -> &'a MessageListeners<'_>`
|
||||||
|
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
|
||||||
|
--> $DIR/impl-implied-bounds-compatibility.rs:11:6
|
||||||
|
|
|
||||||
|
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 | fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
Future incompatibility report: Future breakage diagnostic:
|
For more information about this error, try `rustc --explain E0495`.
|
||||||
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> {
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ 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 <https://github.com/rust-lang/rust/issues/105572>
|
|
||||||
note: the lint level is defined here
|
|
||||||
--> $DIR/impl-implied-bounds-compatibility.rs:1:9
|
|
||||||
|
|
|
||||||
LL | #![deny(implied_bounds_entailment)]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
|
|
|
@ -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::collections::hash_map::{Keys, HashMap};
|
||||||
use std::marker::PhantomData;
|
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<K, V>, (), R>
|
impl<'a, K, V, R> MapAssertion<'a, K, V, R> for Subject<'a, HashMap<K, V>, (), R>
|
||||||
{
|
{
|
||||||
fn key_set(&self) -> Subject<'a, Keys<K, V>, (), R> {
|
fn key_set(&self) -> Subject<'a, Keys<K, V>, (), R> {
|
||||||
|
//~^ ERROR cannot infer an appropriate lifetime for lifetime parameter '_ in generic type due to conflicting requirements
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,37 @@
|
||||||
Future incompatibility report: Future breakage diagnostic:
|
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter '_ in generic type due to conflicting requirements
|
||||||
warning: impl method assumes more implied bounds than the corresponding trait method
|
--> $DIR/resolve-re-error-ice.rs:12:5
|
||||||
--> $DIR/resolve-re-error-ice.rs:17:16
|
|
||||||
|
|
|
|
||||||
LL | fn key_set(&self) -> Subject<'a, Keys<K, V>, (), R> {
|
LL | fn key_set(&self) -> Subject<'a, Keys<K, V>, (), 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: first, the lifetime cannot outlive the anonymous lifetime defined here...
|
||||||
= note: for more information, see issue #105572 <https://github.com/rust-lang/rust/issues/105572>
|
--> $DIR/resolve-re-error-ice.rs:5:16
|
||||||
note: the lint level is defined here
|
|
||||||
--> $DIR/resolve-re-error-ice.rs:4:10
|
|
||||||
|
|
|
|
||||||
LL | #![allow(implied_bounds_entailment)]
|
LL | fn key_set(&self) -> Subject<Keys<K, V>, (), 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<K, V>, (), R> {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
= note: expected `fn(&Subject<'_, _, _, _>) -> Subject<'_, std::collections::hash_map::Keys<'_, _, _>, _, _>`
|
||||||
|
found `fn(&Subject<'_, _, _, _>) -> 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<K, V>, (), 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<K, V>, (), 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 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0495`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue