| 
 | 1 | +- Feature Name: `associated_type_bounds`  | 
 | 2 | +- Start Date: 2018-01-13  | 
 | 3 | +- RFC PR: [rust-lang/rfcs#2289](https://github.com/rust-lang/rfcs/pull/2289)  | 
 | 4 | +- Rust Issue: [rust-lang/rust#52662](https://github.com/rust-lang/rust/issues/52662)  | 
 | 5 | + | 
 | 6 | +# Summary  | 
 | 7 | +[summary]: #summary  | 
 | 8 | + | 
 | 9 | +Introduce the bound form `MyTrait<AssociatedType: Bounds>`, permitted anywhere  | 
 | 10 | +a bound of the form `MyTrait<AssociatedType = T>` would be allowed. The bound  | 
 | 11 | +`T: Trait<AssociatedType: Bounds>` desugars to the bounds `T: Trait` and  | 
 | 12 | +`<T as Trait>::AssociatedType: Bounds`.  | 
 | 13 | +See the [reference][reference-level-explanation] and [rationale][alternatives]  | 
 | 14 | +for exact details.  | 
 | 15 | + | 
 | 16 | +# Motivation  | 
 | 17 | +[motivation]: #motivation  | 
 | 18 | + | 
 | 19 | +Currently, when specifying a bound using a trait that has an associated  | 
 | 20 | +type, the developer can specify the precise type via the syntax  | 
 | 21 | +`MyTrait<AssociatedType = T>`. With the introduction of the `impl Trait`  | 
 | 22 | +syntax for static-dispatch existential types, this syntax also permits  | 
 | 23 | +`MyTrait<AssociatedType = impl Bounds>`, as a shorthand for introducing a  | 
 | 24 | +new type variable and specifying those bounds.  | 
 | 25 | + | 
 | 26 | +However, this introduces an unnecessary level of indirection that does not  | 
 | 27 | +match the developer's intuition and mental model as well as it could. In  | 
 | 28 | +particular, given the ability to write bounds on a type variable as `T: Bounds`,  | 
 | 29 | +it makes sense to permit writing bounds on an associated type directly.  | 
 | 30 | +This results in the simpler syntax `MyTrait<AssociatedType: Bounds>`.  | 
 | 31 | + | 
 | 32 | +# Guide-level explanation  | 
 | 33 | +[guide-level-explanation]: #guide-level-explanation  | 
 | 34 | + | 
 | 35 | +Instead of specifying a concrete type for an associated type, we can  | 
 | 36 | +specify a bound on the associated type, to ensure that it implements  | 
 | 37 | +specific traits, as seen in the example below:  | 
 | 38 | + | 
 | 39 | +```rust  | 
 | 40 | +fn print_all<T: Iterator<Item: Display>>(printables: T) {  | 
 | 41 | +    for p in printables {  | 
 | 42 | +        println!("{}", p);  | 
 | 43 | +    }  | 
 | 44 | +}  | 
 | 45 | +```  | 
 | 46 | + | 
 | 47 | +## In anonymous existential types  | 
 | 48 | + | 
 | 49 | +```rust  | 
 | 50 | +fn printables() -> impl Iterator<Item: Display> {  | 
 | 51 | +    // ..  | 
 | 52 | +}  | 
 | 53 | +```  | 
 | 54 | + | 
 | 55 | +## Further examples  | 
 | 56 | + | 
 | 57 | +Instead of writing:  | 
 | 58 | + | 
 | 59 | +```rust  | 
 | 60 | +impl<I> Clone for Peekable<I>  | 
 | 61 | +where  | 
 | 62 | +    I: Clone + Iterator,  | 
 | 63 | +    <I as Iterator>::Item: Clone,  | 
 | 64 | +{  | 
 | 65 | +    // ..  | 
 | 66 | +}  | 
 | 67 | +```  | 
 | 68 | + | 
 | 69 | +you may write:  | 
 | 70 | + | 
 | 71 | +```rust  | 
 | 72 | +impl<I> Clone for Peekable<I>  | 
 | 73 | +where  | 
 | 74 | +    I: Clone + Iterator<Item: Clone>  | 
 | 75 | +{  | 
 | 76 | +    // ..  | 
 | 77 | +}  | 
 | 78 | +```  | 
 | 79 | + | 
 | 80 | +or replace the `where` clause entirely:  | 
 | 81 | + | 
 | 82 | +```rust  | 
 | 83 | +impl<I: Clone + Iterator<Item: Clone>> Clone for Peekable<I> {  | 
 | 84 | +    // ..  | 
 | 85 | +}  | 
 | 86 | +```  | 
 | 87 | + | 
 | 88 | +# Reference-level explanation  | 
 | 89 | +[reference-level-explanation]: #reference-level-explanation  | 
 | 90 | + | 
 | 91 | +The surface syntax `T: Trait<AssociatedType: Bounds>` should desugar to a pair  | 
 | 92 | +of bounds: `T: Trait` and `<T as Trait>::AssociatedType: Bounds`.  | 
 | 93 | +Rust currently allows both of those bounds anywhere a bound can currently appear;  | 
 | 94 | +the new syntax does not introduce any new semantics.  | 
 | 95 | + | 
 | 96 | +Additionally, the surface syntax `impl Trait<AssociatedType: Bounds>` turns  | 
 | 97 | +into a named type variable `T`, universal or existential depending on context,  | 
 | 98 | +with the usual bound `T: Trait` along with the added bound  | 
 | 99 | +`<T as Trait>::AssociatedType: Bounds`.  | 
 | 100 | + | 
 | 101 | +Meanwhile, the surface syntax `dyn Trait<AssociatedType: Bounds>` desugars into  | 
 | 102 | +`dyn Trait<AssociatedType = T>` where `T` is a named type variable `T` with the  | 
 | 103 | +bound `T: Bounds`.  | 
 | 104 | + | 
 | 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 | + | 
 | 157 | +# Drawbacks  | 
 | 158 | +[drawbacks]: #drawbacks  | 
 | 159 | + | 
 | 160 | +Rust code can already express this using the desugared form. This proposal  | 
 | 161 | +just introduces a simpler surface syntax that parallels other uses of bounds.  | 
 | 162 | +As always, when introducing new syntactic forms, an increased burden is put on  | 
 | 163 | +developers to know about and understand those forms, and this proposal is no  | 
 | 164 | +different. However, we believe that the parallel to the use of bounds elsewhere  | 
 | 165 | +makes this new syntax immediately recognizable and understandable.  | 
 | 166 | + | 
 | 167 | +# Rationale and alternatives  | 
 | 168 | +[alternatives]: #rationale-and-alternatives  | 
 | 169 | + | 
 | 170 | +As with any new surface syntax, one alternative is simply not introducing  | 
 | 171 | +the syntax at all. That would still leave developers with the  | 
 | 172 | +`MyTrait<AssociatedType = impl Bounds>` form. However, allowing the more  | 
 | 173 | +direct bounds syntax provides a better parallel to the use of bounds elsewhere.  | 
 | 174 | +The introduced form in this RFC is comparatively both shorter and clearer.  | 
 | 175 | + | 
 | 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 | + | 
 | 235 | +# Unresolved questions  | 
 | 236 | +[unresolved]: #unresolved-questions  | 
 | 237 | + | 
 | 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