Skip to content

Commit 8b0bfb0

Browse files
committed
Consider negative polarity on overlap check
1 parent 6975afd commit 8b0bfb0

File tree

6 files changed

+46
-19
lines changed

6 files changed

+46
-19
lines changed

compiler/rustc_infer/src/traits/mod.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ pub mod util;
1010

1111
use rustc_hir as hir;
1212
use rustc_middle::ty::error::{ExpectedFound, TypeError};
13-
use rustc_middle::ty::{self, Const, Ty};
13+
use rustc_middle::ty::{self, Const, Ty, TyCtxt};
1414
use rustc_span::Span;
1515

1616
pub use self::FulfillmentErrorCode::*;
@@ -55,6 +55,17 @@ pub struct Obligation<'tcx, T> {
5555
pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
5656
pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
5757

58+
impl PredicateObligation<'tcx> {
59+
pub fn flip_polarity(&self, tcx: TyCtxt<'tcx>) -> Option<PredicateObligation<'tcx>> {
60+
Some(PredicateObligation {
61+
cause: self.cause.clone(),
62+
param_env: self.param_env,
63+
predicate: self.predicate.flip_polarity(tcx)?,
64+
recursion_depth: self.recursion_depth,
65+
})
66+
}
67+
}
68+
5869
// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
5970
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
6071
static_assert_size!(PredicateObligation<'_>, 32);

compiler/rustc_middle/src/traits/select.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_hir::def_id::DefId;
1212
use rustc_query_system::cache::Cache;
1313

1414
pub type SelectionCache<'tcx> = Cache<
15-
ty::ConstnessAnd<ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>>,
15+
(ty::ConstnessAnd<ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>>, ty::ImplPolarity),
1616
SelectionResult<'tcx, SelectionCandidate<'tcx>>,
1717
>;
1818

@@ -101,7 +101,7 @@ pub enum SelectionCandidate<'tcx> {
101101
/// `false` if there are no *further* obligations.
102102
has_nested: bool,
103103
},
104-
ParamCandidate(ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>),
104+
ParamCandidate((ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, ty::ImplPolarity)),
105105
ImplCandidate(DefId),
106106
AutoImplCandidate(DefId),
107107

compiler/rustc_trait_selection/src/traits/coherence.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
//! [trait-specialization]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html
66
77
use crate::infer::{CombinedSnapshot, InferOk, TyCtxtInferExt};
8+
use crate::traits::query::evaluate_obligation::InferCtxtExt;
89
use crate::traits::select::IntercrateAmbiguityCause;
910
use crate::traits::SkipLeakCheck;
1011
use crate::traits::{self, Normalized, Obligation, ObligationCause, SelectionContext};
@@ -186,6 +187,7 @@ fn overlap_within_probe(
186187

187188
// Are any of the obligations unsatisfiable? If so, no overlap.
188189
let infcx = selcx.infcx();
190+
let tcx = infcx.tcx;
189191
let opt_failing_obligation = a_impl_header
190192
.predicates
191193
.iter()
@@ -199,7 +201,13 @@ fn overlap_within_probe(
199201
predicate: p,
200202
})
201203
.chain(obligations)
202-
.find(|o| !selcx.predicate_may_hold_fatal(o));
204+
.find(|o| {
205+
!selcx.predicate_may_hold_fatal(o)
206+
|| o.flip_polarity(tcx)
207+
.as_ref()
208+
.map(|o| selcx.infcx().predicate_must_hold_considering_regions(o))
209+
.unwrap_or(false)
210+
});
203211
// FIXME: the call to `selcx.predicate_may_hold_fatal` above should be ported
204212
// to the canonical trait query form, `infcx.predicate_may_hold`, once
205213
// the new system supports intercrate mode (which coherence needs).

compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
376376
for bound in matching_bounds {
377377
let wc = self.evaluate_where_clause(stack, bound.value)?;
378378
if wc.may_apply() {
379-
candidates.vec.push(ParamCandidate(bound));
379+
candidates.vec.push(ParamCandidate((
380+
bound,
381+
stack.obligation.predicate.skip_binder().polarity,
382+
)));
380383
}
381384
}
382385

compiler/rustc_trait_selection/src/traits/select/confirmation.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
5858
}
5959

6060
ParamCandidate(param) => {
61-
let obligations = self.confirm_param_candidate(obligation, param.value);
62-
Ok(ImplSource::Param(obligations, param.constness))
61+
let obligations = self.confirm_param_candidate(obligation, param.0.value);
62+
Ok(ImplSource::Param(obligations, param.0.constness))
6363
}
6464

6565
ImplCandidate(impl_def_id) => {

compiler/rustc_trait_selection/src/traits/select/mod.rs

+17-12
Original file line numberDiff line numberDiff line change
@@ -1107,10 +1107,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
11071107
// const impl
11081108
ImplCandidate(def_id) if tcx.impl_constness(def_id) == hir::Constness::Const => {}
11091109
// const param
1110-
ParamCandidate(ty::ConstnessAnd {
1111-
constness: ty::BoundConstness::ConstIfConst,
1112-
..
1113-
}) => {}
1110+
ParamCandidate((
1111+
ty::ConstnessAnd { constness: ty::BoundConstness::ConstIfConst, .. },
1112+
_,
1113+
)) => {}
11141114
// auto trait impl
11151115
AutoImplCandidate(..) => {}
11161116
// generator, this will raise error in other places
@@ -1219,14 +1219,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
12191219
if self.can_use_global_caches(param_env) {
12201220
if let Some(res) = tcx
12211221
.selection_cache
1222-
.get(&param_env.and(trait_ref).with_constness(pred.constness), tcx)
1222+
.get(&(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), tcx)
12231223
{
12241224
return Some(res);
12251225
}
12261226
}
12271227
self.infcx
12281228
.selection_cache
1229-
.get(&param_env.and(trait_ref).with_constness(pred.constness), tcx)
1229+
.get(&(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), tcx)
12301230
}
12311231

12321232
/// Determines whether can we safely cache the result
@@ -1286,7 +1286,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
12861286
debug!(?trait_ref, ?candidate, "insert_candidate_cache global");
12871287
// This may overwrite the cache with the same value.
12881288
tcx.selection_cache.insert(
1289-
param_env.and(trait_ref).with_constness(pred.constness),
1289+
(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity),
12901290
dep_node,
12911291
candidate,
12921292
);
@@ -1297,7 +1297,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
12971297

12981298
debug!(?trait_ref, ?candidate, "insert_candidate_cache local");
12991299
self.infcx.selection_cache.insert(
1300-
param_env.and(trait_ref).with_constness(pred.constness),
1300+
(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity),
13011301
dep_node,
13021302
candidate,
13031303
);
@@ -1523,10 +1523,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15231523
| ConstDropCandidate,
15241524
) => false,
15251525

1526-
(ParamCandidate(other), ParamCandidate(victim)) => {
1526+
(
1527+
ParamCandidate((other, other_polarity)),
1528+
ParamCandidate((victim, victim_polarity)),
1529+
) => {
15271530
let same_except_bound_vars = other.value.skip_binder()
15281531
== victim.value.skip_binder()
15291532
&& other.constness == victim.constness
1533+
&& other_polarity == victim_polarity
15301534
&& !other.value.skip_binder().has_escaping_bound_vars();
15311535
if same_except_bound_vars {
15321536
// See issue #84398. In short, we can generate multiple ParamCandidates which are
@@ -1537,6 +1541,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15371541
other.value.bound_vars().len() <= victim.value.bound_vars().len()
15381542
} else if other.value == victim.value
15391543
&& victim.constness == ty::BoundConstness::NotConst
1544+
&& other_polarity == victim_polarity
15401545
{
15411546
// Drop otherwise equivalent non-const candidates in favor of const candidates.
15421547
true
@@ -1566,11 +1571,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15661571
| TraitAliasCandidate(..)
15671572
| ObjectCandidate(_)
15681573
| ProjectionCandidate(_),
1569-
) => !is_global(&cand.value),
1574+
) => !is_global(&cand.0.value),
15701575
(ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
15711576
// Prefer these to a global where-clause bound
15721577
// (see issue #50825).
1573-
is_global(&cand.value)
1578+
is_global(&cand.0.value)
15741579
}
15751580
(
15761581
ImplCandidate(_)
@@ -1586,7 +1591,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15861591
) => {
15871592
// Prefer these to a global where-clause bound
15881593
// (see issue #50825).
1589-
is_global(&cand.value) && other.evaluation.must_apply_modulo_regions()
1594+
is_global(&cand.0.value) && other.evaluation.must_apply_modulo_regions()
15901595
}
15911596

15921597
(ProjectionCandidate(i), ProjectionCandidate(j))

0 commit comments

Comments
 (0)