The following code should be accepted:
#![feature(generic_associated_types)]
trait X {
type Y<'a>;
}
fn f(x: Box<dyn X<Y<'a>=&'a ()>>) {}
// or perhaps:
// fn f(x: Box<dyn for<'a> X<Y<'a>=&'a ()>>) {}
fn g<T: X<Y<'a>=&'a ()>>() {}
I'll take at least the ast part of it for now
Am I correct in that we don't accept any type bounds on the left hand side and suggest moving them into a where clause?
Do you mean is X<Y<T: SomeTrait>=()> accepted? I would guess not because the bounds on T are already determined by the trait.
We allow repeating bounds in impl blocks though, i.e. this is permitted currently
#![feature(generic_associated_types)]
#![allow(incomplete_features)]
trait X<'b> {
type Y<'a: 'b>;
}
struct _S {}
impl<'a> X<'a> for _S {
type Y<'b: 'a> = ();
}
Edit: thinking about it, we probably wouldn't be able to do it even if we want to because we can't parse where clauses anyway
Is this still being handled? I am willing to look into it myself, I am currently stuck on needing this feature (and admittedly have a lot of time on my hands with recent events).
@SuperTails You are welcome to take it, Im busy with chalk work atm
https://github.com/rust-lang/rust/issues/44265#issuecomment-655759017
I found another case where this is needed: I have a trait definition which looks like this:
pub trait ViewFn<S> {
type Output<'ast>: Sized;
fn view<'ast>(&self, node: &'ast S) -> Self::Output<'ast>;
// ...
}
If I want to have a trait bound on ViewFn with Output constrained to be a reference to a object which implements a specific type, I would require this, e.g. the following currently doesn't work:
/*[...]*/<T, O, F>/*[...]*/
where
O: // omitted [...]
F: ViewFn<T, for<'x> Output<'x> = &'x O>,
Is this a duplicate? I copied this from the RFC. Playground.
trait StreamingIterator {
type Item<'a>;
fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
}
fn foo<T: for<'a> StreamingIterator<Item<'a> = &'a [i32]>>(iter: T) { unimplemented!() }
@vandenheuvel I think that is the same issue, yes.
Some thoughts:
Trait<A<'a>: Clone> should be supported as well (https://github.com/rust-lang/rust/issues/52662).Trait<A<T> = u8>
```
A<???>?Trait<A<u8> = u8> or Trait<A<[u8; 10]> = u8> make sense, or ??? must be a single type parameter?The fn f(x: Box<dyn for<'a> X<Y<'a>=&'a ()>>) {} example in the top comment implies that ??? is an argument after all (use, not definition).
I assume it's equivalent to an (unimplemented) type equality predicate in a where clause (for<'a> X::Y<'a> == &'a).
Then ??? can indeed be an arbitrary type (or lifetime) like u8 or [u8; 10].
From that we see that the associated type constraint syntax is really ambiguous with generic type parameters, but also get a clue on how to approach it during parsing.
When parsing a generic argument (inside Trait<...>) we just parse a type and then look at the next token:
=, then it's a type argument.= (Trait<TYPE = ...>), thenTYPE is a single-segment path, possibly with generic arguments (Trait<Ident<Args> = ...>), then we store it into AST as an associated type constraint,for<...> will be required to introduce names, but our syntax already accepts for<...> in that position
for<'a> Trait<A<'a> = &'a u8>
, so we don't have to introduce any new syntax for the name introducer like
Trait<for<'a> A<'a> = &'a u8>
(The only question is whether these two forms can be considered equivalent, it seems like yes.)
personally I would prefer
Trait<for<'a> A<'a> = &'a u8>
(about the alternative:) I just wonder what would happen if it may clash, like:
for<'a> X<'a>: Trait<A<'a> = &'a u8>
vs.
for<'x> X<'x>: Trait<for<'a> A<'a> = &'a u8>
I think we should allow both syntax '(es), which should be considered equivalent in simple cases, but may be able to express more complex relations cleanly.
The Trait<for<'a> A<'a> = &'a u8> form introduces a new syntax and requires a more complex disambiguation because types can start with for (Trait<for<'a> A<'a>> is a type argument, Trait<for<'a> A<'a> = &'a u8> is an assoc type constraint), so I'd prefer to avoid it for now.
It can be added later if it becomes necessary.
Most helpful comment
Some thoughts:
Trait<A<'a>: Clone>should be supported as well (https://github.com/rust-lang/rust/issues/52662).```rust
trait Trait {
type A
}
A<???>?(Arguments use already defined names and parameters introduce names.)
Does
Trait<A<u8> = u8>orTrait<A<[u8; 10]> = u8>make sense, or???must be a single type parameter?The
fn f(x: Box<dyn for<'a> X<Y<'a>=&'a ()>>) {}example in the top comment implies that???is an argument after all (use, not definition).I assume it's equivalent to an (unimplemented) type equality predicate in a
whereclause (for<'a> X::Y<'a> == &'a).Then
???can indeed be an arbitrary type (or lifetime) likeu8or[u8; 10].From that we see that the associated type constraint syntax is really ambiguous with generic type parameters, but also get a clue on how to approach it during parsing.
When parsing a generic argument (inside
Trait<...>) we just parse a type and then look at the next token:=, then it's a type argument.=(Trait<TYPE = ...>), thenTYPEis a single-segment path, possibly with generic arguments (Trait<Ident<Args> = ...>), then we store it into AST as an associated type constraint,for<...>will be required to introduce names, but our syntax already acceptsfor<...>in that position, so we don't have to introduce any new syntax for the name introducer like
(The only question is whether these two forms can be considered equivalent, it seems like yes.)