Consider negative polarity on overlap check
This commit is contained in:
parent
6975afd141
commit
8b0bfb0dcb
6 changed files with 46 additions and 19 deletions
|
@ -10,7 +10,7 @@ pub mod util;
|
||||||
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||||
use rustc_middle::ty::{self, Const, Ty};
|
use rustc_middle::ty::{self, Const, Ty, TyCtxt};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
pub use self::FulfillmentErrorCode::*;
|
pub use self::FulfillmentErrorCode::*;
|
||||||
|
@ -55,6 +55,17 @@ pub struct Obligation<'tcx, T> {
|
||||||
pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
|
pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
|
||||||
pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
|
pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
|
||||||
|
|
||||||
|
impl PredicateObligation<'tcx> {
|
||||||
|
pub fn flip_polarity(&self, tcx: TyCtxt<'tcx>) -> Option<PredicateObligation<'tcx>> {
|
||||||
|
Some(PredicateObligation {
|
||||||
|
cause: self.cause.clone(),
|
||||||
|
param_env: self.param_env,
|
||||||
|
predicate: self.predicate.flip_polarity(tcx)?,
|
||||||
|
recursion_depth: self.recursion_depth,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
|
// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
|
||||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
||||||
static_assert_size!(PredicateObligation<'_>, 32);
|
static_assert_size!(PredicateObligation<'_>, 32);
|
||||||
|
|
|
@ -12,7 +12,7 @@ use rustc_hir::def_id::DefId;
|
||||||
use rustc_query_system::cache::Cache;
|
use rustc_query_system::cache::Cache;
|
||||||
|
|
||||||
pub type SelectionCache<'tcx> = Cache<
|
pub type SelectionCache<'tcx> = Cache<
|
||||||
ty::ConstnessAnd<ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>>,
|
(ty::ConstnessAnd<ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>>, ty::ImplPolarity),
|
||||||
SelectionResult<'tcx, SelectionCandidate<'tcx>>,
|
SelectionResult<'tcx, SelectionCandidate<'tcx>>,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ pub enum SelectionCandidate<'tcx> {
|
||||||
/// `false` if there are no *further* obligations.
|
/// `false` if there are no *further* obligations.
|
||||||
has_nested: bool,
|
has_nested: bool,
|
||||||
},
|
},
|
||||||
ParamCandidate(ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>),
|
ParamCandidate((ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, ty::ImplPolarity)),
|
||||||
ImplCandidate(DefId),
|
ImplCandidate(DefId),
|
||||||
AutoImplCandidate(DefId),
|
AutoImplCandidate(DefId),
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
//! [trait-specialization]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html
|
//! [trait-specialization]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html
|
||||||
|
|
||||||
use crate::infer::{CombinedSnapshot, InferOk, TyCtxtInferExt};
|
use crate::infer::{CombinedSnapshot, InferOk, TyCtxtInferExt};
|
||||||
|
use crate::traits::query::evaluate_obligation::InferCtxtExt;
|
||||||
use crate::traits::select::IntercrateAmbiguityCause;
|
use crate::traits::select::IntercrateAmbiguityCause;
|
||||||
use crate::traits::SkipLeakCheck;
|
use crate::traits::SkipLeakCheck;
|
||||||
use crate::traits::{self, Normalized, Obligation, ObligationCause, SelectionContext};
|
use crate::traits::{self, Normalized, Obligation, ObligationCause, SelectionContext};
|
||||||
|
@ -186,6 +187,7 @@ fn overlap_within_probe(
|
||||||
|
|
||||||
// Are any of the obligations unsatisfiable? If so, no overlap.
|
// Are any of the obligations unsatisfiable? If so, no overlap.
|
||||||
let infcx = selcx.infcx();
|
let infcx = selcx.infcx();
|
||||||
|
let tcx = infcx.tcx;
|
||||||
let opt_failing_obligation = a_impl_header
|
let opt_failing_obligation = a_impl_header
|
||||||
.predicates
|
.predicates
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -199,7 +201,13 @@ fn overlap_within_probe(
|
||||||
predicate: p,
|
predicate: p,
|
||||||
})
|
})
|
||||||
.chain(obligations)
|
.chain(obligations)
|
||||||
.find(|o| !selcx.predicate_may_hold_fatal(o));
|
.find(|o| {
|
||||||
|
!selcx.predicate_may_hold_fatal(o)
|
||||||
|
|| o.flip_polarity(tcx)
|
||||||
|
.as_ref()
|
||||||
|
.map(|o| selcx.infcx().predicate_must_hold_considering_regions(o))
|
||||||
|
.unwrap_or(false)
|
||||||
|
});
|
||||||
// FIXME: the call to `selcx.predicate_may_hold_fatal` above should be ported
|
// FIXME: the call to `selcx.predicate_may_hold_fatal` above should be ported
|
||||||
// to the canonical trait query form, `infcx.predicate_may_hold`, once
|
// to the canonical trait query form, `infcx.predicate_may_hold`, once
|
||||||
// the new system supports intercrate mode (which coherence needs).
|
// the new system supports intercrate mode (which coherence needs).
|
||||||
|
|
|
@ -376,7 +376,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
for bound in matching_bounds {
|
for bound in matching_bounds {
|
||||||
let wc = self.evaluate_where_clause(stack, bound.value)?;
|
let wc = self.evaluate_where_clause(stack, bound.value)?;
|
||||||
if wc.may_apply() {
|
if wc.may_apply() {
|
||||||
candidates.vec.push(ParamCandidate(bound));
|
candidates.vec.push(ParamCandidate((
|
||||||
|
bound,
|
||||||
|
stack.obligation.predicate.skip_binder().polarity,
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,8 +58,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
ParamCandidate(param) => {
|
ParamCandidate(param) => {
|
||||||
let obligations = self.confirm_param_candidate(obligation, param.value);
|
let obligations = self.confirm_param_candidate(obligation, param.0.value);
|
||||||
Ok(ImplSource::Param(obligations, param.constness))
|
Ok(ImplSource::Param(obligations, param.0.constness))
|
||||||
}
|
}
|
||||||
|
|
||||||
ImplCandidate(impl_def_id) => {
|
ImplCandidate(impl_def_id) => {
|
||||||
|
|
|
@ -1107,10 +1107,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
// const impl
|
// const impl
|
||||||
ImplCandidate(def_id) if tcx.impl_constness(def_id) == hir::Constness::Const => {}
|
ImplCandidate(def_id) if tcx.impl_constness(def_id) == hir::Constness::Const => {}
|
||||||
// const param
|
// const param
|
||||||
ParamCandidate(ty::ConstnessAnd {
|
ParamCandidate((
|
||||||
constness: ty::BoundConstness::ConstIfConst,
|
ty::ConstnessAnd { constness: ty::BoundConstness::ConstIfConst, .. },
|
||||||
..
|
_,
|
||||||
}) => {}
|
)) => {}
|
||||||
// auto trait impl
|
// auto trait impl
|
||||||
AutoImplCandidate(..) => {}
|
AutoImplCandidate(..) => {}
|
||||||
// generator, this will raise error in other places
|
// generator, this will raise error in other places
|
||||||
|
@ -1219,14 +1219,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
if self.can_use_global_caches(param_env) {
|
if self.can_use_global_caches(param_env) {
|
||||||
if let Some(res) = tcx
|
if let Some(res) = tcx
|
||||||
.selection_cache
|
.selection_cache
|
||||||
.get(¶m_env.and(trait_ref).with_constness(pred.constness), tcx)
|
.get(&(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), tcx)
|
||||||
{
|
{
|
||||||
return Some(res);
|
return Some(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.infcx
|
self.infcx
|
||||||
.selection_cache
|
.selection_cache
|
||||||
.get(¶m_env.and(trait_ref).with_constness(pred.constness), tcx)
|
.get(&(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), tcx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines whether can we safely cache the result
|
/// Determines whether can we safely cache the result
|
||||||
|
@ -1286,7 +1286,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
debug!(?trait_ref, ?candidate, "insert_candidate_cache global");
|
debug!(?trait_ref, ?candidate, "insert_candidate_cache global");
|
||||||
// This may overwrite the cache with the same value.
|
// This may overwrite the cache with the same value.
|
||||||
tcx.selection_cache.insert(
|
tcx.selection_cache.insert(
|
||||||
param_env.and(trait_ref).with_constness(pred.constness),
|
(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity),
|
||||||
dep_node,
|
dep_node,
|
||||||
candidate,
|
candidate,
|
||||||
);
|
);
|
||||||
|
@ -1297,7 +1297,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
|
|
||||||
debug!(?trait_ref, ?candidate, "insert_candidate_cache local");
|
debug!(?trait_ref, ?candidate, "insert_candidate_cache local");
|
||||||
self.infcx.selection_cache.insert(
|
self.infcx.selection_cache.insert(
|
||||||
param_env.and(trait_ref).with_constness(pred.constness),
|
(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity),
|
||||||
dep_node,
|
dep_node,
|
||||||
candidate,
|
candidate,
|
||||||
);
|
);
|
||||||
|
@ -1523,10 +1523,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
| ConstDropCandidate,
|
| ConstDropCandidate,
|
||||||
) => false,
|
) => false,
|
||||||
|
|
||||||
(ParamCandidate(other), ParamCandidate(victim)) => {
|
(
|
||||||
|
ParamCandidate((other, other_polarity)),
|
||||||
|
ParamCandidate((victim, victim_polarity)),
|
||||||
|
) => {
|
||||||
let same_except_bound_vars = other.value.skip_binder()
|
let same_except_bound_vars = other.value.skip_binder()
|
||||||
== victim.value.skip_binder()
|
== victim.value.skip_binder()
|
||||||
&& other.constness == victim.constness
|
&& other.constness == victim.constness
|
||||||
|
&& other_polarity == victim_polarity
|
||||||
&& !other.value.skip_binder().has_escaping_bound_vars();
|
&& !other.value.skip_binder().has_escaping_bound_vars();
|
||||||
if same_except_bound_vars {
|
if same_except_bound_vars {
|
||||||
// See issue #84398. In short, we can generate multiple ParamCandidates which are
|
// See issue #84398. In short, we can generate multiple ParamCandidates which are
|
||||||
|
@ -1537,6 +1541,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
other.value.bound_vars().len() <= victim.value.bound_vars().len()
|
other.value.bound_vars().len() <= victim.value.bound_vars().len()
|
||||||
} else if other.value == victim.value
|
} else if other.value == victim.value
|
||||||
&& victim.constness == ty::BoundConstness::NotConst
|
&& victim.constness == ty::BoundConstness::NotConst
|
||||||
|
&& other_polarity == victim_polarity
|
||||||
{
|
{
|
||||||
// Drop otherwise equivalent non-const candidates in favor of const candidates.
|
// Drop otherwise equivalent non-const candidates in favor of const candidates.
|
||||||
true
|
true
|
||||||
|
@ -1566,11 +1571,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
| TraitAliasCandidate(..)
|
| TraitAliasCandidate(..)
|
||||||
| ObjectCandidate(_)
|
| ObjectCandidate(_)
|
||||||
| ProjectionCandidate(_),
|
| ProjectionCandidate(_),
|
||||||
) => !is_global(&cand.value),
|
) => !is_global(&cand.0.value),
|
||||||
(ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
|
(ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
|
||||||
// Prefer these to a global where-clause bound
|
// Prefer these to a global where-clause bound
|
||||||
// (see issue #50825).
|
// (see issue #50825).
|
||||||
is_global(&cand.value)
|
is_global(&cand.0.value)
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
ImplCandidate(_)
|
ImplCandidate(_)
|
||||||
|
@ -1586,7 +1591,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
) => {
|
) => {
|
||||||
// Prefer these to a global where-clause bound
|
// Prefer these to a global where-clause bound
|
||||||
// (see issue #50825).
|
// (see issue #50825).
|
||||||
is_global(&cand.value) && other.evaluation.must_apply_modulo_regions()
|
is_global(&cand.0.value) && other.evaluation.must_apply_modulo_regions()
|
||||||
}
|
}
|
||||||
|
|
||||||
(ProjectionCandidate(i), ProjectionCandidate(j))
|
(ProjectionCandidate(i), ProjectionCandidate(j))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue