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,
|
candidate_set,
|
||||||
ProjectionTyCandidate::ParamEnv,
|
ProjectionTyCandidate::ParamEnv,
|
||||||
obligation.param_env.caller_bounds().iter(),
|
obligation.param_env.caller_bounds().iter(),
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -927,6 +928,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
|
||||||
candidate_set,
|
candidate_set,
|
||||||
ProjectionTyCandidate::TraitDef,
|
ProjectionTyCandidate::TraitDef,
|
||||||
bounds.iter(),
|
bounds.iter(),
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -937,6 +939,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
|
||||||
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
|
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
|
||||||
ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>,
|
ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>,
|
||||||
env_predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
|
env_predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
|
||||||
|
potentially_unnormalized_candidates: bool,
|
||||||
) {
|
) {
|
||||||
debug!("assemble_candidates_from_predicates(obligation={:?})", obligation);
|
debug!("assemble_candidates_from_predicates(obligation={:?})", obligation);
|
||||||
let infcx = selcx.infcx();
|
let infcx = selcx.infcx();
|
||||||
|
@ -948,16 +951,12 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
|
||||||
|
|
||||||
let is_match = same_def_id
|
let is_match = same_def_id
|
||||||
&& infcx.probe(|_| {
|
&& infcx.probe(|_| {
|
||||||
let data_poly_trait_ref = data.to_poly_trait_ref(infcx.tcx);
|
selcx.match_projection_projections(
|
||||||
let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
|
obligation,
|
||||||
infcx
|
obligation_trait_ref,
|
||||||
.at(&obligation.cause, obligation.param_env)
|
&data,
|
||||||
.sup(obligation_poly_trait_ref, data_poly_trait_ref)
|
potentially_unnormalized_candidates,
|
||||||
.map(|InferOk { obligations: _, value: () }| {
|
)
|
||||||
// FIXME(#32730) -- do we need to take obligations
|
|
||||||
// into account in any way? At the moment, no.
|
|
||||||
})
|
|
||||||
.is_ok()
|
|
||||||
});
|
});
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
|
@ -1157,9 +1156,12 @@ fn confirm_candidate<'cx, 'tcx>(
|
||||||
debug!("confirm_candidate(candidate={:?}, obligation={:?})", candidate, obligation);
|
debug!("confirm_candidate(candidate={:?}, obligation={:?})", candidate, obligation);
|
||||||
|
|
||||||
let mut progress = match candidate {
|
let mut progress = match candidate {
|
||||||
ProjectionTyCandidate::ParamEnv(poly_projection)
|
ProjectionTyCandidate::ParamEnv(poly_projection) => {
|
||||||
| ProjectionTyCandidate::TraitDef(poly_projection) => {
|
confirm_param_env_candidate(selcx, obligation, poly_projection, false)
|
||||||
confirm_param_env_candidate(selcx, obligation, poly_projection)
|
}
|
||||||
|
|
||||||
|
ProjectionTyCandidate::TraitDef(poly_projection) => {
|
||||||
|
confirm_param_env_candidate(selcx, obligation, poly_projection, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
ProjectionTyCandidate::Select(impl_source) => {
|
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>(
|
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(impl_source.nested)
|
||||||
.with_addl_obligations(obligations)
|
.with_addl_obligations(obligations)
|
||||||
}
|
}
|
||||||
|
@ -1345,7 +1347,7 @@ fn confirm_discriminant_kind_candidate<'cx, 'tcx>(
|
||||||
ty: self_ty.discriminant_ty(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>(
|
fn confirm_fn_pointer_candidate<'cx, 'tcx>(
|
||||||
|
@ -1420,13 +1422,14 @@ fn confirm_callable_candidate<'cx, 'tcx>(
|
||||||
ty: ret_type,
|
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>(
|
fn confirm_param_env_candidate<'cx, 'tcx>(
|
||||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||||
obligation: &ProjectionTyObligation<'tcx>,
|
obligation: &ProjectionTyObligation<'tcx>,
|
||||||
poly_cache_entry: ty::PolyProjectionPredicate<'tcx>,
|
poly_cache_entry: ty::PolyProjectionPredicate<'tcx>,
|
||||||
|
potentially_unnormalized_candidate: bool,
|
||||||
) -> Progress<'tcx> {
|
) -> Progress<'tcx> {
|
||||||
let infcx = selcx.infcx();
|
let infcx = selcx.infcx();
|
||||||
let cause = &obligation.cause;
|
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 cache_trait_ref = cache_entry.projection_ty.trait_ref(infcx.tcx);
|
||||||
let obligation_trait_ref = obligation.predicate.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) {
|
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) => {
|
Err(e) => {
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
"Failed to unify obligation `{:?}` with poly_projection `{:?}`: {:?}",
|
"Failed to unify obligation `{:?}` with poly_projection `{:?}`: {:?}",
|
||||||
|
|
|
@ -137,18 +137,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
let candidate = candidate_predicate
|
let candidate = candidate_predicate
|
||||||
.to_opt_poly_trait_ref()
|
.to_opt_poly_trait_ref()
|
||||||
.expect("projection candidate is not a trait predicate");
|
.expect("projection candidate is not a trait predicate");
|
||||||
let mut obligations = self
|
let Normalized { value: candidate, mut obligations } = normalize_with_depth(
|
||||||
.infcx
|
self,
|
||||||
.at(&obligation.cause, obligation.param_env)
|
obligation.param_env,
|
||||||
.sup(obligation.predicate.to_poly_trait_ref(), candidate)
|
obligation.cause.clone(),
|
||||||
.map(|InferOk { obligations, .. }| obligations)
|
obligation.recursion_depth + 1,
|
||||||
.unwrap_or_else(|_| {
|
&candidate,
|
||||||
bug!(
|
);
|
||||||
"Projection bound `{:?}` was applicable to `{:?}` but now is not",
|
|
||||||
candidate,
|
obligations.extend(
|
||||||
obligation
|
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.
|
// Require that the projection is well-formed.
|
||||||
let self_ty = self.infcx.replace_bound_vars_with_placeholders(&bound_self_ty);
|
let self_ty = self.infcx.replace_bound_vars_with_placeholders(&bound_self_ty);
|
||||||
let self_ty = normalize_with_depth_to(
|
let self_ty = normalize_with_depth_to(
|
||||||
|
|
|
@ -9,6 +9,7 @@ use super::coherence::{self, Conflict};
|
||||||
use super::const_evaluatable;
|
use super::const_evaluatable;
|
||||||
use super::project;
|
use super::project;
|
||||||
use super::project::normalize_with_depth_to;
|
use super::project::normalize_with_depth_to;
|
||||||
|
use super::project::ProjectionTyObligation;
|
||||||
use super::util;
|
use super::util;
|
||||||
use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def};
|
use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def};
|
||||||
use super::wf;
|
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::print::with_no_trimmed_paths;
|
||||||
use rustc_middle::ty::relate::TypeRelation;
|
use rustc_middle::ty::relate::TypeRelation;
|
||||||
use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef};
|
use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef};
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{self, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
|
||||||
self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
|
use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable};
|
||||||
};
|
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
|
|
||||||
use std::cell::{Cell, RefCell};
|
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.
|
/// to have a *lower* recursion_depth than the obligation used to create it.
|
||||||
/// Projection sub-obligations may be returned from the projection cache,
|
/// Projection sub-obligations may be returned from the projection cache,
|
||||||
/// which results in obligations with an 'old' `recursion_depth`.
|
/// which results in obligations with an 'old' `recursion_depth`.
|
||||||
/// Additionally, methods like `wf::obligations` and
|
/// Additionally, methods like `InferCtxt.subtype_predicate` produce
|
||||||
/// `InferCtxt.subtype_predicate` produce subobligations without
|
/// subobligations without taking in a 'parent' depth, causing the
|
||||||
/// taking in a 'parent' depth, causing the generated subobligations
|
/// generated subobligations to have a `recursion_depth` of `0`.
|
||||||
/// to have a `recursion_depth` of `0`.
|
|
||||||
///
|
///
|
||||||
/// To ensure that obligation_depth never decreasees, we force all subobligations
|
/// To ensure that obligation_depth never decreasees, we force all subobligations
|
||||||
/// to have at least the depth of the original obligation.
|
/// 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>,
|
placeholder_trait_ref: ty::TraitRef<'tcx>,
|
||||||
) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
|
) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
|
||||||
debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars());
|
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
|
self.infcx
|
||||||
.at(&obligation.cause, obligation.param_env)
|
.at(&obligation.cause, obligation.param_env)
|
||||||
.sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
|
.sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
|
||||||
.map(|InferOk { obligations, .. }| obligations)
|
.map(|InferOk { obligations, .. }| {
|
||||||
|
nested_obligations.extend(obligations);
|
||||||
|
nested_obligations
|
||||||
|
})
|
||||||
.map_err(|_| ())
|
.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
|
// WINNOW
|
||||||
//
|
//
|
||||||
|
@ -1283,18 +1338,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
//
|
//
|
||||||
// This is a fix for #53123 and prevents winnowing from accidentally extending the
|
// This is a fix for #53123 and prevents winnowing from accidentally extending the
|
||||||
// lifetime of a variable.
|
// 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,
|
(BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate, _) => true,
|
||||||
ParamCandidate(ref cand) => match victim.candidate {
|
(_, BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate) => false,
|
||||||
AutoImplCandidate(..) => {
|
|
||||||
bug!(
|
(ParamCandidate(..), ParamCandidate(..)) => false,
|
||||||
"default implementations shouldn't be recorded \
|
|
||||||
when there are other valid candidates"
|
// 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
|
||||||
BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate => false,
|
// over projection and object candidates.
|
||||||
|
(
|
||||||
|
ParamCandidate(ref cand),
|
||||||
ImplCandidate(..)
|
ImplCandidate(..)
|
||||||
| ClosureCandidate
|
| ClosureCandidate
|
||||||
| GeneratorCandidate
|
| GeneratorCandidate
|
||||||
|
@ -1302,28 +1366,45 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
| BuiltinObjectCandidate
|
| BuiltinObjectCandidate
|
||||||
| BuiltinUnsizeCandidate
|
| BuiltinUnsizeCandidate
|
||||||
| BuiltinCandidate { .. }
|
| BuiltinCandidate { .. }
|
||||||
| TraitAliasCandidate(..) => {
|
| TraitAliasCandidate(..)
|
||||||
// Global bounds from the where clause should be ignored
|
| ObjectCandidate
|
||||||
// here (see issue #50825). Otherwise, we have a where
|
| ProjectionCandidate(_),
|
||||||
// clause so don't go around looking for impls.
|
) => !is_global(cand),
|
||||||
!is_global(cand)
|
(ObjectCandidate | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
|
||||||
}
|
// Prefer these to a global where-clause bound
|
||||||
ObjectCandidate | ProjectionCandidate(_) => {
|
// (see issue #50825).
|
||||||
// Arbitrarily give param candidates priority
|
is_global(cand)
|
||||||
// over projection and object candidates.
|
}
|
||||||
!is_global(cand)
|
(
|
||||||
}
|
ImplCandidate(_)
|
||||||
ParamCandidate(..) => false,
|
| ClosureCandidate
|
||||||
},
|
| GeneratorCandidate
|
||||||
ObjectCandidate | ProjectionCandidate(_) => match victim.candidate {
|
| FnPointerCandidate
|
||||||
AutoImplCandidate(..) => {
|
| BuiltinObjectCandidate
|
||||||
bug!(
|
| BuiltinUnsizeCandidate
|
||||||
"default implementations shouldn't be recorded \
|
| BuiltinCandidate { has_nested: true }
|
||||||
when there are other valid candidates"
|
| TraitAliasCandidate(..),
|
||||||
);
|
ParamCandidate(ref cand),
|
||||||
}
|
) => {
|
||||||
// (*)
|
// Prefer these to a global where-clause bound
|
||||||
BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate => false,
|
// (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(..)
|
ImplCandidate(..)
|
||||||
| ClosureCandidate
|
| ClosureCandidate
|
||||||
| GeneratorCandidate
|
| GeneratorCandidate
|
||||||
|
@ -1331,99 +1412,100 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
| BuiltinObjectCandidate
|
| BuiltinObjectCandidate
|
||||||
| BuiltinUnsizeCandidate
|
| BuiltinUnsizeCandidate
|
||||||
| BuiltinCandidate { .. }
|
| BuiltinCandidate { .. }
|
||||||
| TraitAliasCandidate(..) => true,
|
| TraitAliasCandidate(..),
|
||||||
ObjectCandidate | ProjectionCandidate(_) => {
|
) => true,
|
||||||
// Shouldn't have both an object and projection candidate,
|
|
||||||
// nor multiple object candidates. Multiple projection
|
(
|
||||||
// candidates are ambiguous.
|
ImplCandidate(..)
|
||||||
false
|
| ClosureCandidate
|
||||||
}
|
| GeneratorCandidate
|
||||||
ParamCandidate(ref cand) => is_global(cand),
|
| FnPointerCandidate
|
||||||
},
|
| BuiltinObjectCandidate
|
||||||
ImplCandidate(other_def) => {
|
| BuiltinUnsizeCandidate
|
||||||
|
| BuiltinCandidate { .. }
|
||||||
|
| TraitAliasCandidate(..),
|
||||||
|
ObjectCandidate | ProjectionCandidate(_),
|
||||||
|
) => false,
|
||||||
|
|
||||||
|
(&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.
|
||||||
// This requires us to know *for sure* that the `other` impl applies
|
// This requires us to know *for sure* that the `other` impl applies
|
||||||
// i.e., `EvaluatedToOk`.
|
// i.e., `EvaluatedToOk`.
|
||||||
if other.evaluation.must_apply_modulo_regions() {
|
if other.evaluation.must_apply_modulo_regions() {
|
||||||
match victim.candidate {
|
let tcx = self.tcx();
|
||||||
ImplCandidate(victim_def) => {
|
if tcx.specializes((other_def, victim_def)) {
|
||||||
let tcx = self.tcx();
|
return true;
|
||||||
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);
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
|
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
|
// Everything else is ambiguous
|
||||||
}
|
(
|
||||||
ClosureCandidate
|
ImplCandidate(_)
|
||||||
| GeneratorCandidate
|
| ClosureCandidate
|
||||||
| FnPointerCandidate
|
| GeneratorCandidate
|
||||||
| BuiltinObjectCandidate
|
| FnPointerCandidate
|
||||||
| BuiltinUnsizeCandidate
|
| BuiltinObjectCandidate
|
||||||
| BuiltinCandidate { has_nested: true } => {
|
| BuiltinUnsizeCandidate
|
||||||
match victim.candidate {
|
| BuiltinCandidate { has_nested: true }
|
||||||
ParamCandidate(ref cand) => {
|
| TraitAliasCandidate(..),
|
||||||
// Prefer these to a global where-clause bound
|
ImplCandidate(_)
|
||||||
// (see issue #50825).
|
| ClosureCandidate
|
||||||
is_global(cand) && other.evaluation.must_apply_modulo_regions()
|
| GeneratorCandidate
|
||||||
}
|
| FnPointerCandidate
|
||||||
_ => false,
|
| BuiltinObjectCandidate
|
||||||
}
|
| BuiltinUnsizeCandidate
|
||||||
}
|
| BuiltinCandidate { has_nested: true }
|
||||||
_ => false,
|
| TraitAliasCandidate(..),
|
||||||
|
) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,26 +6,25 @@
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::iter::Once;
|
use std::iter::Once;
|
||||||
|
|
||||||
trait Lam<Binder> { type App; }
|
trait Lam<Binder> {
|
||||||
|
type App;
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct L1;
|
struct L1;
|
||||||
impl<'a> Lam<&'a u8> for L1 { type App = u8; }
|
impl<'a> Lam<&'a u8> for L1 {
|
||||||
|
type App = u8;
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct L2;
|
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 {
|
trait Case1 {
|
||||||
type C: Clone + Iterator<Item:
|
type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
|
||||||
Send + Iterator<Item:
|
//~^ ERROR overflow evaluating the requirement `<<Self as Case1>::C as std::iter::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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct S1;
|
pub struct S1;
|
||||||
|
@ -34,10 +33,20 @@ impl Case1 for S1 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assume_case1<T: Case1>() {
|
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>();
|
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>();
|
assert_b::<_, T::B>();
|
||||||
|
|
||||||
fn assert_c<_0, _1, _2, C>()
|
fn assert_c<_0, _1, _2, C>()
|
||||||
|
@ -46,7 +55,8 @@ fn assume_case1<T: Case1>() {
|
||||||
_2: Send + Iterator<Item = _1>,
|
_2: Send + Iterator<Item = _1>,
|
||||||
_1: for<'a> Lam<&'a u8, App = _0>,
|
_1: for<'a> Lam<&'a u8, App = _0>,
|
||||||
_0: Debug,
|
_0: Debug,
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
assert_c::<_, _, _, T::C>();
|
assert_c::<_, _, _, T::C>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0277]: `<<Self as Case1>::C as std::iter::Iterator>::Item` is not an iterator
|
error[E0275]: overflow evaluating the requirement `<<Self as Case1>::C as std::iter::Iterator>::Item`
|
||||||
--> $DIR/bad-bounds-on-assoc-in-trait.rs:22:5
|
--> $DIR/bad-bounds-on-assoc-in-trait.rs:28:5
|
||||||
|
|
|
|
||||||
LL | / type C: Clone + Iterator<Item:
|
LL | / type C: Clone + Iterator<Item:
|
||||||
LL | | Send + 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 {
|
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() {
|
fn main() {
|
||||||
(&|_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
|
(&|_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
|
||||||
//~^ ERROR: type mismatch in closure arguments
|
//~^ 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)`
|
= 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)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
trait MultiDispatch<T> {
|
trait MultiDispatch<T> {
|
||||||
|
@ -8,10 +10,16 @@ trait Trait: Sized {
|
||||||
type A: MultiDispatch<Self::B, O = Self>;
|
type A: MultiDispatch<Self::B, O = Self>;
|
||||||
type B;
|
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) }
|
fn test<T: Trait<B = i32>>(b: i32) -> T
|
||||||
//~^ ERROR mismatched types
|
where
|
||||||
|
T::A: MultiDispatch<i32>,
|
||||||
|
{
|
||||||
|
T::new(b)
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {}
|
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;
|
use std::ops::Add;
|
||||||
|
|
||||||
trait Trait<T> {
|
trait Trait<T> {
|
||||||
|
@ -18,7 +20,11 @@ enum Either<L, R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<L, R> 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 {
|
match self {
|
||||||
Either::Left(val) => val.get(),
|
Either::Left(val) => val.get(),
|
||||||
Either::Right(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<
|
fn add_generic<A: Add<B>, B>(
|
||||||
impl Trait<<A as Add<B>>::Output>,
|
lhs: A,
|
||||||
impl Trait<<A as Add<B>>::Output>
|
rhs: B,
|
||||||
> {
|
) -> Either<impl Trait<<A as Add<B>>::Output>, impl Trait<<A as Add<B>>::Output>> {
|
||||||
if true {
|
if true { Either::Left(Holder(lhs + rhs)) } else { Either::Right(Holder(lhs + rhs)) }
|
||||||
Either::Left(Holder(lhs + rhs))
|
|
||||||
} else {
|
|
||||||
Either::Right(Holder(lhs + rhs))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_one(
|
fn add_one(
|
||||||
value: u32,
|
value: u32,
|
||||||
) -> Either<impl Trait<<u32 as Add<u32>>::Output>, impl Trait<<u32 as Add<u32>>::Output>> {
|
) -> 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)
|
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() {
|
fn main() {
|
||||||
foo((), drop)
|
foo((), drop)
|
||||||
//~^ ERROR type mismatch in function arguments
|
//~^ 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) -> _`
|
| expected signature of `fn(<() as Trait<'a>>::Item) -> _`
|
||||||
| found signature of `fn(()) -> _`
|
| 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
|
// check-pass
|
||||||
// invalid code.
|
|
||||||
|
|
||||||
trait Parent {
|
trait Parent {
|
||||||
type Ty;
|
type Ty;
|
||||||
|
@ -17,7 +16,6 @@ struct ParentWrapper<T>(T);
|
||||||
impl<A, T: Parent<Ty = A>> Parent for ParentWrapper<T> {
|
impl<A, T: Parent<Ty = A>> Parent for ParentWrapper<T> {
|
||||||
type Ty = A;
|
type Ty = A;
|
||||||
type Assoc = ChildWrapper<T::Assoc>;
|
type Assoc = ChildWrapper<T::Assoc>;
|
||||||
//~^ ERROR the trait bound `<T as Parent>::Assoc: Child<A>` is not satisfied
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
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…
Add table
Add a link
Reference in a new issue