Skip to content

Commit 1376723

Browse files
authored
Merge pull request #4 from Centril/rfc/associated-type-bounds-patch-2
Associated type bounds: clarify stuff...
2 parents d1398b2 + fb31e7e commit 1376723

File tree

1 file changed

+122
-5
lines changed

1 file changed

+122
-5
lines changed

text/0000-associated-type-bounds.md

+122-5
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,58 @@ 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 Trait is
127+
existentially quantified, the `Assoc` is as well. Semantically speaking,
128+
`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 is semantically equivalent to:
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+
152+
[RFC 2071]: https://github.com/rust-lang/rfcs/blob/master/text/2071-impl-trait-type-alias.md
153+
154+
This syntax is specified in [RFC 2071]. As in that RFC, this documentation
155+
uses the non-final syntax for existential type aliases.
156+
103157
# Drawbacks
104158
[drawbacks]: #drawbacks
105159

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

113167
# Rationale and alternatives
114-
[alternatives]: #alternatives
168+
[alternatives]: #rationale-and-alternatives
115169

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

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

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

0 commit comments

Comments
 (0)