Rollup merge of #95039 - spastorino:overlap-super-predicates, r=nikomatsakis
Make negative coherence work when there's impl negative on super predicates r? `@nikomatsakis`
This commit is contained in:
commit
588d389dc5
6 changed files with 96 additions and 44 deletions
|
@ -748,6 +748,13 @@ pub struct TraitPredicate<'tcx> {
|
||||||
|
|
||||||
pub constness: BoundConstness,
|
pub constness: BoundConstness,
|
||||||
|
|
||||||
|
/// If polarity is Positive: we are proving that the trait is implemented.
|
||||||
|
///
|
||||||
|
/// If polarity is Negative: we are proving that a negative impl of this trait
|
||||||
|
/// exists. (Note that coherence also checks whether negative impls of supertraits
|
||||||
|
/// exist via a series of predicates.)
|
||||||
|
///
|
||||||
|
/// If polarity is Reserved: that's a bug.
|
||||||
pub polarity: ImplPolarity,
|
pub polarity: ImplPolarity,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,8 @@ use crate::traits::{
|
||||||
use rustc_errors::Diagnostic;
|
use rustc_errors::Diagnostic;
|
||||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||||
use rustc_hir::CRATE_HIR_ID;
|
use rustc_hir::CRATE_HIR_ID;
|
||||||
use rustc_infer::infer::TyCtxtInferExt;
|
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||||
use rustc_infer::traits::TraitEngine;
|
use rustc_infer::traits::{util, TraitEngine};
|
||||||
use rustc_middle::traits::specialization_graph::OverlapMode;
|
use rustc_middle::traits::specialization_graph::OverlapMode;
|
||||||
use rustc_middle::ty::fast_reject::{self, TreatParams};
|
use rustc_middle::ty::fast_reject::{self, TreatParams};
|
||||||
use rustc_middle::ty::fold::TypeFoldable;
|
use rustc_middle::ty::fold::TypeFoldable;
|
||||||
|
@ -353,6 +353,8 @@ fn negative_impl<'cx, 'tcx>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Try to prove that a negative impl exist for the given obligation and their super predicates.
|
||||||
|
#[instrument(level = "debug", skip(selcx))]
|
||||||
fn negative_impl_exists<'cx, 'tcx>(
|
fn negative_impl_exists<'cx, 'tcx>(
|
||||||
selcx: &SelectionContext<'cx, 'tcx>,
|
selcx: &SelectionContext<'cx, 'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
@ -360,13 +362,39 @@ fn negative_impl_exists<'cx, 'tcx>(
|
||||||
o: &PredicateObligation<'tcx>,
|
o: &PredicateObligation<'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let infcx = &selcx.infcx().fork();
|
let infcx = &selcx.infcx().fork();
|
||||||
|
|
||||||
|
if resolve_negative_obligation(infcx, param_env, region_context, o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to prove a negative obligation exist for super predicates
|
||||||
|
for o in util::elaborate_predicates(infcx.tcx, iter::once(o.predicate)) {
|
||||||
|
if resolve_negative_obligation(infcx, param_env, region_context, &o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(infcx))]
|
||||||
|
fn resolve_negative_obligation<'cx, 'tcx>(
|
||||||
|
infcx: &InferCtxt<'cx, 'tcx>,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
region_context: DefId,
|
||||||
|
o: &PredicateObligation<'tcx>,
|
||||||
|
) -> bool {
|
||||||
let tcx = infcx.tcx;
|
let tcx = infcx.tcx;
|
||||||
o.flip_polarity(tcx)
|
|
||||||
.map(|o| {
|
let Some(o) = o.flip_polarity(tcx) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
let mut fulfillment_cx = FulfillmentContext::new();
|
let mut fulfillment_cx = FulfillmentContext::new();
|
||||||
fulfillment_cx.register_predicate_obligation(infcx, o);
|
fulfillment_cx.register_predicate_obligation(infcx, o);
|
||||||
|
|
||||||
let errors = fulfillment_cx.select_all_or_error(infcx);
|
let errors = fulfillment_cx.select_all_or_error(infcx);
|
||||||
|
|
||||||
if !errors.is_empty() {
|
if !errors.is_empty() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -387,15 +415,13 @@ fn negative_impl_exists<'cx, 'tcx>(
|
||||||
param_env,
|
param_env,
|
||||||
);
|
);
|
||||||
|
|
||||||
let errors =
|
let errors = infcx.resolve_regions(region_context, &outlives_env, RegionckMode::default());
|
||||||
infcx.resolve_regions(region_context, &outlives_env, RegionckMode::default());
|
|
||||||
if !errors.is_empty() {
|
if !errors.is_empty() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
})
|
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trait_ref_is_knowable<'tcx>(
|
pub fn trait_ref_is_knowable<'tcx>(
|
||||||
|
|
12
src/test/ui/coherence/coherence-overlap-double-negative.rs
Normal file
12
src/test/ui/coherence/coherence-overlap-double-negative.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![feature(negative_impls)]
|
||||||
|
#![feature(with_negative_coherence)]
|
||||||
|
|
||||||
|
trait A {}
|
||||||
|
trait B: A {}
|
||||||
|
|
||||||
|
impl !A for u32 {}
|
||||||
|
impl !B for u32 {}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -1,3 +1,5 @@
|
||||||
|
// check-pass
|
||||||
|
|
||||||
#![feature(negative_impls)]
|
#![feature(negative_impls)]
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
#![feature(trait_alias)]
|
#![feature(trait_alias)]
|
||||||
|
@ -13,7 +15,5 @@ impl !A for u32 {}
|
||||||
trait C {}
|
trait C {}
|
||||||
impl<T: AB> C for T {}
|
impl<T: AB> C for T {}
|
||||||
impl C for u32 {}
|
impl C for u32 {}
|
||||||
//~^ ERROR: conflicting implementations of trait `C` for type `u32` [E0119]
|
|
||||||
// FIXME this should work, we should implement an `assemble_neg_candidates` fn
|
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
error[E0119]: conflicting implementations of trait `C` for type `u32`
|
|
||||||
--> $DIR/coherence-overlap-negate-alias-strict.rs:15:1
|
|
||||||
|
|
|
||||||
LL | impl<T: AB> C for T {}
|
|
||||||
| ------------------- first implementation here
|
|
||||||
LL | impl C for u32 {}
|
|
||||||
| ^^^^^^^^^^^^^^ conflicting implementation for `u32`
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0119`.
|
|
18
src/test/ui/coherence/coherence-overlap-super-negative.rs
Normal file
18
src/test/ui/coherence/coherence-overlap-super-negative.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![feature(negative_impls)]
|
||||||
|
#![feature(rustc_attrs)]
|
||||||
|
#![feature(with_negative_coherence)]
|
||||||
|
|
||||||
|
trait Trait1: Trait2 {}
|
||||||
|
trait Trait2 {}
|
||||||
|
|
||||||
|
struct MyType {}
|
||||||
|
impl !Trait2 for MyType {}
|
||||||
|
|
||||||
|
#[rustc_strict_coherence]
|
||||||
|
trait Foo {}
|
||||||
|
impl<T: Trait1> Foo for T {}
|
||||||
|
impl Foo for MyType {}
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue