Repository navigation
Open
Labels
A-GATsArea: Generic associated types (GATs)Area: Generic associated types (GATs)C-discussionCategory: Discussion or questions that doesn't represent real issues.Category: Discussion or questions that doesn't represent real issues.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.T-typesRelevant to the types team, which will review and decide on the PR/issue.Relevant to the types team, which will review and decide on the PR/issue.
Description
I tried this code:
#![feature(generic_associated_types)]
trait Collection {
type Iter<'a>: IntoIterator
where
<Self::Iter<'a> as IntoIterator>::Item: std::fmt::Debug;
}This fails to compile with:
Compiling playground v0.0.1 (/playground)
error[E0277]: the trait bound `<Self as Collection>::Iter<'a>: IntoIterator` is not satisfied
--> src/lib.rs:4:5
|
4 | / type Iter<'a>: IntoIterator
5 | | where
6 | | <Self::Iter<'a> as IntoIterator>::Item: std::fmt::Debug;
| |________________________________________________________________^ the trait `IntoIterator` is not implemented for `<Self as Collection>::Iter<'a>`
|
help: consider further restricting the associated type
|
3 | trait Collection where <Self as Collection>::Iter<'a>: IntoIterator {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0277]: the trait bound `<Self as Collection>::Iter<'a>: IntoIterator` is not satisfied
--> src/lib.rs:4:20
|
4 | type Iter<'a>: IntoIterator
| ^^^^^^^^^^^^ the trait `IntoIterator` is not implemented for `<Self as Collection>::Iter<'a>`
|
help: consider further restricting the associated type
|
3 | trait Collection where <Self as Collection>::Iter<'a>: IntoIterator {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` due to 2 previous errors
aka/rrevenantt on Discord discovered the following workaround, which to me seems like it should be treated the same as above. The only difference is the location of the bound - one using "inheritance style", the other as part of a where clause:
#![feature(generic_associated_types)]
trait Collection {
type Iter<'a>
where
Self::Iter<'a>: IntoIterator,
<Self::Iter<'a> as IntoIterator>::Item: std::fmt::Debug;
}It's worth noting that the same issue exists without GATs. But where clauses on associated types are also feature gated under generic_associated_types.
This fails to compile:
#![feature(generic_associated_types)]
trait Collection {
type Iter: IntoIterator
where
<Self::Iter as IntoIterator>::Item: std::fmt::Debug;
}However this works on stable (lifting the bound to the trait itself):
trait Collection
where
<Self::Iter as IntoIterator>::Item: std::fmt::Debug,
{
type Iter: IntoIterator;
}Metadata
Metadata
Assignees
Labels
A-GATsArea: Generic associated types (GATs)Area: Generic associated types (GATs)C-discussionCategory: Discussion or questions that doesn't represent real issues.Category: Discussion or questions that doesn't represent real issues.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.T-typesRelevant to the types team, which will review and decide on the PR/issue.Relevant to the types team, which will review and decide on the PR/issue.
Activity
udoprog commentedon Aug 7, 2021
So I encountered that the proposed workaround might not be as workable as I'd like, in that it requires the caller to specify that bound at each item where the associated type is used, like so:
And in my mental model I think this makes sense in general with GATs, because the item (
fn iter) might specify additional bounds on generic parameters. But it also means that it's a difference (intentional or not) with inheritance-style bounds liketype Iter<'a>: IntoIteratorwhich does not need to be specified every time it's used.Like this:
Compared to this:
jackh726 commentedon Aug 10, 2021
Ah, so. There indeed is a difference between writing
and
Specifically, the bounds
type Bar<T>: Debugmust be proved by the impl, whereas the where clauses must be provable by the type.The well-formedness rules for these are generally laid out pretty well in the Chalk book (http://rust-lang.github.io/chalk/book/clauses/wf.html). Though, this is the "ideal" world and might not be completely implemented in rustc this way (these in some ways rely on implied bounds and such).
But, I wanted to point out that for
we generate the following goal:
This is essentially saying that "if we assume the where clauses on the trait hold, then we require that the types present on those where clauses be well formed" and "if we assume the where clauses on the associated type hold too, then we require that the types in the bounds and where clauses on the associated type are well formed"
For this example:
there are no where clauses on the trait, so that bit is straightforward. But then we say that if
<Self::Iter<'a> as IntoIterator>::Item: std::fmt::Debugholds then we require thatSelf::Iter<'a>: IntoIteratoris well-formed. Importantly, the rules as-written don't take into account theIter<'a>: IntoIteratorbound.At first thought, this feels wrong to me: given that we have the
IntoIteratorbound, should we always satisfy that (and so we don't need to repeat that in the where clause)? Not sure :) This is something to think about.jackh726 commentedon Oct 16, 2021
GATs issue triage: not blocking. See my previous comment. This is probably code that shouldn't be written as-is. But nonetheless is not really a GATs issue.
Auto merge of rust-lang#96709 - jackh726:gats-stabilization, r=compil…
Auto merge of rust-lang#96709 - jackh726:gats-stabilization, r=compil…