Skip to content

Commit ac0b6af

Browse files
committed
Permit negative impls coherence to take advantage of implied bounds
1 parent 5ff45dc commit ac0b6af

File tree

3 files changed

+29
-22
lines changed

3 files changed

+29
-22
lines changed

compiler/rustc_trait_selection/src/traits/coherence.rs

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@
66
77
use crate::infer::outlives::env::OutlivesEnvironment;
88
use crate::infer::{CombinedSnapshot, InferOk};
9+
use crate::traits::outlives_bounds::InferCtxtExt as _;
910
use crate::traits::select::IntercrateAmbiguityCause;
1011
use crate::traits::util::impl_subject_and_oblig;
1112
use crate::traits::SkipLeakCheck;
1213
use crate::traits::{
13-
self, Normalized, Obligation, ObligationCause, PredicateObligation, PredicateObligations,
14-
SelectionContext,
14+
self, Normalized, Obligation, ObligationCause, ObligationCtxt, PredicateObligation,
15+
PredicateObligations, SelectionContext,
1516
};
1617
use rustc_data_structures::fx::FxIndexSet;
1718
use rustc_errors::Diagnostic;
@@ -322,7 +323,7 @@ fn negative_impl<'cx, 'tcx>(
322323
let (subject2, obligations) =
323324
impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs);
324325

325-
!equate(&infcx, impl_env, subject1, subject2, obligations)
326+
!equate(&infcx, impl_env, subject1, subject2, obligations, impl1_def_id)
326327
})
327328
}
328329

@@ -332,6 +333,7 @@ fn equate<'cx, 'tcx>(
332333
subject1: ImplSubject<'tcx>,
333334
subject2: ImplSubject<'tcx>,
334335
obligations: impl Iterator<Item = PredicateObligation<'tcx>>,
336+
body_def_id: DefId,
335337
) -> bool {
336338
// do the impls unify? If not, not disjoint.
337339
let Ok(InferOk { obligations: more_obligations, .. }) =
@@ -342,8 +344,10 @@ fn equate<'cx, 'tcx>(
342344
};
343345

344346
let selcx = &mut SelectionContext::new(&infcx);
345-
let opt_failing_obligation =
346-
obligations.into_iter().chain(more_obligations).find(|o| negative_impl_exists(selcx, o));
347+
let opt_failing_obligation = obligations
348+
.into_iter()
349+
.chain(more_obligations)
350+
.find(|o| negative_impl_exists(selcx, o, body_def_id));
347351

348352
if let Some(failing_obligation) = opt_failing_obligation {
349353
debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
@@ -358,14 +362,15 @@ fn equate<'cx, 'tcx>(
358362
fn negative_impl_exists<'cx, 'tcx>(
359363
selcx: &SelectionContext<'cx, 'tcx>,
360364
o: &PredicateObligation<'tcx>,
365+
body_def_id: DefId,
361366
) -> bool {
362-
if resolve_negative_obligation(selcx.infcx().fork(), o) {
367+
if resolve_negative_obligation(selcx.infcx().fork(), o, body_def_id) {
363368
return true;
364369
}
365370

366371
// Try to prove a negative obligation exists for super predicates
367372
for o in util::elaborate_predicates(selcx.tcx(), iter::once(o.predicate)) {
368-
if resolve_negative_obligation(selcx.infcx().fork(), &o) {
373+
if resolve_negative_obligation(selcx.infcx().fork(), &o, body_def_id) {
369374
return true;
370375
}
371376
}
@@ -377,6 +382,7 @@ fn negative_impl_exists<'cx, 'tcx>(
377382
fn resolve_negative_obligation<'cx, 'tcx>(
378383
infcx: InferCtxt<'cx, 'tcx>,
379384
o: &PredicateObligation<'tcx>,
385+
body_def_id: DefId,
380386
) -> bool {
381387
let tcx = infcx.tcx;
382388

@@ -390,7 +396,19 @@ fn resolve_negative_obligation<'cx, 'tcx>(
390396
return false;
391397
}
392398

393-
let outlives_env = OutlivesEnvironment::new(param_env);
399+
let outlives_env = if let Some(body_def_id) = body_def_id.as_local() {
400+
let body_id = tcx.hir().local_def_id_to_hir_id(body_def_id);
401+
let ocx = ObligationCtxt::new(&infcx);
402+
let wf_tys = ocx.assumed_wf_types(param_env, DUMMY_SP, body_def_id);
403+
OutlivesEnvironment::with_bounds(
404+
param_env,
405+
Some(&infcx),
406+
infcx.implied_bounds_tys(param_env, body_id, wf_tys),
407+
)
408+
} else {
409+
OutlivesEnvironment::new(param_env)
410+
};
411+
394412
infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env);
395413

396414
infcx.resolve_regions(&outlives_env).is_empty()
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// revisions: stock with_negative_coherence
2+
//[with_negative_coherence] check-pass
3+
24
#![feature(negative_impls)]
35
#![cfg_attr(with_negative_coherence, feature(with_negative_coherence))]
46

5-
// FIXME: this should compile
6-
77
trait MyPredicate<'a> {}
88

99
impl<'a, T> !MyPredicate<'a> for &'a T where T: 'a {}
@@ -12,6 +12,6 @@ trait MyTrait<'a> {}
1212

1313
impl<'a, T: MyPredicate<'a>> MyTrait<'a> for T {}
1414
impl<'a, T> MyTrait<'a> for &'a T {}
15-
//~^ ERROR: conflicting implementations of trait `MyTrait<'_>` for type `&_`
15+
//[stock]~^ ERROR: conflicting implementations of trait `MyTrait<'_>` for type `&_`
1616

1717
fn main() {}

src/test/ui/coherence/coherence-negative-outlives-lifetimes.with_negative_coherence.stderr

Lines changed: 0 additions & 11 deletions
This file was deleted.

0 commit comments

Comments
 (0)