improve readability of winnowing
This commit is contained in:
parent
39f2657d11
commit
3097453f21
@ -465,14 +465,14 @@ fn candidate_from_obligation_no_cache<'o>(
|
|||||||
if candidates.len() > 1 {
|
if candidates.len() > 1 {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < candidates.len() {
|
while i < candidates.len() {
|
||||||
let is_dup = (0..candidates.len()).filter(|&j| i != j).any(|j| {
|
let should_drop_i = (0..candidates.len()).filter(|&j| i != j).any(|j| {
|
||||||
self.candidate_should_be_dropped_in_favor_of(
|
self.candidate_should_be_dropped_in_favor_of(
|
||||||
&candidates[i],
|
&candidates[i],
|
||||||
&candidates[j],
|
&candidates[j],
|
||||||
needs_infer,
|
needs_infer,
|
||||||
)
|
) == DropVictim::Yes
|
||||||
});
|
});
|
||||||
if is_dup {
|
if should_drop_i {
|
||||||
debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len());
|
debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len());
|
||||||
candidates.swap_remove(i);
|
candidates.swap_remove(i);
|
||||||
} else {
|
} else {
|
||||||
@ -1842,15 +1842,21 @@ pub(super) fn match_projection_projections(
|
|||||||
ProjectionMatchesProjection::No
|
ProjectionMatchesProjection::No
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
// WINNOW
|
enum DropVictim {
|
||||||
//
|
Yes,
|
||||||
// Winnowing is the process of attempting to resolve ambiguity by
|
No,
|
||||||
// probing further. During the winnowing process, we unify all
|
}
|
||||||
// type variables and then we also attempt to evaluate recursive
|
|
||||||
// bounds to see if they are satisfied.
|
|
||||||
|
|
||||||
|
/// ## Winnowing
|
||||||
|
///
|
||||||
|
/// Winnowing is the process of attempting to resolve ambiguity by
|
||||||
|
/// probing further. During the winnowing process, we unify all
|
||||||
|
/// type variables and then we also attempt to evaluate recursive
|
||||||
|
/// bounds to see if they are satisfied.
|
||||||
|
impl<'tcx> SelectionContext<'_, 'tcx> {
|
||||||
/// Returns `true` if `victim` should be dropped in favor of
|
/// Returns `true` if `victim` should be dropped in favor of
|
||||||
/// `other`. Generally speaking we will drop duplicate
|
/// `other`. Generally speaking we will drop duplicate
|
||||||
/// candidates and prefer where-clause candidates.
|
/// candidates and prefer where-clause candidates.
|
||||||
@ -1861,9 +1867,9 @@ fn candidate_should_be_dropped_in_favor_of(
|
|||||||
victim: &EvaluatedCandidate<'tcx>,
|
victim: &EvaluatedCandidate<'tcx>,
|
||||||
other: &EvaluatedCandidate<'tcx>,
|
other: &EvaluatedCandidate<'tcx>,
|
||||||
needs_infer: bool,
|
needs_infer: bool,
|
||||||
) -> bool {
|
) -> DropVictim {
|
||||||
if victim.candidate == other.candidate {
|
if victim.candidate == other.candidate {
|
||||||
return true;
|
return DropVictim::Yes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if a bound would previously have been removed when normalizing
|
// Check if a bound would previously have been removed when normalizing
|
||||||
@ -1887,11 +1893,15 @@ fn candidate_should_be_dropped_in_favor_of(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(@jswrenn): this should probably be more sophisticated
|
// FIXME(@jswrenn): this should probably be more sophisticated
|
||||||
(TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => false,
|
(TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => DropVictim::No,
|
||||||
|
|
||||||
// (*)
|
// (*)
|
||||||
(BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_), _) => true,
|
(BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_), _) => {
|
||||||
(_, BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_)) => false,
|
DropVictim::Yes
|
||||||
|
}
|
||||||
|
(_, BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_)) => {
|
||||||
|
DropVictim::No
|
||||||
|
}
|
||||||
|
|
||||||
(ParamCandidate(other), ParamCandidate(victim)) => {
|
(ParamCandidate(other), ParamCandidate(victim)) => {
|
||||||
let same_except_bound_vars = other.skip_binder().trait_ref
|
let same_except_bound_vars = other.skip_binder().trait_ref
|
||||||
@ -1905,28 +1915,27 @@ fn candidate_should_be_dropped_in_favor_of(
|
|||||||
// or the current one if tied (they should both evaluate to the same answer). This is
|
// or the current one if tied (they should both evaluate to the same answer). This is
|
||||||
// probably best characterized as a "hack", since we might prefer to just do our
|
// probably best characterized as a "hack", since we might prefer to just do our
|
||||||
// best to *not* create essentially duplicate candidates in the first place.
|
// best to *not* create essentially duplicate candidates in the first place.
|
||||||
other.bound_vars().len() <= victim.bound_vars().len()
|
if other.bound_vars().len() <= victim.bound_vars().len() {
|
||||||
|
DropVictim::Yes
|
||||||
|
} else {
|
||||||
|
DropVictim::No
|
||||||
|
}
|
||||||
} else if other.skip_binder().trait_ref == victim.skip_binder().trait_ref
|
} else if other.skip_binder().trait_ref == victim.skip_binder().trait_ref
|
||||||
&& victim.skip_binder().constness == ty::BoundConstness::NotConst
|
&& victim.skip_binder().constness == ty::BoundConstness::NotConst
|
||||||
&& other.skip_binder().polarity == victim.skip_binder().polarity
|
&& other.skip_binder().polarity == victim.skip_binder().polarity
|
||||||
{
|
{
|
||||||
// Drop otherwise equivalent non-const candidates in favor of const candidates.
|
// Drop otherwise equivalent non-const candidates in favor of const candidates.
|
||||||
true
|
DropVictim::Yes
|
||||||
} else {
|
} else {
|
||||||
false
|
DropVictim::No
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drop otherwise equivalent non-const fn pointer candidates
|
// Drop otherwise equivalent non-const fn pointer candidates
|
||||||
(FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => true,
|
(FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => DropVictim::Yes,
|
||||||
|
|
||||||
// Global bounds from the where clause should be ignored
|
|
||||||
// here (see issue #50825). Otherwise, we have a where
|
|
||||||
// clause so don't go around looking for impls.
|
|
||||||
// Arbitrarily give param candidates priority
|
|
||||||
// over projection and object candidates.
|
|
||||||
(
|
(
|
||||||
ParamCandidate(ref cand),
|
ParamCandidate(ref other_cand),
|
||||||
ImplCandidate(..)
|
ImplCandidate(..)
|
||||||
| ClosureCandidate { .. }
|
| ClosureCandidate { .. }
|
||||||
| GeneratorCandidate
|
| GeneratorCandidate
|
||||||
@ -1939,11 +1948,23 @@ fn candidate_should_be_dropped_in_favor_of(
|
|||||||
| TraitAliasCandidate
|
| TraitAliasCandidate
|
||||||
| ObjectCandidate(_)
|
| ObjectCandidate(_)
|
||||||
| ProjectionCandidate(..),
|
| ProjectionCandidate(..),
|
||||||
) => !is_global(cand),
|
) => {
|
||||||
(ObjectCandidate(_) | ProjectionCandidate(..), ParamCandidate(ref cand)) => {
|
if is_global(other_cand) {
|
||||||
|
DropVictim::No
|
||||||
|
} else {
|
||||||
|
// We have a where clause so don't go around looking
|
||||||
|
// for impls. Arbitrarily give param candidates priority
|
||||||
|
// over projection and object candidates.
|
||||||
|
//
|
||||||
|
// Global bounds from the where clause should be ignored
|
||||||
|
// here (see issue #50825).
|
||||||
|
DropVictim::Yes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(ObjectCandidate(_) | ProjectionCandidate(..), ParamCandidate(ref victim_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)
|
if is_global(victim_cand) { DropVictim::Yes } else { DropVictim::No }
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
ImplCandidate(_)
|
ImplCandidate(_)
|
||||||
@ -1956,18 +1977,22 @@ fn candidate_should_be_dropped_in_favor_of(
|
|||||||
| TraitUpcastingUnsizeCandidate(_)
|
| TraitUpcastingUnsizeCandidate(_)
|
||||||
| BuiltinCandidate { has_nested: true }
|
| BuiltinCandidate { has_nested: true }
|
||||||
| TraitAliasCandidate,
|
| TraitAliasCandidate,
|
||||||
ParamCandidate(ref cand),
|
ParamCandidate(ref victim_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) && other.evaluation.must_apply_modulo_regions()
|
if is_global(victim_cand) && other.evaluation.must_apply_modulo_regions() {
|
||||||
|
DropVictim::Yes
|
||||||
|
} else {
|
||||||
|
DropVictim::No
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(ProjectionCandidate(i, _), ProjectionCandidate(j, _))
|
(ProjectionCandidate(i, _), ProjectionCandidate(j, _))
|
||||||
| (ObjectCandidate(i), ObjectCandidate(j)) => {
|
| (ObjectCandidate(i), ObjectCandidate(j)) => {
|
||||||
// Arbitrarily pick the lower numbered candidate for backwards
|
// Arbitrarily pick the lower numbered candidate for backwards
|
||||||
// compatibility reasons. Don't let this affect inference.
|
// compatibility reasons. Don't let this affect inference.
|
||||||
i < j && !needs_infer
|
if i < j && !needs_infer { DropVictim::Yes } else { DropVictim::No }
|
||||||
}
|
}
|
||||||
(ObjectCandidate(_), ProjectionCandidate(..))
|
(ObjectCandidate(_), ProjectionCandidate(..))
|
||||||
| (ProjectionCandidate(..), ObjectCandidate(_)) => {
|
| (ProjectionCandidate(..), ObjectCandidate(_)) => {
|
||||||
@ -1987,7 +2012,7 @@ fn candidate_should_be_dropped_in_favor_of(
|
|||||||
| TraitUpcastingUnsizeCandidate(_)
|
| TraitUpcastingUnsizeCandidate(_)
|
||||||
| BuiltinCandidate { .. }
|
| BuiltinCandidate { .. }
|
||||||
| TraitAliasCandidate,
|
| TraitAliasCandidate,
|
||||||
) => true,
|
) => DropVictim::Yes,
|
||||||
|
|
||||||
(
|
(
|
||||||
ImplCandidate(..)
|
ImplCandidate(..)
|
||||||
@ -2001,7 +2026,7 @@ fn candidate_should_be_dropped_in_favor_of(
|
|||||||
| BuiltinCandidate { .. }
|
| BuiltinCandidate { .. }
|
||||||
| TraitAliasCandidate,
|
| TraitAliasCandidate,
|
||||||
ObjectCandidate(_) | ProjectionCandidate(..),
|
ObjectCandidate(_) | ProjectionCandidate(..),
|
||||||
) => false,
|
) => DropVictim::No,
|
||||||
|
|
||||||
(&ImplCandidate(other_def), &ImplCandidate(victim_def)) => {
|
(&ImplCandidate(other_def), &ImplCandidate(victim_def)) => {
|
||||||
// See if we can toss out `victim` based on specialization.
|
// See if we can toss out `victim` based on specialization.
|
||||||
@ -2014,7 +2039,7 @@ fn candidate_should_be_dropped_in_favor_of(
|
|||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
if other.evaluation.must_apply_modulo_regions() {
|
if other.evaluation.must_apply_modulo_regions() {
|
||||||
if tcx.specializes((other_def, victim_def)) {
|
if tcx.specializes((other_def, victim_def)) {
|
||||||
return true;
|
return DropVictim::Yes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2060,13 +2085,13 @@ fn candidate_should_be_dropped_in_favor_of(
|
|||||||
// will then correctly report an inference error, since the
|
// will then correctly report an inference error, since the
|
||||||
// existence of multiple marker trait impls tells us nothing
|
// existence of multiple marker trait impls tells us nothing
|
||||||
// about which one should actually apply.
|
// about which one should actually apply.
|
||||||
!needs_infer
|
if needs_infer { DropVictim::No } else { DropVictim::Yes }
|
||||||
}
|
}
|
||||||
Some(_) => true,
|
Some(_) => DropVictim::Yes,
|
||||||
None => false,
|
None => DropVictim::No,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
false
|
DropVictim::No
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2092,10 +2117,12 @@ fn candidate_should_be_dropped_in_favor_of(
|
|||||||
| TraitUpcastingUnsizeCandidate(_)
|
| TraitUpcastingUnsizeCandidate(_)
|
||||||
| BuiltinCandidate { has_nested: true }
|
| BuiltinCandidate { has_nested: true }
|
||||||
| TraitAliasCandidate,
|
| TraitAliasCandidate,
|
||||||
) => false,
|
) => DropVictim::No,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> SelectionContext<'_, 'tcx> {
|
||||||
fn sized_conditions(
|
fn sized_conditions(
|
||||||
&mut self,
|
&mut self,
|
||||||
obligation: &TraitObligation<'tcx>,
|
obligation: &TraitObligation<'tcx>,
|
||||||
|
Loading…
Reference in New Issue
Block a user