Permit negative impls coherence to take advantage of implied bounds

This commit is contained in:
Santiago Pastorino 2022-08-22 15:52:49 -03:00
parent 5ff45dc89e
commit ac0b6af37b
No known key found for this signature in database
GPG Key ID: 8131A24E0C79EFAF
3 changed files with 29 additions and 22 deletions

View File

@ -6,12 +6,13 @@
use crate::infer::outlives::env::OutlivesEnvironment;
use crate::infer::{CombinedSnapshot, InferOk};
use crate::traits::outlives_bounds::InferCtxtExt as _;
use crate::traits::select::IntercrateAmbiguityCause;
use crate::traits::util::impl_subject_and_oblig;
use crate::traits::SkipLeakCheck;
use crate::traits::{
self, Normalized, Obligation, ObligationCause, PredicateObligation, PredicateObligations,
SelectionContext,
self, Normalized, Obligation, ObligationCause, ObligationCtxt, PredicateObligation,
PredicateObligations, SelectionContext,
};
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::Diagnostic;
@ -322,7 +323,7 @@ fn negative_impl<'cx, 'tcx>(
let (subject2, obligations) =
impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs);
!equate(&infcx, impl_env, subject1, subject2, obligations)
!equate(&infcx, impl_env, subject1, subject2, obligations, impl1_def_id)
})
}
@ -332,6 +333,7 @@ fn equate<'cx, 'tcx>(
subject1: ImplSubject<'tcx>,
subject2: ImplSubject<'tcx>,
obligations: impl Iterator<Item = PredicateObligation<'tcx>>,
body_def_id: DefId,
) -> bool {
// do the impls unify? If not, not disjoint.
let Ok(InferOk { obligations: more_obligations, .. }) =
@ -342,8 +344,10 @@ fn equate<'cx, 'tcx>(
};
let selcx = &mut SelectionContext::new(&infcx);
let opt_failing_obligation =
obligations.into_iter().chain(more_obligations).find(|o| negative_impl_exists(selcx, o));
let opt_failing_obligation = obligations
.into_iter()
.chain(more_obligations)
.find(|o| negative_impl_exists(selcx, o, body_def_id));
if let Some(failing_obligation) = opt_failing_obligation {
debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
@ -358,14 +362,15 @@ fn equate<'cx, 'tcx>(
fn negative_impl_exists<'cx, 'tcx>(
selcx: &SelectionContext<'cx, 'tcx>,
o: &PredicateObligation<'tcx>,
body_def_id: DefId,
) -> bool {
if resolve_negative_obligation(selcx.infcx().fork(), o) {
if resolve_negative_obligation(selcx.infcx().fork(), o, body_def_id) {
return true;
}
// Try to prove a negative obligation exists for super predicates
for o in util::elaborate_predicates(selcx.tcx(), iter::once(o.predicate)) {
if resolve_negative_obligation(selcx.infcx().fork(), &o) {
if resolve_negative_obligation(selcx.infcx().fork(), &o, body_def_id) {
return true;
}
}
@ -377,6 +382,7 @@ fn negative_impl_exists<'cx, 'tcx>(
fn resolve_negative_obligation<'cx, 'tcx>(
infcx: InferCtxt<'cx, 'tcx>,
o: &PredicateObligation<'tcx>,
body_def_id: DefId,
) -> bool {
let tcx = infcx.tcx;
@ -390,7 +396,19 @@ fn resolve_negative_obligation<'cx, 'tcx>(
return false;
}
let outlives_env = OutlivesEnvironment::new(param_env);
let outlives_env = if let Some(body_def_id) = body_def_id.as_local() {
let body_id = tcx.hir().local_def_id_to_hir_id(body_def_id);
let ocx = ObligationCtxt::new(&infcx);
let wf_tys = ocx.assumed_wf_types(param_env, DUMMY_SP, body_def_id);
OutlivesEnvironment::with_bounds(
param_env,
Some(&infcx),
infcx.implied_bounds_tys(param_env, body_id, wf_tys),
)
} else {
OutlivesEnvironment::new(param_env)
};
infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env);
infcx.resolve_regions(&outlives_env).is_empty()

View File

@ -1,9 +1,9 @@
// revisions: stock with_negative_coherence
//[with_negative_coherence] check-pass
#![feature(negative_impls)]
#![cfg_attr(with_negative_coherence, feature(with_negative_coherence))]
// FIXME: this should compile
trait MyPredicate<'a> {}
impl<'a, T> !MyPredicate<'a> for &'a T where T: 'a {}
@ -12,6 +12,6 @@ trait MyTrait<'a> {}
impl<'a, T: MyPredicate<'a>> MyTrait<'a> for T {}
impl<'a, T> MyTrait<'a> for &'a T {}
//~^ ERROR: conflicting implementations of trait `MyTrait<'_>` for type `&_`
//[stock]~^ ERROR: conflicting implementations of trait `MyTrait<'_>` for type `&_`
fn main() {}

View File

@ -1,11 +0,0 @@
error[E0119]: conflicting implementations of trait `MyTrait<'_>` for type `&_`
--> $DIR/coherence-negative-outlives-lifetimes.rs:14:1
|
LL | impl<'a, T: MyPredicate<'a>> MyTrait<'a> for T {}
| ---------------------------------------------- first implementation here
LL | impl<'a, T> MyTrait<'a> for &'a T {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0119`.