mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
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
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,26 +6,25 @@
|
||||
use std::fmt::Debug;
|
||||
use std::iter::Once;
|
||||
|
||||
trait Lam<Binder> { type App; }
|
||||
trait Lam<Binder> {
|
||||
type App;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct L1;
|
||||
impl<'a> Lam<&'a u8> for L1 { type App = u8; }
|
||||
impl<'a> Lam<&'a u8> for L1 {
|
||||
type App = u8;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct L2;
|
||||
impl<'a, 'b> Lam<&'a &'b u8> for L2 { type App = u8; }
|
||||
impl<'a, 'b> Lam<&'a &'b u8> for L2 {
|
||||
type App = u8;
|
||||
}
|
||||
|
||||
trait Case1 {
|
||||
type C: Clone + Iterator<Item:
|
||||
Send + Iterator<Item:
|
||||
for<'a> Lam<&'a u8, App:
|
||||
Debug
|
||||
>
|
||||
> + Sync>;
|
||||
//~^^^^^^ ERROR `<<Self as Case1>::C as std::iter::Iterator>::Item` is not an iterator
|
||||
//~^^^^^^ ERROR `<<Self as Case1>::C as std::iter::Iterator>::Item` cannot be sent between threads safely
|
||||
//~^^^ ERROR `<<Self as Case1>::C as std::iter::Iterator>::Item` cannot be shared between threads safely
|
||||
type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
|
||||
//~^ ERROR overflow evaluating the requirement `<<Self as Case1>::C as std::iter::Iterator>::Item`
|
||||
}
|
||||
|
||||
pub struct S1;
|
||||
@ -34,10 +33,20 @@ impl Case1 for S1 {
|
||||
}
|
||||
|
||||
fn assume_case1<T: Case1>() {
|
||||
fn assert_a<_0, A>() where A: Iterator<Item = _0>, _0: Debug {}
|
||||
fn assert_a<_0, A>()
|
||||
where
|
||||
A: Iterator<Item = _0>,
|
||||
_0: Debug,
|
||||
{
|
||||
}
|
||||
assert_a::<_, T::A>();
|
||||
|
||||
fn assert_b<_0, B>() where B: Iterator<Item = _0>, _0: 'static {}
|
||||
fn assert_b<_0, B>()
|
||||
where
|
||||
B: Iterator<Item = _0>,
|
||||
_0: 'static,
|
||||
{
|
||||
}
|
||||
assert_b::<_, T::B>();
|
||||
|
||||
fn assert_c<_0, _1, _2, C>()
|
||||
@ -46,7 +55,8 @@ fn assume_case1<T: Case1>() {
|
||||
_2: Send + Iterator<Item = _1>,
|
||||
_1: for<'a> Lam<&'a u8, App = _0>,
|
||||
_0: Debug,
|
||||
{}
|
||||
{
|
||||
}
|
||||
assert_c::<_, _, _, T::C>();
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
error[E0277]: `<<Self as Case1>::C as std::iter::Iterator>::Item` is not an iterator
|
||||
--> $DIR/bad-bounds-on-assoc-in-trait.rs:22:5
|
||||
error[E0275]: overflow evaluating the requirement `<<Self as Case1>::C as std::iter::Iterator>::Item`
|
||||
--> $DIR/bad-bounds-on-assoc-in-trait.rs:28:5
|
||||
|
|
||||
LL | / type C: Clone + Iterator<Item:
|
||||
LL | | Send + Iterator<Item:
|
||||
@ -49,6 +49,6 @@ help: consider further restricting the associated type
|
||||
LL | trait Case1 where <<Self as Case1>::C as std::iter::Iterator>::Item: std::marker::Sync {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
For more information about this error, try `rustc --explain E0275`.
|
||||
|
@ -0,0 +1,25 @@
|
||||
// Make sure that we normalize bounds on associated types before checking them
|
||||
// as candidates.
|
||||
|
||||
// check-pass
|
||||
|
||||
trait Mul<T> {
|
||||
type Output;
|
||||
}
|
||||
|
||||
trait Matrix: Mul<<Self as Matrix>::Row, Output = ()> {
|
||||
type Row;
|
||||
|
||||
type Transpose: Matrix<Row = Self::Row>;
|
||||
}
|
||||
|
||||
fn is_mul<S, T: Mul<S, Output = ()>>() {}
|
||||
|
||||
fn f<T: Matrix>() {
|
||||
// The unnormalized bound on `T::Transpose` is
|
||||
// `Mul<<T::Transpose as Matrix>::Row` which has to be normalized to be
|
||||
// equal to `T::Row`.
|
||||
is_mul::<T::Row, T::Transpose>();
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -9,4 +9,5 @@ impl<'g> T<'g> for u32 {
|
||||
fn main() {
|
||||
(&|_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
|
||||
//~^ ERROR: type mismatch in closure arguments
|
||||
//~| ERROR: size for values of type `<u32 as T<'_>>::V` cannot be known at compilation time
|
||||
}
|
||||
|
@ -9,6 +9,24 @@ LL | (&|_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
|
||||
|
|
||||
= note: required for the cast to the object type `dyn for<'x> Fn(<u32 as T<'x>>::V)`
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0277]: the size for values of type `<u32 as T<'_>>::V` cannot be known at compilation time
|
||||
--> $DIR/issue-41366.rs:10:8
|
||||
|
|
||||
LL | (&|_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
|
||||
| ^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `std::marker::Sized` is not implemented for `<u32 as T<'_>>::V`
|
||||
= help: unsized locals are gated as an unstable feature
|
||||
help: consider further restricting the associated type
|
||||
|
|
||||
LL | fn main() where <u32 as T<'_>>::V: std::marker::Sized {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||
|
|
||||
LL | (&|&_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
|
||||
| ^
|
||||
|
||||
For more information about this error, try `rustc --explain E0631`.
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0631.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
|
@ -1,3 +1,5 @@
|
||||
// check-pass
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
trait MultiDispatch<T> {
|
||||
@ -8,10 +10,16 @@ trait Trait: Sized {
|
||||
type A: MultiDispatch<Self::B, O = Self>;
|
||||
type B;
|
||||
|
||||
fn new<U>(u: U) -> <Self::A as MultiDispatch<U>>::O where Self::A : MultiDispatch<U>;
|
||||
fn new<U>(u: U) -> <Self::A as MultiDispatch<U>>::O
|
||||
where
|
||||
Self::A: MultiDispatch<U>;
|
||||
}
|
||||
|
||||
fn test<T: Trait<B=i32>>(b: i32) -> T where T::A: MultiDispatch<i32> { T::new(b) }
|
||||
//~^ ERROR mismatched types
|
||||
fn test<T: Trait<B = i32>>(b: i32) -> T
|
||||
where
|
||||
T::A: MultiDispatch<i32>,
|
||||
{
|
||||
T::new(b)
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,15 +0,0 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-24204.rs:14:72
|
||||
|
|
||||
LL | fn test<T: Trait<B=i32>>(b: i32) -> T where T::A: MultiDispatch<i32> { T::new(b) }
|
||||
| - - ^^^^^^^^^ expected type parameter `T`, found associated type
|
||||
| | |
|
||||
| this type parameter expected `T` because of return type
|
||||
|
|
||||
= note: expected type parameter `T`
|
||||
found associated type `<<T as Trait>::A as MultiDispatch<i32>>::O`
|
||||
= note: you might be missing a type parameter or trait bound
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
@ -1,3 +1,5 @@
|
||||
// check-pass
|
||||
|
||||
use std::ops::Add;
|
||||
|
||||
trait Trait<T> {
|
||||
@ -18,7 +20,11 @@ enum Either<L, R> {
|
||||
}
|
||||
|
||||
impl<L, R> Either<L, R> {
|
||||
fn converge<T>(self) -> T where L: Trait<T>, R: Trait<T> {
|
||||
fn converge<T>(self) -> T
|
||||
where
|
||||
L: Trait<T>,
|
||||
R: Trait<T>,
|
||||
{
|
||||
match self {
|
||||
Either::Left(val) => val.get(),
|
||||
Either::Right(val) => val.get(),
|
||||
@ -26,22 +32,16 @@ impl<L, R> Either<L, R> {
|
||||
}
|
||||
}
|
||||
|
||||
fn add_generic<A: Add<B>, B>(lhs: A, rhs: B) -> Either<
|
||||
impl Trait<<A as Add<B>>::Output>,
|
||||
impl Trait<<A as Add<B>>::Output>
|
||||
> {
|
||||
if true {
|
||||
Either::Left(Holder(lhs + rhs))
|
||||
} else {
|
||||
Either::Right(Holder(lhs + rhs))
|
||||
}
|
||||
fn add_generic<A: Add<B>, B>(
|
||||
lhs: A,
|
||||
rhs: B,
|
||||
) -> Either<impl Trait<<A as Add<B>>::Output>, impl Trait<<A as Add<B>>::Output>> {
|
||||
if true { Either::Left(Holder(lhs + rhs)) } else { Either::Right(Holder(lhs + rhs)) }
|
||||
}
|
||||
|
||||
fn add_one(
|
||||
value: u32,
|
||||
) -> Either<impl Trait<<u32 as Add<u32>>::Output>, impl Trait<<u32 as Add<u32>>::Output>> {
|
||||
//~^ ERROR: the trait bound `impl Trait<<u32 as Add>::Output>: Trait<u32>`
|
||||
//~| ERROR: the trait bound `impl Trait<<u32 as Add>::Output>: Trait<u32>`
|
||||
add_generic(value, 1u32)
|
||||
}
|
||||
|
||||
|
@ -1,25 +0,0 @@
|
||||
error[E0277]: the trait bound `impl Trait<<u32 as Add>::Output>: Trait<u32>` is not satisfied
|
||||
--> $DIR/issue-58344.rs:42:13
|
||||
|
|
||||
LL | ) -> Either<impl Trait<<u32 as Add<u32>>::Output>, impl Trait<<u32 as Add<u32>>::Output>> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<u32>` is not implemented for `impl Trait<<u32 as Add>::Output>`
|
||||
...
|
||||
LL | add_generic(value, 1u32)
|
||||
| ------------------------ this returned value is of type `Either<impl Trait<<u32 as Add>::Output>, impl Trait<<u32 as Add>::Output>>`
|
||||
|
|
||||
= note: the return type of a function must have a statically known size
|
||||
|
||||
error[E0277]: the trait bound `impl Trait<<u32 as Add>::Output>: Trait<u32>` is not satisfied
|
||||
--> $DIR/issue-58344.rs:42:52
|
||||
|
|
||||
LL | ) -> Either<impl Trait<<u32 as Add<u32>>::Output>, impl Trait<<u32 as Add<u32>>::Output>> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<u32>` is not implemented for `impl Trait<<u32 as Add>::Output>`
|
||||
...
|
||||
LL | add_generic(value, 1u32)
|
||||
| ------------------------ this returned value is of type `Either<impl Trait<<u32 as Add>::Output>, impl Trait<<u32 as Add>::Output>>`
|
||||
|
|
||||
= note: the return type of a function must have a statically known size
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
@ -16,4 +16,5 @@ where
|
||||
fn main() {
|
||||
foo((), drop)
|
||||
//~^ ERROR type mismatch in function arguments
|
||||
//~| ERROR the size for values of type `<() as Trait<'_>>::Item` cannot be known at compilation time
|
||||
}
|
||||
|
@ -13,6 +13,24 @@ LL | foo((), drop)
|
||||
| expected signature of `fn(<() as Trait<'a>>::Item) -> _`
|
||||
| found signature of `fn(()) -> _`
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0277]: the size for values of type `<() as Trait<'_>>::Item` cannot be known at compilation time
|
||||
--> $DIR/issue-60283.rs:17:13
|
||||
|
|
||||
LL | foo((), drop)
|
||||
| ^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
::: $SRC_DIR/libcore/mem/mod.rs:LL:COL
|
||||
|
|
||||
LL | pub fn drop<T>(_x: T) {}
|
||||
| - required by this bound in `std::mem::drop`
|
||||
|
|
||||
= help: the trait `std::marker::Sized` is not implemented for `<() as Trait<'_>>::Item`
|
||||
help: consider further restricting the associated type
|
||||
|
|
||||
LL | fn main() where <() as Trait<'_>>::Item: std::marker::Sized {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
For more information about this error, try `rustc --explain E0631`.
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0631.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
|
@ -1,5 +1,4 @@
|
||||
// Running rustfix would cause the same suggestion to be applied multiple times, which results in
|
||||
// invalid code.
|
||||
// check-pass
|
||||
|
||||
trait Parent {
|
||||
type Ty;
|
||||
@ -17,7 +16,6 @@ struct ParentWrapper<T>(T);
|
||||
impl<A, T: Parent<Ty = A>> Parent for ParentWrapper<T> {
|
||||
type Ty = A;
|
||||
type Assoc = ChildWrapper<T::Assoc>;
|
||||
//~^ ERROR the trait bound `<T as Parent>::Assoc: Child<A>` is not satisfied
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,18 +0,0 @@
|
||||
error[E0277]: the trait bound `<T as Parent>::Assoc: Child<A>` is not satisfied
|
||||
--> $DIR/missing-assoc-type-bound-restriction.rs:19:5
|
||||
|
|
||||
LL | type Assoc: Child<Self::Ty>;
|
||||
| --------------- required by this bound in `Parent::Assoc`
|
||||
...
|
||||
LL | type Assoc = ChildWrapper<T::Assoc>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Child<A>` is not implemented for `<T as Parent>::Assoc`
|
||||
|
|
||||
= note: required because of the requirements on the impl of `Child<A>` for `ChildWrapper<<T as Parent>::Assoc>`
|
||||
help: consider further restricting the associated type
|
||||
|
|
||||
LL | impl<A, T: Parent<Ty = A>> Parent for ParentWrapper<T> where <T as Parent>::Assoc: Child<A> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
Loading…
Reference in New Issue
Block a user