Skip to content

Commit d2603ab

Browse files
Add words about associated type bounds
1 parent f03d3b9 commit d2603ab

File tree

1 file changed

+41
-26
lines changed

1 file changed

+41
-26
lines changed

text/3437-implementable-trait-alias.md

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,8 @@ The rule of thumb is: if you can copy everything between the `=` and `;` of a tr
189189

190190
# Reference-level explanation
191191

192+
## Implementability rules
193+
192194
A trait alias has the following syntax (using the Rust Reference's notation):
193195

194196
> [Visibility](https://doc.rust-lang.org/stable/reference/visibility-and-privacy.html)<sup>?</sup> `trait` [IDENTIFIER](https://doc.rust-lang.org/stable/reference/identifiers.html) [GenericParams](https://doc.rust-lang.org/stable/reference/items/generics.html)<sup>?</sup> `=` [TypeParamBounds](https://doc.rust-lang.org/stable/reference/trait-bounds.html)<sup>?</sup> [WhereClause](https://doc.rust-lang.org/stable/reference/items/generics.html#where-clauses)<sup>?</sup> `;`
@@ -199,7 +201,22 @@ Implementable trait aliases must follow a more restrictive form:
199201

200202
> [Visibility](https://doc.rust-lang.org/stable/reference/visibility-and-privacy.html)<sup>?</sup> `trait` [IDENTIFIER](https://doc.rust-lang.org/stable/reference/identifiers.html) [GenericParams](https://doc.rust-lang.org/stable/reference/items/generics.html)<sup>?</sup> `=` [TypePath](https://doc.rust-lang.org/stable/reference/paths.html#paths-in-types) [WhereClause](https://doc.rust-lang.org/stable/reference/items/generics.html#where-clauses)<sup>?</sup> `;`
201203
202-
For example, `trait Foo<T> = PartialEq<T> where Self: Sync;` is a valid implementable alias. The `=` must be followed by a single trait (or implementable trait alias), and then some number of where clauses.
204+
For example, `trait Foo<T> = PartialEq<T> where Self: Sync;` is a valid implementable alias. The `=` must be followed by a single trait (or implementable trait alias), and then some number of where clauses. The trait's generic parameter list may contain associated type constraints (for example `trait IntIterator = Iterator<Item = u32>`).
205+
206+
There is another restriction that trait aliases must adhere to in order to be implementable: all generic parameters of the alias itself must be used as generic parameters of the alias's primary trait.
207+
208+
```rust
209+
// Implementable
210+
trait Foo<T> = PartialEq<T>;
211+
212+
// Not implementable
213+
trait Foo<T> = Copy;
214+
trait Foo<T> = Copy where T: Send;
215+
trait Foo<T> = Iterator<Item = T>;
216+
trait Foo<T> = Copy where Self: PartialEq<T>;
217+
```
218+
219+
## Usage in `impl` blocks
203220

204221
An impl block for a trait alias looks just like an impl block for the underlying trait. The alias's where clauses are treated as if they had been written out in the `impl` header.
205222

@@ -223,27 +240,14 @@ impl !Send for Bar;
223240
// impl IntIterator for Bar { /* ... */ }
224241
```
225242

226-
There is another restriction that trait aliases must adhere to in order to be implementable: all generic parameters of the alias itself must be used as generic parameters of the alias's primary trait.
227-
228-
```rust
229-
// Implementable
230-
trait Foo<T> = PartialEq<T>;
231-
232-
// Not implementable
233-
trait Foo<T> = Copy;
234-
trait Foo<T> = Copy where T: Send;
235-
trait Foo<T> = Iterator<Item = T>;
236-
trait Foo<T> = Copy where Self: PartialEq<T>;
237-
```
238-
239-
Bounds on such generic parameters are enforced at the `impl` site.
243+
Bounds on generic parameters are also enforced at the `impl` site.
240244

241245
```rust
242246
trait Underlying<T> {}
243247

244248
trait Alias<T: Send> = Underlying<T>;
245249

246-
impl<T> Alias<T> for i32 {} // Error: missing `T: Send` bound
250+
impl Alias<*const i32> for i32 {} // Error: `*const i32` is not `Send`
247251
```
248252

249253
If the trait alias uniquely constrains a portion of the `impl` block, that part can be omitted.
@@ -297,21 +301,32 @@ impl Frobber for MyType {
297301

298302
Trait aliases are `unsafe` to implement iff the underlying trait is marked `unsafe`.
299303

304+
## Usage in paths
305+
300306
Implementable trait aliases can also be used with trait-qualified and fully-qualified method call syntax, as well as in paths more generally. When used this way, they are treated equivalently to the underlying primary trait, with the additional restriction that all `where` clauses and type parameter/associated type bounds must be satisfied.
301307

302308
```rust
303309
trait IntIter = Iterator<Item = u32> where Self: Clone;
304310

305-
fn foo() {
306-
let iter = [1_u32].into_iter();
307-
let _: IntIter::Item = IntIter::next(&mut iter); // works
308-
let _: <std::array::IntoIter as IntIter>::Item = <std::array::IntoIter as IntIter>::next(); // works
309-
//IntIter::clone(&iter); // ERROR: trait `Iterator` has no method named `clone()`
310-
let dyn_iter: &mut dyn Iterator<Item = u32> = &mut iter;
311-
//IntIter::next(dyn_iter); // ERROR: `dyn Iterator<Item = u32>` does not implement `Clone`
312-
let signed_iter = [1_i32].into_iter();
313-
//IntIter::next(&mut signed_iter); // ERROR: Expected `<Self as Iterator>::Item` to be `u32`, it is `i32`
314-
}
311+
let iter = [1_u32].into_iter();
312+
let _: IntIter::Item = IntIter::next(&mut iter); // works
313+
let _: <std::array::IntoIter as IntIter>::Item = <std::array::IntoIter as IntIter>::next(); // works
314+
//IntIter::clone(&iter); // ERROR: trait `Iterator` has no method named `clone()`
315+
let dyn_iter: &mut dyn Iterator<Item = u32> = &mut iter;
316+
//IntIter::next(dyn_iter); // ERROR: `dyn Iterator<Item = u32>` does not implement `Clone`
317+
let signed_iter = [1_i32].into_iter();
318+
//IntIter::next(&mut signed_iter); // ERROR: Expected `<Self as Iterator>::Item` to be `u32`, it is `i32`
319+
```
320+
321+
Implementable trait aliases can also be used with associated type bounds; the associated type must belong to the alias's primary trait.
322+
323+
```rust
324+
trait IteratorAlias = Iterator;
325+
let _: IteratorAlias<Item = u32> = [1_u32].into_iter();
326+
327+
trait IntIter = Iterator<Item = u32> where Self: Clone;
328+
let _: IntIter<Item = u32> = [1_u32].into_iter(); // `Item = u32` is redundant, but allowed
329+
//let _: IntIter<Item = f64> = [1.0_f64].into_iter(); // ERROR: `Item = f64` conflicts with `Item = u32`
315330
```
316331

317332
# Drawbacks

0 commit comments

Comments
 (0)