diff --git a/text/0000-associated-type-bounds.md b/text/0000-associated-type-bounds.md index 26dfcfef454..3c00eb7250d 100644 --- a/text/0000-associated-type-bounds.md +++ b/text/0000-associated-type-bounds.md @@ -10,6 +10,8 @@ Introduce the bound form `MyTrait`, permitted anywhere a bound of the form `MyTrait` would be allowed. The bound `T: Trait` desugars to the bounds `T: Trait` and `::AssociatedType: Bounds`. +See the [reference][reference-level-explanation] and [rationale][alternatives] +for exact details. # Motivation [motivation]: #motivation @@ -86,8 +88,8 @@ impl> Clone for Peekable { # Reference-level explanation [reference-level-explanation]: #reference-level-explanation -The surface syntax `T: Trait` should always desugar -to a pair of bounds: `T: Trait` and `::AssociatedType: Bounds`. +The surface syntax `T: Trait` should desugar to a pair +of bounds: `T: Trait` and `::AssociatedType: Bounds`. Rust currently allows both of those bounds anywhere a bound can currently appear; the new syntax does not introduce any new semantics. @@ -100,6 +102,58 @@ Meanwhile, the surface syntax `dyn Trait` desugars into `dyn Trait` where `T` is a named type variable `T` with the bound `T: Bounds`. +## The desugaring for associated types + +In the case of an associated type having a bound of the form: + +```rust +trait TraitA { + type AssocA: TraitB; +} +``` + +we desugar to an anonymous associated type for `AssocB`, which corresponds to: + +```rust +trait TraitA { + type AssocA: TraitB; + type AssocA_0: TraitC; // Associated type is Unnamed! +} +``` + +## Notes on the meaning of `impl Trait` + +Note that in the context `-> impl Trait`, since the Trait is +existentially quantified, the `Assoc` is as well. Semantically speaking, +`fn printables..` is equivalent to: + +```rust +fn printables() -> impl Iterator { .. } +``` + +For `arg: impl Trait`, it is semantically equivalent to: +`arg: impl Trait`. + +## Meaning of `existential type Foo: Trait` + +Given: + +``` +existential type Foo: Trait; +``` + +it can be seen as the same as: + +```rust +existential type Foo: Trait; +existential type _0: Bound; +``` + +[RFC 2071]: https://github.com/rust-lang/rfcs/blob/master/text/2071-impl-trait-type-alias.md + +This syntax is specified in [RFC 2071]. As in that RFC, this documentation +uses the non-final syntax for existential type aliases. + # Drawbacks [drawbacks]: #drawbacks @@ -111,7 +165,7 @@ different. However, we believe that the parallel to the use of bounds elsewhere makes this new syntax immediately recognizable and understandable. # Rationale and alternatives -[alternatives]: #alternatives +[alternatives]: #rationale-and-alternatives As with any new surface syntax, one alternative is simply not introducing the syntax at all. That would still leave developers with the @@ -119,8 +173,71 @@ the syntax at all. That would still leave developers with the direct bounds syntax provides a better parallel to the use of bounds elsewhere. The introduced form in this RFC is comparatively both shorter and clearer. +### An alternative desugaring of bounds on associated types + +[RFC 2089]: https://github.com/rust-lang/rfcs/blob/master/text/2089-implied-bounds.md + +An alternative desugaring of the following definition: + +```rust +trait TraitA { + type AssocA: TraitB; +} +``` + +is to add the `where` clause, as specified above, to the trait, desugaring to: + +```rust +trait TraitA +where + ::AssocB: TraitC, +{ + type AssocA: TraitB; +} +``` + +However, at the time of this writing, a Rust compiler will treat this +differently than the desugaring proposed in the reference. +The following snippet illustrates the difference: + +```rust +trait Foo where ::Item: Copy { + type Bar: Iterator; +} + +trait Foo2 { + type Bar: Iterator; + type BarItem: Copy; +} + +fn use_foo(arg: X) +where ::Item: Copy +// ^-- Remove this line and it will error with: +// error[E0277]: `<::Bar as std::iter::Iterator>::Item` doesn't implement `Copy` +{ + let item: ::Item; +} + +fn use_foo2(arg: X) { + let item: ::Item; +} +``` + +The desugaring with a `where` therefore becomes problematic from a perspective +of usability. + +However, [RFC 2089, Implied Bounds][RFC 2089] specifies that desugaring to the +`where` clause in the trait will permit the `use_foo` function to omit its +`where` clause. This entails that both desugarings become equivalent from the +point of view of a user. The desugaring with `where` therefore becomes viable +in the presence of [RFC 2089]. + # Unresolved questions [unresolved]: #unresolved-questions -- Does allowing this for `dyn` trait objects introduce any unforseen issues? - This can be resolved during stabilization. \ No newline at end of file +- Does allowing this for `dyn` trait objects introduce any unforeseen issues? + This can be resolved during stabilization. + +- The exact desugaring in the context of putting bounds on an associated type + of a trait is left unresolved. The semantics should however be preserved. + This is also the case with other desugarings in this RFC.