Only check outlives goals on impl compared to trait
This commit is contained in:
parent
a6f8aa5a09
commit
3028dc4ef7
3 changed files with 77 additions and 12 deletions
|
@ -1,7 +1,7 @@
|
|||
use super::potentially_plural_count;
|
||||
use crate::errors::LifetimesOrBoundsMismatchOnTrait;
|
||||
use hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
|
||||
use rustc_errors::{
|
||||
pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed, MultiSpan,
|
||||
};
|
||||
|
@ -265,7 +265,6 @@ fn compare_method_predicate_entailment<'tcx>(
|
|||
infer::HigherRankedType,
|
||||
tcx.fn_sig(impl_m.def_id).instantiate_identity(),
|
||||
);
|
||||
let unnormalized_impl_fty = Ty::new_fn_ptr(tcx, ty::Binder::dummy(unnormalized_impl_sig));
|
||||
|
||||
let norm_cause = ObligationCause::misc(impl_m_span, impl_m_def_id);
|
||||
let impl_sig = ocx.normalize(&norm_cause, param_env, unnormalized_impl_sig);
|
||||
|
@ -309,16 +308,44 @@ fn compare_method_predicate_entailment<'tcx>(
|
|||
}
|
||||
|
||||
if check_implied_wf == CheckImpliedWfMode::Check && !(impl_sig, trait_sig).references_error() {
|
||||
// We need to check that the impl's args are well-formed given
|
||||
// the hybrid param-env (impl + trait method where-clauses).
|
||||
ocx.register_obligation(traits::Obligation::new(
|
||||
infcx.tcx,
|
||||
ObligationCause::dummy(),
|
||||
// See #108544. Annoying, we can end up in cases where, because of winnowing,
|
||||
// we pick param env candidates over a more general impl, leading to more
|
||||
// stricter lifetime requirements than we would otherwise need. This can
|
||||
// trigger the lint. Instead, let's only consider type outlives and
|
||||
// region outlives obligations.
|
||||
//
|
||||
// FIXME(-Ztrait-solver=next): Try removing this hack again once
|
||||
// the new solver is stable.
|
||||
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?))
|
||||
// will give back the well-formed predicate of the same array.
|
||||
let mut wf_args_seen: FxHashSet<_> = wf_args.iter().copied().collect();
|
||||
while let Some(arg) = wf_args.pop() {
|
||||
let Some(obligations) = rustc_trait_selection::traits::wf::obligations(
|
||||
infcx,
|
||||
param_env,
|
||||
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(
|
||||
unnormalized_impl_fty.into(),
|
||||
))),
|
||||
));
|
||||
impl_m_def_id,
|
||||
0,
|
||||
arg,
|
||||
impl_m_span,
|
||||
) else {
|
||||
continue;
|
||||
};
|
||||
for obligation in obligations {
|
||||
match obligation.predicate.kind().skip_binder() {
|
||||
ty::PredicateKind::Clause(
|
||||
ty::ClauseKind::RegionOutlives(..) | ty::ClauseKind::TypeOutlives(..),
|
||||
) => ocx.register_obligation(obligation),
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
|
||||
if wf_args_seen.insert(arg) {
|
||||
wf_args.push(arg)
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that all obligations are satisfied by the implementation's
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
// check-pass
|
||||
// See issue #109356. We don't want a false positive to the `implied_bounds_entailment` lint.
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
pub trait Trait {
|
||||
fn method(self) -> Option<Cow<'static, str>>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
impl<'a> Trait for Cow<'a, str> {
|
||||
// If we're not careful here, we'll check `WF(return-type)` using the trait
|
||||
// and impl where clauses, requiring that `Cow<'a, str>: Sized`. This is
|
||||
// obviously true, but if we pick the `Self: Sized` clause from the trait
|
||||
// over the "inherent impl", we will require `'a == 'static`, which triggers
|
||||
// the `implied_bounds_entailment` lint.
|
||||
fn method(self) -> Option<Cow<'static, str>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
15
tests/ui/implied-bounds/trait-where-clause-implied.rs
Normal file
15
tests/ui/implied-bounds/trait-where-clause-implied.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
// check-pass
|
||||
|
||||
pub trait Trait<'a, 'b> {
|
||||
fn method(self, _: &'static &'static ())
|
||||
where
|
||||
'a: 'b;
|
||||
}
|
||||
|
||||
impl<'a> Trait<'a, 'static> for () {
|
||||
// On first glance, this seems like we have the extra implied bound that
|
||||
// `'a: 'static`, but we know this from the trait method where clause.
|
||||
fn method(self, _: &'static &'a ()) {}
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue