Normalize projection bounds when considering candidates

This unfortunately requires some winnowing hacks to avoid
now ambiguous candidates.
This commit is contained in:
Matthew Jasper 2020-07-24 19:10:22 +01:00
parent cfee49593d
commit 34e5a4992c
16 changed files with 390 additions and 256 deletions

View file

@ -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 `{:?}`: {:?}",

View file

@ -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(

View file

@ -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,
}
}

View file

@ -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>();
}

View file

@ -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`.

View file

@ -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() {}

View file

@ -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
}

View file

@ -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`.

View file

@ -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() {}

View file

@ -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`.

View file

@ -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)
}

View file

@ -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`.

View file

@ -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
}

View file

@ -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`.

View file

@ -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() {}

View file

@ -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`.