Normalize projection bounds when considering candidates
This unfortunately requires some winnowing hacks to avoid now ambiguous candidates.
This commit is contained in:
parent
cfee49593d
commit
34e5a4992c
16 changed files with 390 additions and 256 deletions
|
@ -884,6 +884,7 @@ fn assemble_candidates_from_param_env<'cx, 'tcx>(
|
|||
candidate_set,
|
||||
ProjectionTyCandidate::ParamEnv,
|
||||
obligation.param_env.caller_bounds().iter(),
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -927,6 +928,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
|
|||
candidate_set,
|
||||
ProjectionTyCandidate::TraitDef,
|
||||
bounds.iter(),
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -937,6 +939,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
|
|||
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
|
||||
ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>,
|
||||
env_predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
|
||||
potentially_unnormalized_candidates: bool,
|
||||
) {
|
||||
debug!("assemble_candidates_from_predicates(obligation={:?})", obligation);
|
||||
let infcx = selcx.infcx();
|
||||
|
@ -948,16 +951,12 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
|
|||
|
||||
let is_match = same_def_id
|
||||
&& infcx.probe(|_| {
|
||||
let data_poly_trait_ref = data.to_poly_trait_ref(infcx.tcx);
|
||||
let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
|
||||
infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.sup(obligation_poly_trait_ref, data_poly_trait_ref)
|
||||
.map(|InferOk { obligations: _, value: () }| {
|
||||
// FIXME(#32730) -- do we need to take obligations
|
||||
// into account in any way? At the moment, no.
|
||||
})
|
||||
.is_ok()
|
||||
selcx.match_projection_projections(
|
||||
obligation,
|
||||
obligation_trait_ref,
|
||||
&data,
|
||||
potentially_unnormalized_candidates,
|
||||
)
|
||||
});
|
||||
|
||||
debug!(
|
||||
|
@ -1157,9 +1156,12 @@ fn confirm_candidate<'cx, 'tcx>(
|
|||
debug!("confirm_candidate(candidate={:?}, obligation={:?})", candidate, obligation);
|
||||
|
||||
let mut progress = match candidate {
|
||||
ProjectionTyCandidate::ParamEnv(poly_projection)
|
||||
| ProjectionTyCandidate::TraitDef(poly_projection) => {
|
||||
confirm_param_env_candidate(selcx, obligation, poly_projection)
|
||||
ProjectionTyCandidate::ParamEnv(poly_projection) => {
|
||||
confirm_param_env_candidate(selcx, obligation, poly_projection, false)
|
||||
}
|
||||
|
||||
ProjectionTyCandidate::TraitDef(poly_projection) => {
|
||||
confirm_param_env_candidate(selcx, obligation, poly_projection, true)
|
||||
}
|
||||
|
||||
ProjectionTyCandidate::Select(impl_source) => {
|
||||
|
@ -1272,7 +1274,7 @@ fn confirm_object_candidate<'cx, 'tcx>(
|
|||
}
|
||||
};
|
||||
|
||||
confirm_param_env_candidate(selcx, obligation, env_predicate)
|
||||
confirm_param_env_candidate(selcx, obligation, env_predicate, false)
|
||||
}
|
||||
|
||||
fn confirm_generator_candidate<'cx, 'tcx>(
|
||||
|
@ -1323,7 +1325,7 @@ fn confirm_generator_candidate<'cx, 'tcx>(
|
|||
}
|
||||
});
|
||||
|
||||
confirm_param_env_candidate(selcx, obligation, predicate)
|
||||
confirm_param_env_candidate(selcx, obligation, predicate, false)
|
||||
.with_addl_obligations(impl_source.nested)
|
||||
.with_addl_obligations(obligations)
|
||||
}
|
||||
|
@ -1345,7 +1347,7 @@ fn confirm_discriminant_kind_candidate<'cx, 'tcx>(
|
|||
ty: self_ty.discriminant_ty(tcx),
|
||||
};
|
||||
|
||||
confirm_param_env_candidate(selcx, obligation, ty::Binder::bind(predicate))
|
||||
confirm_param_env_candidate(selcx, obligation, ty::Binder::bind(predicate), false)
|
||||
}
|
||||
|
||||
fn confirm_fn_pointer_candidate<'cx, 'tcx>(
|
||||
|
@ -1420,13 +1422,14 @@ fn confirm_callable_candidate<'cx, 'tcx>(
|
|||
ty: ret_type,
|
||||
});
|
||||
|
||||
confirm_param_env_candidate(selcx, obligation, predicate)
|
||||
confirm_param_env_candidate(selcx, obligation, predicate, false)
|
||||
}
|
||||
|
||||
fn confirm_param_env_candidate<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
poly_cache_entry: ty::PolyProjectionPredicate<'tcx>,
|
||||
potentially_unnormalized_candidate: bool,
|
||||
) -> Progress<'tcx> {
|
||||
let infcx = selcx.infcx();
|
||||
let cause = &obligation.cause;
|
||||
|
@ -1440,8 +1443,27 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
|
|||
|
||||
let cache_trait_ref = cache_entry.projection_ty.trait_ref(infcx.tcx);
|
||||
let obligation_trait_ref = obligation.predicate.trait_ref(infcx.tcx);
|
||||
let mut nested_obligations = Vec::new();
|
||||
let cache_trait_ref = if potentially_unnormalized_candidate {
|
||||
ensure_sufficient_stack(|| {
|
||||
normalize_with_depth_to(
|
||||
selcx,
|
||||
obligation.param_env,
|
||||
obligation.cause.clone(),
|
||||
obligation.recursion_depth + 1,
|
||||
&cache_trait_ref,
|
||||
&mut nested_obligations,
|
||||
)
|
||||
})
|
||||
} else {
|
||||
cache_trait_ref
|
||||
};
|
||||
|
||||
match infcx.at(cause, param_env).eq(cache_trait_ref, obligation_trait_ref) {
|
||||
Ok(InferOk { value: _, obligations }) => Progress { ty: cache_entry.ty, obligations },
|
||||
Ok(InferOk { value: _, obligations }) => {
|
||||
nested_obligations.extend(obligations);
|
||||
Progress { ty: cache_entry.ty, obligations: nested_obligations }
|
||||
}
|
||||
Err(e) => {
|
||||
let msg = format!(
|
||||
"Failed to unify obligation `{:?}` with poly_projection `{:?}`: {:?}",
|
||||
|
|
|
@ -137,18 +137,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
let candidate = candidate_predicate
|
||||
.to_opt_poly_trait_ref()
|
||||
.expect("projection candidate is not a trait predicate");
|
||||
let mut obligations = self
|
||||
.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.sup(obligation.predicate.to_poly_trait_ref(), candidate)
|
||||
.map(|InferOk { obligations, .. }| obligations)
|
||||
.unwrap_or_else(|_| {
|
||||
bug!(
|
||||
"Projection bound `{:?}` was applicable to `{:?}` but now is not",
|
||||
candidate,
|
||||
obligation
|
||||
);
|
||||
});
|
||||
let Normalized { value: candidate, mut obligations } = normalize_with_depth(
|
||||
self,
|
||||
obligation.param_env,
|
||||
obligation.cause.clone(),
|
||||
obligation.recursion_depth + 1,
|
||||
&candidate,
|
||||
);
|
||||
|
||||
obligations.extend(
|
||||
self.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.sup(obligation.predicate.to_poly_trait_ref(), candidate)
|
||||
.map(|InferOk { obligations, .. }| obligations)
|
||||
.unwrap_or_else(|_| {
|
||||
bug!(
|
||||
"Projection bound `{:?}` was applicable to `{:?}` but now is not",
|
||||
candidate,
|
||||
obligation
|
||||
);
|
||||
}),
|
||||
);
|
||||
// Require that the projection is well-formed.
|
||||
let self_ty = self.infcx.replace_bound_vars_with_placeholders(&bound_self_ty);
|
||||
let self_ty = normalize_with_depth_to(
|
||||
|
|
|
@ -9,6 +9,7 @@ use super::coherence::{self, Conflict};
|
|||
use super::const_evaluatable;
|
||||
use super::project;
|
||||
use super::project::normalize_with_depth_to;
|
||||
use super::project::ProjectionTyObligation;
|
||||
use super::util;
|
||||
use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def};
|
||||
use super::wf;
|
||||
|
@ -36,9 +37,8 @@ use rustc_middle::ty::fast_reject;
|
|||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::relate::TypeRelation;
|
||||
use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef};
|
||||
use rustc_middle::ty::{
|
||||
self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
|
||||
};
|
||||
use rustc_middle::ty::{self, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
|
||||
use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
@ -946,10 +946,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
/// to have a *lower* recursion_depth than the obligation used to create it.
|
||||
/// Projection sub-obligations may be returned from the projection cache,
|
||||
/// which results in obligations with an 'old' `recursion_depth`.
|
||||
/// Additionally, methods like `wf::obligations` and
|
||||
/// `InferCtxt.subtype_predicate` produce subobligations without
|
||||
/// taking in a 'parent' depth, causing the generated subobligations
|
||||
/// to have a `recursion_depth` of `0`.
|
||||
/// Additionally, methods like `InferCtxt.subtype_predicate` produce
|
||||
/// subobligations without taking in a 'parent' depth, causing the
|
||||
/// generated subobligations to have a `recursion_depth` of `0`.
|
||||
///
|
||||
/// To ensure that obligation_depth never decreasees, we force all subobligations
|
||||
/// to have at least the depth of the original obligation.
|
||||
|
@ -1229,10 +1228,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
placeholder_trait_ref: ty::TraitRef<'tcx>,
|
||||
) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
|
||||
debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars());
|
||||
if placeholder_trait_ref.def_id != trait_bound.def_id() {
|
||||
// Avoid unnecessary normalization
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let Normalized { value: trait_bound, obligations: mut nested_obligations } =
|
||||
ensure_sufficient_stack(|| {
|
||||
project::normalize_with_depth(
|
||||
self,
|
||||
obligation.param_env,
|
||||
obligation.cause.clone(),
|
||||
obligation.recursion_depth + 1,
|
||||
&trait_bound,
|
||||
)
|
||||
});
|
||||
self.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
|
||||
.map(|InferOk { obligations, .. }| obligations)
|
||||
.map(|InferOk { obligations, .. }| {
|
||||
nested_obligations.extend(obligations);
|
||||
nested_obligations
|
||||
})
|
||||
.map_err(|_| ())
|
||||
}
|
||||
|
||||
|
@ -1249,6 +1266,44 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
pub(super) fn match_projection_projections(
|
||||
&mut self,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
obligation_trait_ref: &ty::TraitRef<'tcx>,
|
||||
data: &PolyProjectionPredicate<'tcx>,
|
||||
potentially_unnormalized_candidates: bool,
|
||||
) -> bool {
|
||||
let mut nested_obligations = Vec::new();
|
||||
let projection_ty = if potentially_unnormalized_candidates {
|
||||
ensure_sufficient_stack(|| {
|
||||
project::normalize_with_depth_to(
|
||||
self,
|
||||
obligation.param_env,
|
||||
obligation.cause.clone(),
|
||||
obligation.recursion_depth + 1,
|
||||
&data.map_bound_ref(|data| data.projection_ty),
|
||||
&mut nested_obligations,
|
||||
)
|
||||
})
|
||||
} else {
|
||||
data.map_bound_ref(|data| data.projection_ty)
|
||||
};
|
||||
|
||||
// FIXME(generic_associated_types): Compare the whole projections
|
||||
let data_poly_trait_ref = projection_ty.map_bound(|proj| proj.trait_ref(self.tcx()));
|
||||
let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
|
||||
self.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.sup(obligation_poly_trait_ref, data_poly_trait_ref)
|
||||
.map_or(false, |InferOk { obligations, value: () }| {
|
||||
self.evaluate_predicates_recursively(
|
||||
TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
|
||||
nested_obligations.into_iter().chain(obligations),
|
||||
)
|
||||
.map_or(false, |res| res.may_apply())
|
||||
})
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// WINNOW
|
||||
//
|
||||
|
@ -1283,18 +1338,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
//
|
||||
// This is a fix for #53123 and prevents winnowing from accidentally extending the
|
||||
// lifetime of a variable.
|
||||
match other.candidate {
|
||||
match (&other.candidate, &victim.candidate) {
|
||||
(_, AutoImplCandidate(..)) | (AutoImplCandidate(..), _) => {
|
||||
bug!(
|
||||
"default implementations shouldn't be recorded \
|
||||
when there are other valid candidates"
|
||||
);
|
||||
}
|
||||
|
||||
// (*)
|
||||
BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate => true,
|
||||
ParamCandidate(ref cand) => match victim.candidate {
|
||||
AutoImplCandidate(..) => {
|
||||
bug!(
|
||||
"default implementations shouldn't be recorded \
|
||||
when there are other valid candidates"
|
||||
);
|
||||
}
|
||||
// (*)
|
||||
BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate => false,
|
||||
(BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate, _) => true,
|
||||
(_, BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate) => false,
|
||||
|
||||
(ParamCandidate(..), ParamCandidate(..)) => false,
|
||||
|
||||
// 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),
|
||||
ImplCandidate(..)
|
||||
| ClosureCandidate
|
||||
| GeneratorCandidate
|
||||
|
@ -1302,28 +1366,45 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
| BuiltinObjectCandidate
|
||||
| BuiltinUnsizeCandidate
|
||||
| BuiltinCandidate { .. }
|
||||
| TraitAliasCandidate(..) => {
|
||||
// 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.
|
||||
!is_global(cand)
|
||||
}
|
||||
ObjectCandidate | ProjectionCandidate(_) => {
|
||||
// Arbitrarily give param candidates priority
|
||||
// over projection and object candidates.
|
||||
!is_global(cand)
|
||||
}
|
||||
ParamCandidate(..) => false,
|
||||
},
|
||||
ObjectCandidate | ProjectionCandidate(_) => match victim.candidate {
|
||||
AutoImplCandidate(..) => {
|
||||
bug!(
|
||||
"default implementations shouldn't be recorded \
|
||||
when there are other valid candidates"
|
||||
);
|
||||
}
|
||||
// (*)
|
||||
BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate => false,
|
||||
| TraitAliasCandidate(..)
|
||||
| ObjectCandidate
|
||||
| ProjectionCandidate(_),
|
||||
) => !is_global(cand),
|
||||
(ObjectCandidate | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
|
||||
// Prefer these to a global where-clause bound
|
||||
// (see issue #50825).
|
||||
is_global(cand)
|
||||
}
|
||||
(
|
||||
ImplCandidate(_)
|
||||
| ClosureCandidate
|
||||
| GeneratorCandidate
|
||||
| FnPointerCandidate
|
||||
| BuiltinObjectCandidate
|
||||
| BuiltinUnsizeCandidate
|
||||
| BuiltinCandidate { has_nested: true }
|
||||
| TraitAliasCandidate(..),
|
||||
ParamCandidate(ref cand),
|
||||
) => {
|
||||
// Prefer these to a global where-clause bound
|
||||
// (see issue #50825).
|
||||
is_global(cand) && other.evaluation.must_apply_modulo_regions()
|
||||
}
|
||||
|
||||
(ProjectionCandidate(i), ProjectionCandidate(j)) => {
|
||||
// Arbitrarily pick the first candidate for backwards
|
||||
// compatibility reasons. Don't let this affect inference.
|
||||
i > j && !needs_infer
|
||||
}
|
||||
(ObjectCandidate, ObjectCandidate) => bug!("Duplicate object candidate"),
|
||||
(ObjectCandidate, ProjectionCandidate(_))
|
||||
| (ProjectionCandidate(_), ObjectCandidate) => {
|
||||
bug!("Have both object and projection candidate")
|
||||
}
|
||||
|
||||
// Arbitrarily give projection and object candidates priority.
|
||||
(
|
||||
ObjectCandidate | ProjectionCandidate(_),
|
||||
ImplCandidate(..)
|
||||
| ClosureCandidate
|
||||
| GeneratorCandidate
|
||||
|
@ -1331,99 +1412,100 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
| BuiltinObjectCandidate
|
||||
| BuiltinUnsizeCandidate
|
||||
| BuiltinCandidate { .. }
|
||||
| TraitAliasCandidate(..) => true,
|
||||
ObjectCandidate | ProjectionCandidate(_) => {
|
||||
// Shouldn't have both an object and projection candidate,
|
||||
// nor multiple object candidates. Multiple projection
|
||||
// candidates are ambiguous.
|
||||
false
|
||||
}
|
||||
ParamCandidate(ref cand) => is_global(cand),
|
||||
},
|
||||
ImplCandidate(other_def) => {
|
||||
| TraitAliasCandidate(..),
|
||||
) => true,
|
||||
|
||||
(
|
||||
ImplCandidate(..)
|
||||
| ClosureCandidate
|
||||
| GeneratorCandidate
|
||||
| FnPointerCandidate
|
||||
| BuiltinObjectCandidate
|
||||
| BuiltinUnsizeCandidate
|
||||
| BuiltinCandidate { .. }
|
||||
| TraitAliasCandidate(..),
|
||||
ObjectCandidate | ProjectionCandidate(_),
|
||||
) => false,
|
||||
|
||||
(&ImplCandidate(other_def), &ImplCandidate(victim_def)) => {
|
||||
// See if we can toss out `victim` based on specialization.
|
||||
// This requires us to know *for sure* that the `other` impl applies
|
||||
// i.e., `EvaluatedToOk`.
|
||||
if other.evaluation.must_apply_modulo_regions() {
|
||||
match victim.candidate {
|
||||
ImplCandidate(victim_def) => {
|
||||
let tcx = self.tcx();
|
||||
if tcx.specializes((other_def, victim_def)) {
|
||||
return true;
|
||||
}
|
||||
return match tcx.impls_are_allowed_to_overlap(other_def, victim_def) {
|
||||
Some(ty::ImplOverlapKind::Permitted { marker: true }) => {
|
||||
// Subtle: If the predicate we are evaluating has inference
|
||||
// variables, do *not* allow discarding candidates due to
|
||||
// marker trait impls.
|
||||
//
|
||||
// Without this restriction, we could end up accidentally
|
||||
// constrainting inference variables based on an arbitrarily
|
||||
// chosen trait impl.
|
||||
//
|
||||
// Imagine we have the following code:
|
||||
//
|
||||
// ```rust
|
||||
// #[marker] trait MyTrait {}
|
||||
// impl MyTrait for u8 {}
|
||||
// impl MyTrait for bool {}
|
||||
// ```
|
||||
//
|
||||
// And we are evaluating the predicate `<_#0t as MyTrait>`.
|
||||
//
|
||||
// During selection, we will end up with one candidate for each
|
||||
// impl of `MyTrait`. If we were to discard one impl in favor
|
||||
// of the other, we would be left with one candidate, causing
|
||||
// us to "successfully" select the predicate, unifying
|
||||
// _#0t with (for example) `u8`.
|
||||
//
|
||||
// However, we have no reason to believe that this unification
|
||||
// is correct - we've essentially just picked an arbitrary
|
||||
// *possibility* for _#0t, and required that this be the *only*
|
||||
// possibility.
|
||||
//
|
||||
// Eventually, we will either:
|
||||
// 1) Unify all inference variables in the predicate through
|
||||
// some other means (e.g. type-checking of a function). We will
|
||||
// then be in a position to drop marker trait candidates
|
||||
// without constraining inference variables (since there are
|
||||
// none left to constrin)
|
||||
// 2) Be left with some unconstrained inference variables. We
|
||||
// will then correctly report an inference error, since the
|
||||
// existence of multiple marker trait impls tells us nothing
|
||||
// about which one should actually apply.
|
||||
!needs_infer
|
||||
}
|
||||
Some(_) => true,
|
||||
None => false,
|
||||
};
|
||||
}
|
||||
ParamCandidate(ref cand) => {
|
||||
// Prefer the impl to a global where clause candidate.
|
||||
return is_global(cand);
|
||||
}
|
||||
_ => (),
|
||||
let tcx = self.tcx();
|
||||
if tcx.specializes((other_def, victim_def)) {
|
||||
return true;
|
||||
}
|
||||
return match tcx.impls_are_allowed_to_overlap(other_def, victim_def) {
|
||||
Some(ty::ImplOverlapKind::Permitted { marker: true }) => {
|
||||
// Subtle: If the predicate we are evaluating has inference
|
||||
// variables, do *not* allow discarding candidates due to
|
||||
// marker trait impls.
|
||||
//
|
||||
// Without this restriction, we could end up accidentally
|
||||
// constrainting inference variables based on an arbitrarily
|
||||
// chosen trait impl.
|
||||
//
|
||||
// Imagine we have the following code:
|
||||
//
|
||||
// ```rust
|
||||
// #[marker] trait MyTrait {}
|
||||
// impl MyTrait for u8 {}
|
||||
// impl MyTrait for bool {}
|
||||
// ```
|
||||
//
|
||||
// And we are evaluating the predicate `<_#0t as MyTrait>`.
|
||||
//
|
||||
// During selection, we will end up with one candidate for each
|
||||
// impl of `MyTrait`. If we were to discard one impl in favor
|
||||
// of the other, we would be left with one candidate, causing
|
||||
// us to "successfully" select the predicate, unifying
|
||||
// _#0t with (for example) `u8`.
|
||||
//
|
||||
// However, we have no reason to believe that this unification
|
||||
// is correct - we've essentially just picked an arbitrary
|
||||
// *possibility* for _#0t, and required that this be the *only*
|
||||
// possibility.
|
||||
//
|
||||
// Eventually, we will either:
|
||||
// 1) Unify all inference variables in the predicate through
|
||||
// some other means (e.g. type-checking of a function). We will
|
||||
// then be in a position to drop marker trait candidates
|
||||
// without constraining inference variables (since there are
|
||||
// none left to constrin)
|
||||
// 2) Be left with some unconstrained inference variables. We
|
||||
// will then correctly report an inference error, since the
|
||||
// existence of multiple marker trait impls tells us nothing
|
||||
// about which one should actually apply.
|
||||
!needs_infer
|
||||
}
|
||||
Some(_) => true,
|
||||
None => false,
|
||||
};
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
ClosureCandidate
|
||||
| GeneratorCandidate
|
||||
| FnPointerCandidate
|
||||
| BuiltinObjectCandidate
|
||||
| BuiltinUnsizeCandidate
|
||||
| BuiltinCandidate { has_nested: true } => {
|
||||
match victim.candidate {
|
||||
ParamCandidate(ref cand) => {
|
||||
// Prefer these to a global where-clause bound
|
||||
// (see issue #50825).
|
||||
is_global(cand) && other.evaluation.must_apply_modulo_regions()
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
// Everything else is ambiguous
|
||||
(
|
||||
ImplCandidate(_)
|
||||
| ClosureCandidate
|
||||
| GeneratorCandidate
|
||||
| FnPointerCandidate
|
||||
| BuiltinObjectCandidate
|
||||
| BuiltinUnsizeCandidate
|
||||
| BuiltinCandidate { has_nested: true }
|
||||
| TraitAliasCandidate(..),
|
||||
ImplCandidate(_)
|
||||
| ClosureCandidate
|
||||
| GeneratorCandidate
|
||||
| FnPointerCandidate
|
||||
| BuiltinObjectCandidate
|
||||
| BuiltinUnsizeCandidate
|
||||
| BuiltinCandidate { has_nested: true }
|
||||
| TraitAliasCandidate(..),
|
||||
) => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue