Skip to content

Commit 95d569a

Browse files
committed
rfc, associated-type-bounds: clarify a bunch of things / leave some things unresolved.
1 parent d1398b2 commit 95d569a

File tree

1 file changed

+117
-5
lines changed

1 file changed

+117
-5
lines changed

text/0000-associated-type-bounds.md

Lines changed: 117 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ Introduce the bound form `MyTrait<AssociatedType: Bounds>`, permitted anywhere
1010
a bound of the form `MyTrait<AssociatedType = T>` would be allowed. The bound
1111
`T: Trait<AssociatedType: Bounds>` desugars to the bounds `T: Trait` and
1212
`<T as Trait>::AssociatedType: Bounds`.
13+
See the [reference][reference-level-explanation] and [rationale][alternatives]
14+
for exact details.
1315

1416
# Motivation
1517
[motivation]: #motivation
@@ -86,8 +88,8 @@ impl<I: Clone + Iterator<Item: Clone>> Clone for Peekable<I> {
8688
# Reference-level explanation
8789
[reference-level-explanation]: #reference-level-explanation
8890

89-
The surface syntax `T: Trait<AssociatedType: Bounds>` should always desugar
90-
to a pair of bounds: `T: Trait` and `<T as Trait>::AssociatedType: Bounds`.
91+
The surface syntax `T: Trait<AssociatedType: Bounds>` should desugar to a pair
92+
of bounds: `T: Trait` and `<T as Trait>::AssociatedType: Bounds`.
9193
Rust currently allows both of those bounds anywhere a bound can currently appear;
9294
the new syntax does not introduce any new semantics.
9395

@@ -100,6 +102,53 @@ Meanwhile, the surface syntax `dyn Trait<AssociatedType: Bounds>` desugars into
100102
`dyn Trait<AssociatedType = T>` where `T` is a named type variable `T` with the
101103
bound `T: Bounds`.
102104

105+
## The desugaring for associated types
106+
107+
In the case of an associated type having a bound of the form:
108+
109+
```rust
110+
trait TraitA {
111+
type AssocA: TraitB<AssocB: TraitC>;
112+
}
113+
```
114+
115+
we desugar to an anonymous associated type for `AssocB`, which corresponds to:
116+
117+
```rust
118+
trait TraitA {
119+
type AssocA: TraitB<AssocB = Self::AssocA_0>;
120+
type AssocA_0: TraitC; // Associated type is Unnamed!
121+
}
122+
```
123+
124+
## Notes on the meaning of `impl Trait<Assoc: Bound>`
125+
126+
Note that in the context `-> impl Trait<Assoc: Bound>`, since the
127+
`Trait` is existentially quantified, so is in effect also the `Assoc`.
128+
Semantically speaking, `fn printables..` is equivalent to:
129+
130+
```rust
131+
fn printables() -> impl Iterator<Item = impl Display> { .. }
132+
```
133+
134+
For `arg: impl Trait<Assoc: Bound>`, it can likewise be seen as:
135+
`arg: impl Trait<Assoc = impl Bound>`.
136+
137+
## Meaning of `existential type Foo: Trait<Assoc: Bound>`
138+
139+
Given:
140+
141+
```
142+
existential type Foo: Trait<Assoc: Bound>;
143+
```
144+
145+
it can be seen as the same as:
146+
147+
```rust
148+
existential type Foo: Trait<Assoc = _0>;
149+
existential type _0: Bound;
150+
```
151+
103152
# Drawbacks
104153
[drawbacks]: #drawbacks
105154

@@ -111,16 +160,79 @@ different. However, we believe that the parallel to the use of bounds elsewhere
111160
makes this new syntax immediately recognizable and understandable.
112161

113162
# Rationale and alternatives
114-
[alternatives]: #alternatives
163+
[alternatives]: #rationale-and-alternatives
115164

116165
As with any new surface syntax, one alternative is simply not introducing
117166
the syntax at all. That would still leave developers with the
118167
`MyTrait<AssociatedType = impl Bounds>` form. However, allowing the more
119168
direct bounds syntax provides a better parallel to the use of bounds elsewhere.
120169
The introduced form in this RFC is comparatively both shorter and clearer.
121170

171+
### An alternative desugaring of bounds on associated types
172+
173+
[RFC 2089]: https://github.com/rust-lang/rfcs/blob/master/text/2089-implied-bounds.md
174+
175+
An alternative desugaring of the following definition:
176+
177+
```rust
178+
trait TraitA {
179+
type AssocA: TraitB<AssocB: TraitC>;
180+
}
181+
```
182+
183+
is to add the `where` clause, as specified above, to the trait, desugaring to:
184+
185+
```rust
186+
trait TraitA
187+
where
188+
<Self::AssocA as TraitB>::AssocB: TraitC,
189+
{
190+
type AssocA: TraitB;
191+
}
192+
```
193+
194+
However, at the time of this writing, a Rust compiler will treat this
195+
differently than the desugaring proposed in the reference.
196+
The following snippet illustrates the difference:
197+
198+
```rust
199+
trait Foo where <Self::Bar as Iterator>::Item: Copy {
200+
type Bar: Iterator;
201+
}
202+
203+
trait Foo2 {
204+
type Bar: Iterator<Item = Self::BarItem>;
205+
type BarItem: Copy;
206+
}
207+
208+
fn use_foo<X: Foo>(arg: X)
209+
where <X::Bar as Iterator>::Item: Copy
210+
// ^-- Remove this line and it will error with:
211+
// error[E0277]: `<<X as Foo>::Bar as std::iter::Iterator>::Item` doesn't implement `Copy`
212+
{
213+
let item: <X::Bar as Iterator>::Item;
214+
}
215+
216+
fn use_foo2<X: Foo2>(arg: X) {
217+
let item: <X::Bar as Iterator>::Item;
218+
}
219+
```
220+
221+
The desugaring with a `where` therefore becomes problematic from a perspective
222+
of usability.
223+
224+
However, [RFC 2089, Implied Bounds][RFC 2089] specifies that desugaring to the
225+
`where` clause in the trait will permit the `use_foo` function to omit its
226+
`where` clause. This entails that both desugarings become equivalent from the
227+
point of view of a user. The desugaring with `where` therefore becomes viable
228+
in the presence of [RFC 2089].
229+
122230
# Unresolved questions
123231
[unresolved]: #unresolved-questions
124232

125-
- Does allowing this for `dyn` trait objects introduce any unforseen issues?
126-
This can be resolved during stabilization.
233+
- Does allowing this for `dyn` trait objects introduce any unforeseen issues?
234+
This can be resolved during stabilization.
235+
236+
- The exact desugaring in the context of putting bounds on an associated type
237+
of a trait is left unresolved. The semantics should however be preserved.
238+
This is also the case with other desugarings in this RFC.

0 commit comments

Comments
 (0)