Skip to content

Commit

Permalink
Auto merge of #109356 - jackh726:issue-108544, r=lcnr
Browse files Browse the repository at this point in the history
Only check outlives goals on impl compared to trait

Fixes #108544

r? `@compiler-errors`
  • Loading branch information
bors committed Aug 12, 2023
2 parents b08dd92 + 3028dc4 commit f1b8548
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 12 deletions.
51 changes: 39 additions & 12 deletions compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
Original file line number Diff line number Diff line change
@@ -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,
};
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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(),
param_env,
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(
unnormalized_impl_fty.into(),
))),
));
// 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,
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
Expand Down
Original file line number Diff line number Diff line change
@@ -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 changes: 15 additions & 0 deletions tests/ui/implied-bounds/trait-where-clause-implied.rs
Original file line number Diff line number Diff line change
@@ -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() {}

0 comments on commit f1b8548

Please sign in to comment.