Rollup merge of #120584 - compiler-errors:u, r=lcnr

For a rigid projection, recursively look at the self type's item bounds to fix the `associated_type_bounds` feature

Given a deeply nested rigid projection like `<<<T as Trait1>::Assoc1 as Trait2>::Assoc2 as Trait3>::Assoc3`, this PR adjusts both trait solvers to look at the item bounds for all of `Assoc3`, `Assoc2`, and `Assoc1` in order to satisfy a goal. We do this because the item bounds for projections may contain relevant bounds for *other* nested projections when the `associated_type_bounds` (ATB) feature is enabled. For example:

```rust
#![feature(associated_type_bounds)]

trait Trait1 {
    type Assoc1: Trait2<Assoc2: Foo>;
    // Item bounds for `Assoc1` are:
    // `<Self as Trait1>::Assoc1: Trait2`
    // `<<Self as Trait1>::Assoc1 as Trait2>::Assoc2: Foo`
}

trait Trait2 {
    type Assoc2;
}

trait Foo {}

fn hello<T: Trait1>(x: <<T as Trait1>::Assoc1 as Trait2>::Assoc2) {
    fn is_foo(_: impl Foo) {}
    is_foo(x);
    // Currently fails with:
    // ERROR the trait bound `<<Self as Trait1>::Assoc1 as Trait2>::Assoc2: Foo` is not satisfied
}
```

This has been a long-standing place of brokenness for ATBs, and is also part of the reason why ATBs currently desugar so differently in various positions (i.e. sometimes desugaring to param-env bounds, sometimes desugaring to RPITs, etc). For example, in RPIT and TAIT position, `impl Foo<Bar: Baz>` currently desugars to `impl Foo<Bar = impl Baz>` because we do not currently take advantage of these nested item bounds if we desugared them into a single set of item bounds on the opaque. This is obviously both strange and unnecessary if we just take advantage of these bounds as we should.

## Approach

This PR repeatedly peels off each projection of a given goal's self type and tries to match its item bounds against a goal, repeating with the self type of the projection. This is pretty straightforward to implement in the new solver, only requiring us to loop on the self type of a rigid projection to discover inner rigid projections, and we also need to introduce an extra probe so we can normalize them.

In the old solver, we can do essentially the same thing, however we rely on the fact that projections *should* be normalized already. This is obviously not always the case -- however, in the case that they are not fully normalized, such as a projection which has both infer vars and, we bail out with ambiguity if we hit an infer var for the self type.

## Caveats

⚠️ In the old solver, this has the side-effect of actually stalling some higher-ranked trait goals of the form `for<'a> <?0 as Tr<'a>>: Tr2`. Because we stall them, they no longer are eagerly treated as error -- this cause some existing `known-bug` tests to go from fail -> pass.

I'm pretty unconvinced that this is a problem since we make code that we expect to pass in the *new* solver also pass in the *old* solver, though this obviously doesn't solve the *full* problem.

## And then also...

We also adjust the desugaring of ATB to always desugar to a regular associated bound, rather than sometimes to an impl Trait **except** for when the ATB is present in a `dyn Trait`. We need to lower `dyn Trait<Assoc: Bar>` to `dyn Trait<Assoc = impl Bar>` because object types need all of their associated types specified.

I would also be in favor of splitting out the ATB feature and/or removing support for object types in order to stabilize just the set of positions for which the ATB feature is consistent (i.e. always elaborates to a bound).
This commit is contained in:
Matthias Krüger 2024-02-10 00:58:36 +01:00 committed by GitHub
commit 9ec287dec2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 308 additions and 412 deletions

View File

@ -1092,24 +1092,22 @@ enum DesugarKind {
// Piggy-back on the `impl Trait` context to figure out the correct behavior.
let desugar_kind = match itctx {
// We are in the return position:
//
// fn foo() -> impl Iterator<Item: Debug>
//
// so desugar to
//
// fn foo() -> impl Iterator<Item = impl Debug>
ImplTraitContext::ReturnPositionOpaqueTy { .. }
| ImplTraitContext::TypeAliasesOpaqueTy { .. } => DesugarKind::ImplTrait,
// We are in the argument position, but within a dyn type:
// in an argument, RPIT, or TAIT, if we are within a dyn type:
//
// fn foo(x: dyn Iterator<Item: Debug>)
//
// so desugar to
// then desugar to:
//
// fn foo(x: dyn Iterator<Item = impl Debug>)
ImplTraitContext::Universal if self.is_in_dyn_type => DesugarKind::ImplTrait,
//
// This is because dyn traits must have all of their associated types specified.
ImplTraitContext::ReturnPositionOpaqueTy { .. }
| ImplTraitContext::TypeAliasesOpaqueTy { .. }
| ImplTraitContext::Universal
if self.is_in_dyn_type =>
{
DesugarKind::ImplTrait
}
ImplTraitContext::Disallowed(position) if self.is_in_dyn_type => {
DesugarKind::Error(position)

View File

@ -548,7 +548,27 @@ fn assemble_alias_bound_candidates<G: GoalKind<'tcx>>(
goal: Goal<'tcx, G>,
candidates: &mut Vec<Candidate<'tcx>>,
) {
let alias_ty = match goal.predicate.self_ty().kind() {
let () = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| {
ecx.assemble_alias_bound_candidates_recur(goal.predicate.self_ty(), goal, candidates);
});
}
/// For some deeply nested `<T>::A::B::C::D` rigid associated type,
/// we should explore the item bounds for all levels, since the
/// `associated_type_bounds` feature means that a parent associated
/// type may carry bounds for a nested associated type.
///
/// If we have a projection, check that its self type is a rigid projection.
/// If so, continue searching by recursively calling after normalization.
// FIXME: This may recurse infinitely, but I can't seem to trigger it without
// hitting another overflow error something. Add a depth parameter needed later.
fn assemble_alias_bound_candidates_recur<G: GoalKind<'tcx>>(
&mut self,
self_ty: Ty<'tcx>,
goal: Goal<'tcx, G>,
candidates: &mut Vec<Candidate<'tcx>>,
) {
let (kind, alias_ty) = match *self_ty.kind() {
ty::Bool
| ty::Char
| ty::Int(_)
@ -573,13 +593,27 @@ fn assemble_alias_bound_candidates<G: GoalKind<'tcx>>(
| ty::Param(_)
| ty::Placeholder(..)
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
| ty::Alias(ty::Inherent, _)
| ty::Alias(ty::Weak, _)
| ty::Error(_) => return,
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
| ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"),
// Excluding IATs and type aliases here as they don't have meaningful item bounds.
ty::Alias(ty::Projection | ty::Opaque, alias_ty) => alias_ty,
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) | ty::Bound(..) => {
bug!("unexpected self type for `{goal:?}`")
}
ty::Infer(ty::TyVar(_)) => {
// If we hit infer when normalizing the self type of an alias,
// then bail with ambiguity. We should never encounter this on
// the *first* iteration of this recursive function.
if let Ok(result) =
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
{
candidates.push(Candidate { source: CandidateSource::AliasBound, result });
}
return;
}
ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty),
ty::Alias(ty::Inherent | ty::Weak, _) => {
unreachable!("Weak and Inherent aliases should have been normalized away already")
}
};
for assumption in
@ -587,9 +621,28 @@ fn assemble_alias_bound_candidates<G: GoalKind<'tcx>>(
{
match G::consider_alias_bound_candidate(self, goal, assumption) {
Ok(result) => {
candidates.push(Candidate { source: CandidateSource::AliasBound, result })
candidates.push(Candidate { source: CandidateSource::AliasBound, result });
}
Err(NoSolution) => {}
}
}
if kind != ty::Projection {
return;
}
match self.try_normalize_ty(goal.param_env, alias_ty.self_ty()) {
// Recurse on the self type of the projection.
Some(next_self_ty) => {
self.assemble_alias_bound_candidates_recur(next_self_ty, goal, candidates);
}
// Bail if we overflow when normalizing, adding an ambiguous candidate.
None => {
if let Ok(result) =
self.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW)
{
candidates.push(Candidate { source: CandidateSource::AliasBound, result });
}
Err(NoSolution) => (),
}
}
}

View File

@ -40,6 +40,7 @@
use rustc_span::symbol::sym;
use std::collections::BTreeMap;
use std::ops::ControlFlow;
pub use rustc_middle::traits::Reveal;
@ -1614,32 +1615,44 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
candidate_set: &mut ProjectionCandidateSet<'tcx>,
) {
debug!("assemble_candidates_from_trait_def(..)");
let mut ambiguous = false;
selcx.for_each_item_bound(
obligation.predicate.self_ty(),
|selcx, clause, _| {
let Some(clause) = clause.as_projection_clause() else {
return ControlFlow::Continue(());
};
let tcx = selcx.tcx();
// Check whether the self-type is itself a projection.
// If so, extract what we know from the trait and try to come up with a good answer.
let bounds = match *obligation.predicate.self_ty().kind() {
// Excluding IATs and type aliases here as they don't have meaningful item bounds.
ty::Alias(ty::Projection | ty::Opaque, ref data) => {
tcx.item_bounds(data.def_id).instantiate(tcx, data.args)
}
ty::Infer(ty::TyVar(_)) => {
// If the self-type is an inference variable, then it MAY wind up
// being a projected type, so induce an ambiguity.
candidate_set.mark_ambiguous();
return;
}
_ => return,
};
let is_match =
selcx.infcx.probe(|_| selcx.match_projection_projections(obligation, clause, true));
assemble_candidates_from_predicates(
selcx,
obligation,
candidate_set,
ProjectionCandidate::TraitDef,
bounds.iter(),
true,
match is_match {
ProjectionMatchesProjection::Yes => {
candidate_set.push_candidate(ProjectionCandidate::TraitDef(clause));
if !obligation.predicate.has_non_region_infer() {
// HACK: Pick the first trait def candidate for a fully
// inferred predicate. This is to allow duplicates that
// differ only in normalization.
return ControlFlow::Break(());
}
}
ProjectionMatchesProjection::Ambiguous => {
candidate_set.mark_ambiguous();
}
ProjectionMatchesProjection::No => {}
}
ControlFlow::Continue(())
},
// `ProjectionCandidateSet` is borrowed in the above closure,
// so just mark ambiguous outside of the closure.
|| ambiguous = true,
);
if ambiguous {
candidate_set.mark_ambiguous();
}
}
/// In the case of a trait object like

View File

@ -6,13 +6,16 @@
//!
//! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly
use std::ops::ControlFlow;
use hir::def_id::DefId;
use hir::LangItem;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_infer::traits::ObligationCause;
use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError};
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt};
use crate::traits;
use crate::traits::query::evaluate_obligation::InferCtxtExt;
@ -158,11 +161,50 @@ fn assemble_candidates_from_projected_tys(
_ => return,
}
let result = self
.infcx
.probe(|_| self.match_projection_obligation_against_definition_bounds(obligation));
self.infcx.probe(|_| {
let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate);
let placeholder_trait_predicate =
self.infcx.enter_forall_and_leak_universe(poly_trait_predicate);
debug!(?placeholder_trait_predicate);
candidates.vec.extend(result.into_iter().map(|idx| ProjectionCandidate(idx)));
// The bounds returned by `item_bounds` may contain duplicates after
// normalization, so try to deduplicate when possible to avoid
// unnecessary ambiguity.
let mut distinct_normalized_bounds = FxHashSet::default();
self.for_each_item_bound::<!>(
placeholder_trait_predicate.self_ty(),
|selcx, bound, idx| {
let Some(bound) = bound.as_trait_clause() else {
return ControlFlow::Continue(());
};
if bound.polarity() != placeholder_trait_predicate.polarity {
return ControlFlow::Continue(());
}
selcx.infcx.probe(|_| {
match selcx.match_normalize_trait_ref(
obligation,
bound.to_poly_trait_ref(),
placeholder_trait_predicate.trait_ref,
) {
Ok(None) => {
candidates.vec.push(ProjectionCandidate(idx));
}
Ok(Some(normalized_trait))
if distinct_normalized_bounds.insert(normalized_trait) =>
{
candidates.vec.push(ProjectionCandidate(idx));
}
_ => {}
}
});
ControlFlow::Continue(())
},
// On ambiguity.
|| candidates.ambiguous = true,
);
});
}
/// Given an obligation like `<SomeTrait for T>`, searches the obligations that the caller

View File

@ -162,20 +162,26 @@ fn confirm_projection_candidate(
self.infcx.enter_forall_and_leak_universe(trait_predicate).trait_ref;
let placeholder_self_ty = placeholder_trait_predicate.self_ty();
let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate);
let (def_id, args) = match *placeholder_self_ty.kind() {
// Excluding IATs and type aliases here as they don't have meaningful item bounds.
ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
(def_id, args)
}
_ => bug!("projection candidate for unexpected type: {:?}", placeholder_self_ty),
};
let candidate_predicate =
tcx.item_bounds(def_id).map_bound(|i| i[idx]).instantiate(tcx, args);
let candidate_predicate = self
.for_each_item_bound(
placeholder_self_ty,
|_, clause, clause_idx| {
if clause_idx == idx {
ControlFlow::Break(clause)
} else {
ControlFlow::Continue(())
}
},
|| unreachable!(),
)
.break_value()
.expect("expected to index into clause that exists");
let candidate = candidate_predicate
.as_trait_clause()
.expect("projection candidate is not a trait predicate")
.map_bound(|t| t.trait_ref);
let mut obligations = Vec::new();
let candidate = normalize_with_depth_to(
self,
@ -194,8 +200,9 @@ fn confirm_projection_candidate(
.map_err(|_| Unimplemented)
})?);
if let ty::Alias(ty::Projection, ..) = placeholder_self_ty.kind() {
let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, args);
// FIXME(compiler-errors): I don't think this is needed.
if let ty::Alias(ty::Projection, alias_ty) = placeholder_self_ty.kind() {
let predicates = tcx.predicates_of(alias_ty.def_id).instantiate_own(tcx, alias_ty.args);
for (predicate, _) in predicates {
let normalized = normalize_with_depth_to(
self,

View File

@ -52,6 +52,7 @@
use std::cmp;
use std::fmt::{self, Display};
use std::iter;
use std::ops::ControlFlow;
pub use rustc_middle::traits::select::*;
use rustc_middle::ty::print::with_no_trimmed_paths;
@ -1592,71 +1593,41 @@ fn insert_candidate_cache(
self.infcx.selection_cache.insert((param_env, pred), dep_node, candidate);
}
/// Matches a predicate against the bounds of its self type.
///
/// Given an obligation like `<T as Foo>::Bar: Baz` where the self type is
/// a projection, look at the bounds of `T::Bar`, see if we can find a
/// `Baz` bound. We return indexes into the list returned by
/// `tcx.item_bounds` for any applicable bounds.
#[instrument(level = "debug", skip(self), ret)]
fn match_projection_obligation_against_definition_bounds(
/// Looks at the item bounds of the projection or opaque type.
/// If this is a nested rigid projection, such as
/// `<<T as Tr1>::Assoc as Tr2>::Assoc`, consider the item bounds
/// on both `Tr1::Assoc` and `Tr2::Assoc`, since we may encounter
/// relative bounds on both via the `associated_type_bounds` feature.
pub(super) fn for_each_item_bound<T>(
&mut self,
obligation: &PolyTraitObligation<'tcx>,
) -> smallvec::SmallVec<[usize; 2]> {
let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate);
let placeholder_trait_predicate =
self.infcx.enter_forall_and_leak_universe(poly_trait_predicate);
debug!(?placeholder_trait_predicate);
let tcx = self.infcx.tcx;
let (def_id, args) = match *placeholder_trait_predicate.trait_ref.self_ty().kind() {
ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
(def_id, args)
}
_ => {
span_bug!(
obligation.cause.span,
"match_projection_obligation_against_definition_bounds() called \
but self-ty is not a projection: {:?}",
placeholder_trait_predicate.trait_ref.self_ty()
);
}
};
let bounds = tcx.item_bounds(def_id).instantiate(tcx, args);
// The bounds returned by `item_bounds` may contain duplicates after
// normalization, so try to deduplicate when possible to avoid
// unnecessary ambiguity.
let mut distinct_normalized_bounds = FxHashSet::default();
bounds
.iter()
.enumerate()
.filter_map(|(idx, bound)| {
let bound_predicate = bound.kind();
if let ty::ClauseKind::Trait(pred) = bound_predicate.skip_binder() {
let bound = bound_predicate.rebind(pred.trait_ref);
if self.infcx.probe(|_| {
match self.match_normalize_trait_ref(
obligation,
bound,
placeholder_trait_predicate.trait_ref,
) {
Ok(None) => true,
Ok(Some(normalized_trait))
if distinct_normalized_bounds.insert(normalized_trait) =>
{
true
}
_ => false,
}
}) {
return Some(idx);
}
mut self_ty: Ty<'tcx>,
mut for_each: impl FnMut(&mut Self, ty::Clause<'tcx>, usize) -> ControlFlow<T, ()>,
on_ambiguity: impl FnOnce(),
) -> ControlFlow<T, ()> {
let mut idx = 0;
loop {
let (kind, alias_ty) = match *self_ty.kind() {
ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty),
ty::Infer(ty::TyVar(_)) => {
on_ambiguity();
return ControlFlow::Continue(());
}
None
})
.collect()
_ => return ControlFlow::Continue(()),
};
for bound in
self.tcx().item_bounds(alias_ty.def_id).instantiate(self.tcx(), alias_ty.args)
{
for_each(self, bound, idx)?;
idx += 1;
}
if kind == ty::Projection {
self_ty = alias_ty.self_ty();
} else {
return ControlFlow::Continue(());
}
}
}
/// Equates the trait in `obligation` with trait bound. If the two traits

View File

@ -1,5 +1,4 @@
// NOTE: rustc cannot currently handle bounds of the form `for<'a> <Foo as Bar<'a>>::Assoc: Baz`.
// This should hopefully be fixed with Chalk.
// check-pass
#![feature(associated_type_bounds)]
@ -24,9 +23,6 @@ impl<'a, 'b> Lam<&'a &'b u8> for L2 {
trait Case1 {
type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
//~^ ERROR `<<Self as Case1>::C as Iterator>::Item` is not an iterator
//~| ERROR `<<Self as Case1>::C as Iterator>::Item` cannot be sent between threads safely
//~| ERROR `<<Self as Case1>::C as Iterator>::Item` cannot be shared between threads safely
}
pub struct S1;
@ -35,33 +31,17 @@ impl Case1 for S1 {
}
fn assume_case1<T: Case1>() {
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,
{
}
assert_b::<_, T::B>();
fn assert_c<_0, _1, _2, C>()
fn assert_c<_1, _2, C>()
where
C: Clone + Iterator<Item = _2>,
_2: Send + Iterator<Item = _1>,
_1: for<'a> Lam<&'a u8, App = _0>,
_0: Debug,
_1: for<'a> Lam<&'a u8>,
for<'a> <_1 as Lam<&'a u8>>::App: Debug,
{
}
assert_c::<_, _, _, T::C>();
assert_c::<_, _, T::C>();
}
fn main() {
assume_case1(S1);
assume_case1::<S1>();
}

View File

@ -1,39 +0,0 @@
error[E0277]: `<<Self as Case1>::C as Iterator>::Item` cannot be sent between threads safely
--> $DIR/bad-bounds-on-assoc-in-trait.rs:26:36
|
LL | type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
| ^^^^ `<<Self as Case1>::C as Iterator>::Item` cannot be sent between threads safely
|
= help: the trait `Send` is not implemented for `<<Self as Case1>::C as Iterator>::Item`
help: consider further restricting the associated type
|
LL | trait Case1 where <<Self as Case1>::C as Iterator>::Item: Send {
| ++++++++++++++++++++++++++++++++++++++++++++++++++
error[E0277]: `<<Self as Case1>::C as Iterator>::Item` is not an iterator
--> $DIR/bad-bounds-on-assoc-in-trait.rs:26:43
|
LL | type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `<<Self as Case1>::C as Iterator>::Item` is not an iterator
|
= help: the trait `Iterator` is not implemented for `<<Self as Case1>::C as Iterator>::Item`
help: consider further restricting the associated type
|
LL | trait Case1 where <<Self as Case1>::C as Iterator>::Item: Iterator {
| ++++++++++++++++++++++++++++++++++++++++++++++++++++++
error[E0277]: `<<Self as Case1>::C as Iterator>::Item` cannot be shared between threads safely
--> $DIR/bad-bounds-on-assoc-in-trait.rs:26:93
|
LL | type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
| ^^^^ `<<Self as Case1>::C as Iterator>::Item` cannot be shared between threads safely
|
= help: the trait `Sync` is not implemented for `<<Self as Case1>::C as Iterator>::Item`
help: consider further restricting the associated type
|
LL | trait Case1 where <<Self as Case1>::C as Iterator>::Item: Sync {
| ++++++++++++++++++++++++++++++++++++++++++++++++++
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -1,3 +1,5 @@
// check-pass
#![feature(associated_type_bounds)]
use std::fmt::Debug;
@ -16,8 +18,6 @@
trait Case1 {
type A: Iterator<Item: Debug>;
//~^ ERROR `<<Self as Case1>::A as Iterator>::Item` doesn't implement `Debug`
type B: Iterator<Item: 'static>;
}
@ -33,7 +33,6 @@ impl Case1 for S1 {
// bounds of `Out`, but trait selection can't find the bound since it applies
// to a type other than `Self::Out`.
pub trait Foo { type Out: Baz<Assoc: Default>; }
//~^ ERROR trait bound `<<Self as Foo>::Out as Baz>::Assoc: Default` is not satisfied
pub trait Baz { type Assoc; }
#[derive(Default)]

View File

@ -1,26 +0,0 @@
error[E0277]: `<<Self as Case1>::A as Iterator>::Item` doesn't implement `Debug`
--> $DIR/bounds-on-assoc-in-trait.rs:18:28
|
LL | type A: Iterator<Item: Debug>;
| ^^^^^ `<<Self as Case1>::A as Iterator>::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
= help: the trait `Debug` is not implemented for `<<Self as Case1>::A as Iterator>::Item`
help: consider further restricting the associated type
|
LL | trait Case1 where <<Self as Case1>::A as Iterator>::Item: Debug {
| +++++++++++++++++++++++++++++++++++++++++++++++++++
error[E0277]: the trait bound `<<Self as Foo>::Out as Baz>::Assoc: Default` is not satisfied
--> $DIR/bounds-on-assoc-in-trait.rs:35:38
|
LL | pub trait Foo { type Out: Baz<Assoc: Default>; }
| ^^^^^^^ the trait `Default` is not implemented for `<<Self as Foo>::Out as Baz>::Assoc`
|
help: consider further restricting the associated type
|
LL | pub trait Foo where <<Self as Foo>::Out as Baz>::Assoc: Default { type Out: Baz<Assoc: Default>; }
| +++++++++++++++++++++++++++++++++++++++++++++++++
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -251,13 +251,10 @@ trait TRSW3
trait TRA1 {
type A: Iterator<Item: Copy, Item: Send>;
//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
//~| ERROR `<<Self as TRA1>::A as Iterator>::Item` cannot be sent between threads safely
//~| ERROR the trait bound `<<Self as TRA1>::A as Iterator>::Item: Copy` is not satisfied
}
trait TRA2 {
type A: Iterator<Item: Copy, Item: Copy>;
//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
//~| ERROR the trait bound `<<Self as TRA2>::A as Iterator>::Item: Copy` is not satisfied
}
trait TRA3 {
type A: Iterator<Item: 'static, Item: 'static>;

View File

@ -7,7 +7,7 @@ LL | struct SI1<T: Iterator<Item: Copy, Item: Send>> {
| `Item` bound here first
error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
--> $DIR/duplicate.rs:267:40
--> $DIR/duplicate.rs:264:40
|
LL | type TADyn1 = dyn Iterator<Item: Copy, Item: Send>;
| ---------- ^^^^^^^^^^ re-bound here
@ -15,7 +15,7 @@ LL | type TADyn1 = dyn Iterator<Item: Copy, Item: Send>;
| `Item` bound here first
error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
--> $DIR/duplicate.rs:269:44
--> $DIR/duplicate.rs:266:44
|
LL | type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>;
| ---------- ^^^^^^^^^^ re-bound here
@ -23,7 +23,7 @@ LL | type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>;
| `Item` bound here first
error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
--> $DIR/duplicate.rs:271:43
--> $DIR/duplicate.rs:268:43
|
LL | type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>;
| ------------- ^^^^^^^^^^^^^ re-bound here
@ -523,7 +523,7 @@ LL | type A: Iterator<Item: Copy, Item: Send>;
| `Item` bound here first
error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
--> $DIR/duplicate.rs:258:34
--> $DIR/duplicate.rs:256:34
|
LL | type A: Iterator<Item: Copy, Item: Copy>;
| ---------- ^^^^^^^^^^ re-bound here
@ -531,7 +531,7 @@ LL | type A: Iterator<Item: Copy, Item: Copy>;
| `Item` bound here first
error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
--> $DIR/duplicate.rs:263:37
--> $DIR/duplicate.rs:260:37
|
LL | type A: Iterator<Item: 'static, Item: 'static>;
| ------------- ^^^^^^^^^^^^^ re-bound here
@ -631,41 +631,7 @@ LL | Self: Iterator<Item: 'static, Item: 'static>,
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0277]: the trait bound `<<Self as TRA1>::A as Iterator>::Item: Copy` is not satisfied
--> $DIR/duplicate.rs:252:28
|
LL | type A: Iterator<Item: Copy, Item: Send>;
| ^^^^ the trait `Copy` is not implemented for `<<Self as TRA1>::A as Iterator>::Item`
|
help: consider further restricting the associated type
|
LL | trait TRA1 where <<Self as TRA1>::A as Iterator>::Item: Copy {
| +++++++++++++++++++++++++++++++++++++++++++++++++
error: aborting due to 75 previous errors
error[E0277]: `<<Self as TRA1>::A as Iterator>::Item` cannot be sent between threads safely
--> $DIR/duplicate.rs:252:40
|
LL | type A: Iterator<Item: Copy, Item: Send>;
| ^^^^ `<<Self as TRA1>::A as Iterator>::Item` cannot be sent between threads safely
|
= help: the trait `Send` is not implemented for `<<Self as TRA1>::A as Iterator>::Item`
help: consider further restricting the associated type
|
LL | trait TRA1 where <<Self as TRA1>::A as Iterator>::Item: Send {
| +++++++++++++++++++++++++++++++++++++++++++++++++
error[E0277]: the trait bound `<<Self as TRA2>::A as Iterator>::Item: Copy` is not satisfied
--> $DIR/duplicate.rs:258:28
|
LL | type A: Iterator<Item: Copy, Item: Copy>;
| ^^^^ the trait `Copy` is not implemented for `<<Self as TRA2>::A as Iterator>::Item`
|
help: consider further restricting the associated type
|
LL | trait TRA2 where <<Self as TRA2>::A as Iterator>::Item: Copy {
| +++++++++++++++++++++++++++++++++++++++++++++++++
error: aborting due to 78 previous errors
Some errors have detailed explanations: E0277, E0282, E0719.
For more information about an error, try `rustc --explain E0277`.
Some errors have detailed explanations: E0282, E0719.
For more information about an error, try `rustc --explain E0282`.

View File

@ -0,0 +1,17 @@
// check-pass
#![feature(associated_type_bounds)]
trait A<'a> {
type Assoc: ?Sized;
}
impl<'a> A<'a> for () {
type Assoc = &'a ();
}
fn hello() -> impl for<'a> A<'a, Assoc: Sized> {
()
}
fn main() {}

View File

@ -0,0 +1,37 @@
// check-pass
#![feature(associated_type_bounds)]
trait Trait1 {
type Assoc1: Bar;
fn assoc(self) -> Self::Assoc1;
}
impl Trait1 for () {
type Assoc1 = ();
fn assoc(self) {}
}
trait Foo {}
impl Foo for () {}
trait Bar {}
impl Bar for () {}
fn hello() -> impl Trait1<Assoc1: Foo> {
()
}
fn world() {
// Tests that `Assoc1: Foo` bound in the RPIT doesn't disqualify
// the `Assoc1: Bar` bound in the item, as a nested RPIT desugaring
// would do.
fn is_foo(_: impl Foo) {}
is_foo(hello().assoc());
fn is_bar(_: impl Bar) {}
is_bar(hello().assoc());
}
fn main() {}

View File

@ -12,6 +12,10 @@ LL | trait X<'a>
LL | where
LL | for<'b> <Self as X<'b>>::U: Clone,
| ^^^^^ required by this bound in `X`
help: consider further restricting the associated type
|
LL | fn f<'a, T: X<'a> + ?Sized>(x: &<T as X<'a>>::U) where for<'b> <T as X<'b>>::U: Clone {
| ++++++++++++++++++++++++++++++++++++
error: aborting due to 1 previous error

View File

@ -1,5 +1,5 @@
warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/normalizing-self-auto-trait-issue-109924.rs:7:12
--> $DIR/normalizing-self-auto-trait-issue-109924.rs:6:12
|
LL | #![feature(return_type_notation)]
| ^^^^^^^^^^^^^^^^^^^^
@ -7,29 +7,5 @@ LL | #![feature(return_type_notation)]
= note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
= note: `#[warn(incomplete_features)]` on by default
error[E0277]: `impl Future<Output = ()> { <_ as Foo>::bar() }` cannot be sent between threads safely
--> $DIR/normalizing-self-auto-trait-issue-109924.rs:22:11
|
LL | build(Bar);
| ----- ^^^ `impl Future<Output = ()> { <_ as Foo>::bar() }` cannot be sent between threads safely
| |
| required by a bound introduced by this call
|
= help: the trait `for<'a> Send` is not implemented for `impl Future<Output = ()> { <_ as Foo>::bar() }`
note: this is a known limitation of the trait solver that will be lifted in the future
--> $DIR/normalizing-self-auto-trait-issue-109924.rs:22:11
|
LL | build(Bar);
| ------^^^-
| | |
| | the trait solver is unable to infer the generic types that should be inferred from this argument
| add turbofish arguments to this call to specify the types manually, even if it's redundant
note: required by a bound in `build`
--> $DIR/normalizing-self-auto-trait-issue-109924.rs:19:39
|
LL | fn build<T>(_: T) where T: Foo<bar(): Send> {}
| ^^^^ required by this bound in `build`
warning: 1 warning emitted
error: aborting due to 1 previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0277`.

View File

@ -1,5 +1,5 @@
warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/normalizing-self-auto-trait-issue-109924.rs:7:12
--> $DIR/normalizing-self-auto-trait-issue-109924.rs:6:12
|
LL | #![feature(return_type_notation)]
| ^^^^^^^^^^^^^^^^^^^^

View File

@ -1,11 +1,10 @@
// check-pass
// revisions: current next
//[current] known-bug: #109924
//[next] check-pass
//[next] compile-flags: -Znext-solver
// edition:2021
#![feature(return_type_notation)]
//[next]~^ WARN the feature `return_type_notation` is incomplete
//~^ WARN the feature `return_type_notation` is incomplete
trait Foo {
async fn bar(&self);

View File

@ -11,7 +11,6 @@
trait _Tr3 {
type A: Iterator<Item: Copy>;
//~^ ERROR associated type bounds are unstable
//~| ERROR the trait bound `<<Self as _Tr3>::A as Iterator>::Item: Copy` is not satisfied
type B: Iterator<Item: 'static>;
//~^ ERROR associated type bounds are unstable

View File

@ -9,7 +9,7 @@ LL | type A: Iterator<Item: Copy>;
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: associated type bounds are unstable
--> $DIR/feature-gate-associated_type_bounds.rs:16:22
--> $DIR/feature-gate-associated_type_bounds.rs:15:22
|
LL | type B: Iterator<Item: 'static>;
| ^^^^^^^^^^^^^
@ -19,7 +19,7 @@ LL | type B: Iterator<Item: 'static>;
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: associated type bounds are unstable
--> $DIR/feature-gate-associated_type_bounds.rs:20:20
--> $DIR/feature-gate-associated_type_bounds.rs:19:20
|
LL | struct _St1<T: Tr1<As1: Tr2>> {
| ^^^^^^^^
@ -29,7 +29,7 @@ LL | struct _St1<T: Tr1<As1: Tr2>> {
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: associated type bounds are unstable
--> $DIR/feature-gate-associated_type_bounds.rs:27:18
--> $DIR/feature-gate-associated_type_bounds.rs:26:18
|
LL | enum _En1<T: Tr1<As1: Tr2>> {
| ^^^^^^^^
@ -39,7 +39,7 @@ LL | enum _En1<T: Tr1<As1: Tr2>> {
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: associated type bounds are unstable
--> $DIR/feature-gate-associated_type_bounds.rs:34:19
--> $DIR/feature-gate-associated_type_bounds.rs:33:19
|
LL | union _Un1<T: Tr1<As1: Tr2>> {
| ^^^^^^^^
@ -49,7 +49,7 @@ LL | union _Un1<T: Tr1<As1: Tr2>> {
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: associated type bounds are unstable
--> $DIR/feature-gate-associated_type_bounds.rs:41:37
--> $DIR/feature-gate-associated_type_bounds.rs:40:37
|
LL | type _TaWhere1<T> where T: Iterator<Item: Copy> = T;
| ^^^^^^^^^^
@ -59,7 +59,7 @@ LL | type _TaWhere1<T> where T: Iterator<Item: Copy> = T;
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: associated type bounds are unstable
--> $DIR/feature-gate-associated_type_bounds.rs:44:22
--> $DIR/feature-gate-associated_type_bounds.rs:43:22
|
LL | fn _apit(_: impl Tr1<As1: Copy>) {}
| ^^^^^^^^^
@ -69,7 +69,7 @@ LL | fn _apit(_: impl Tr1<As1: Copy>) {}
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: associated type bounds are unstable
--> $DIR/feature-gate-associated_type_bounds.rs:46:26
--> $DIR/feature-gate-associated_type_bounds.rs:45:26
|
LL | fn _apit_dyn(_: &dyn Tr1<As1: Copy>) {}
| ^^^^^^^^^
@ -79,7 +79,7 @@ LL | fn _apit_dyn(_: &dyn Tr1<As1: Copy>) {}
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: associated type bounds are unstable
--> $DIR/feature-gate-associated_type_bounds.rs:49:24
--> $DIR/feature-gate-associated_type_bounds.rs:48:24
|
LL | fn _rpit() -> impl Tr1<As1: Copy> { S1 }
| ^^^^^^^^^
@ -89,7 +89,7 @@ LL | fn _rpit() -> impl Tr1<As1: Copy> { S1 }
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: associated type bounds are unstable
--> $DIR/feature-gate-associated_type_bounds.rs:52:31
--> $DIR/feature-gate-associated_type_bounds.rs:51:31
|
LL | fn _rpit_dyn() -> Box<dyn Tr1<As1: Copy>> { Box::new(S1) }
| ^^^^^^^^^
@ -99,7 +99,7 @@ LL | fn _rpit_dyn() -> Box<dyn Tr1<As1: Copy>> { Box::new(S1) }
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: associated type bounds are unstable
--> $DIR/feature-gate-associated_type_bounds.rs:55:23
--> $DIR/feature-gate-associated_type_bounds.rs:54:23
|
LL | const _cdef: impl Tr1<As1: Copy> = S1;
| ^^^^^^^^^
@ -109,7 +109,7 @@ LL | const _cdef: impl Tr1<As1: Copy> = S1;
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: associated type bounds are unstable
--> $DIR/feature-gate-associated_type_bounds.rs:61:24
--> $DIR/feature-gate-associated_type_bounds.rs:60:24
|
LL | static _sdef: impl Tr1<As1: Copy> = S1;
| ^^^^^^^^^
@ -119,7 +119,7 @@ LL | static _sdef: impl Tr1<As1: Copy> = S1;
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: associated type bounds are unstable
--> $DIR/feature-gate-associated_type_bounds.rs:68:21
--> $DIR/feature-gate-associated_type_bounds.rs:67:21
|
LL | let _: impl Tr1<As1: Copy> = S1;
| ^^^^^^^^^
@ -129,7 +129,7 @@ LL | let _: impl Tr1<As1: Copy> = S1;
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0562]: `impl Trait` is not allowed in const types
--> $DIR/feature-gate-associated_type_bounds.rs:55:14
--> $DIR/feature-gate-associated_type_bounds.rs:54:14
|
LL | const _cdef: impl Tr1<As1: Copy> = S1;
| ^^^^^^^^^^^^^^^^^^^
@ -137,7 +137,7 @@ LL | const _cdef: impl Tr1<As1: Copy> = S1;
= note: `impl Trait` is only allowed in arguments and return types of functions and methods
error[E0562]: `impl Trait` is not allowed in static types
--> $DIR/feature-gate-associated_type_bounds.rs:61:15
--> $DIR/feature-gate-associated_type_bounds.rs:60:15
|
LL | static _sdef: impl Tr1<As1: Copy> = S1;
| ^^^^^^^^^^^^^^^^^^^
@ -145,25 +145,14 @@ LL | static _sdef: impl Tr1<As1: Copy> = S1;
= note: `impl Trait` is only allowed in arguments and return types of functions and methods
error[E0562]: `impl Trait` is not allowed in the type of variable bindings
--> $DIR/feature-gate-associated_type_bounds.rs:68:12
--> $DIR/feature-gate-associated_type_bounds.rs:67:12
|
LL | let _: impl Tr1<As1: Copy> = S1;
| ^^^^^^^^^^^^^^^^^^^
|
= note: `impl Trait` is only allowed in arguments and return types of functions and methods
error[E0277]: the trait bound `<<Self as _Tr3>::A as Iterator>::Item: Copy` is not satisfied
--> $DIR/feature-gate-associated_type_bounds.rs:12:28
|
LL | type A: Iterator<Item: Copy>;
| ^^^^ the trait `Copy` is not implemented for `<<Self as _Tr3>::A as Iterator>::Item`
|
help: consider further restricting the associated type
|
LL | trait _Tr3 where <<Self as _Tr3>::A as Iterator>::Item: Copy {
| +++++++++++++++++++++++++++++++++++++++++++++++++
error: aborting due to 16 previous errors
error: aborting due to 17 previous errors
Some errors have detailed explanations: E0277, E0562, E0658.
For more information about an error, try `rustc --explain E0277`.
Some errors have detailed explanations: E0562, E0658.
For more information about an error, try `rustc --explain E0562`.

View File

@ -1,7 +1,4 @@
// check-fail
// known-bug: #88460
// This should pass, but has a missed normalization due to HRTB.
// check-pass
pub trait Marker {}

View File

@ -1,29 +0,0 @@
error[E0277]: the trait bound `for<'a> <_ as Trait>::Assoc<'a>: Marker` is not satisfied
--> $DIR/issue-88460.rs:28:10
|
LL | test(Foo);
| ---- ^^^ the trait `for<'a> Marker` is not implemented for `<_ as Trait>::Assoc<'a>`
| |
| required by a bound introduced by this call
|
= help: the trait `Marker` is implemented for `()`
note: this is a known limitation of the trait solver that will be lifted in the future
--> $DIR/issue-88460.rs:28:10
|
LL | test(Foo);
| -----^^^-
| | |
| | the trait solver is unable to infer the generic types that should be inferred from this argument
| add turbofish arguments to this call to specify the types manually, even if it's redundant
note: required by a bound in `test`
--> $DIR/issue-88460.rs:15:27
|
LL | fn test<T>(value: T)
| ---- required by a bound in this function
...
LL | for<'a> T::Assoc<'a>: Marker,
| ^^^^^^ required by this bound in `test`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.

View File

@ -1,5 +1,4 @@
// check-fail
// known-bug: #90950
// check-pass
trait Yokeable<'a>: 'static {
type Output: 'a;

View File

@ -1,29 +0,0 @@
error[E0277]: the trait bound `for<'a> <_ as Yokeable<'a>>::Output: IsCovariant<'a>` is not satisfied
--> $DIR/issue-90950.rs:50:12
|
LL | upcast(y)
| ------ ^ the trait `for<'a> IsCovariant<'a>` is not implemented for `<_ as Yokeable<'a>>::Output`
| |
| required by a bound introduced by this call
|
= help: the trait `IsCovariant<'a>` is implemented for `std::borrow::Cow<'a, T>`
note: this is a known limitation of the trait solver that will be lifted in the future
--> $DIR/issue-90950.rs:50:12
|
LL | upcast(y)
| -------^-
| | |
| | the trait solver is unable to infer the generic types that should be inferred from this argument
| add turbofish arguments to this call to specify the types manually, even if it's redundant
note: required by a bound in `upcast`
--> $DIR/issue-90950.rs:27:42
|
LL | fn upcast<Y>(x: Yoke<Y>) -> Yoke<Box<dyn IsCovariant<'static> + 'static>> where
| ------ required by a bound in this function
LL | Y: for<'a> Yokeable<'a>,
LL | for<'a> <Y as Yokeable<'a>>::Output: IsCovariant<'a>
| ^^^^^^^^^^^^^^^ required by this bound in `upcast`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.

View File

@ -1,5 +1,4 @@
// check-fail
// known-bug: #89196
// check-pass
// Should pass, but we normalize and check bounds before we resolve the generics
// of the function (which we know because of the return type).

View File

@ -1,23 +0,0 @@
error[E0277]: the trait bound `for<'a> <_ as Trait<'a>>::Out: Copy` is not satisfied
--> $DIR/norm-before-method-resolution.rs:22:17
|
LL | let _: () = weird_bound();
| ^^^^^^^^^^^^^ the trait `for<'a> Copy` is not implemented for `<_ as Trait<'a>>::Out`
|
note: this is a known limitation of the trait solver that will be lifted in the future
--> $DIR/norm-before-method-resolution.rs:22:17
|
LL | let _: () = weird_bound();
| ^^^^^^^^^^^^^ try adding turbofish arguments to this expression to specify the types manually, even if it's redundant
note: required by a bound in `weird_bound`
--> $DIR/norm-before-method-resolution.rs:18:40
|
LL | fn weird_bound<X>() -> X
| ----------- required by a bound in this function
...
LL | for<'a> <X as Trait<'a>>::Out: Copy
| ^^^^ required by this bound in `weird_bound`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.