You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: text/3245-refined-impls.md
+90-2Lines changed: 90 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -194,7 +194,7 @@ Because we allow writing impls that look refined, but are [not usable][not-usabl
194
194
195
195
### Lint against unmarked refined impls
196
196
197
-
After this RFC is merged, we should warn when a user writes an impl that looks refined and suggest that they copy the exact API of the trait they are implementing. Once this feature stabilizes, we can should add and suggest using `#[refine]` attribute to mark that an impl is intentionally refined.
197
+
After this RFC is merged, we should warn when a user writes an impl that looks refined and suggest that they copy the exact API of the trait they are implementing. Once this feature stabilizes, we can suggest using `#[refine]` attribute to mark that an impl is intentionally refined.
198
198
199
199
### Automatic migration for the next edition
200
200
@@ -275,6 +275,17 @@ It is possible for a user to form an impression of a trait API by seeing its use
275
275
276
276
It'srarelyobvious, however, thata*trait*APIisbeingusedatacallsiteasopposedtoaninherentAPI (whichcanbecompletelydifferentfromonetypetothenext).Theoneplaceitisobviousisingenericfunctions, whichwilltypicallyonlyhaveaccesstotheoriginaltraitAPI.
Insomesituationstheusermayrealizetheyarerelyingontoomanydetailsoftheconcretetypeandeitherdon'twanttomaketheircodegeneric, orneedtorefactorittobemoregeneral.Inothersituations, however, theymaywanttoaddextraboundssotheircodecanbegenericwithoutsignificantmodifications.
With refinement impls, we can say that this desugaring is equivalent because return position impl trait would give the exact same flexibility as associated types.
380
+
With refinement impls, we can say that this desugaring is equivalent because return position impl trait would give the same flexibility to implementers as associated types.
381
+
382
+
## Bounding refined items
383
+
[Bounding refined items]: #bounding-refined-items
384
+
385
+
As described in the [Refactoring] drawbacks section, when making existing code generic a user may run into dependence on refined aspects of a concrete type not specified in the trait itself. In this case the user may want to add additional bounds so they can make their code generic without significant modifications.
386
+
387
+
This problem already exists for associated types, but bounds can be added for those. This implies a couple of ways to solve this problem.
388
+
389
+
### New kinds of bounds
390
+
391
+
We can make it possible to add bounds on all refine-able aspects of a trait API.
392
+
393
+
It is already likely we will want to allow bounding the return type of methods:
394
+
395
+
```rust
396
+
traitTrait {
397
+
fnfoo() ->implClone;
398
+
}
399
+
400
+
fntake_foo<T:Foo>(_:T) whereT::foo:Copy { ... }
401
+
```
402
+
403
+
The need for this arises both in `async` (e.g. needing to bound a future return type by `Send`) and in cases like `-> impl Iterator` where additional properties are required. A mechanism for supplying these bounds could possibly be extended to bounding what _argument_ types a method accepts.
404
+
405
+
There is no way to bound the type of a const today. It is possible one could be added, but since consts will only allow subtype refinement (i.e. a type with a longer lifetime than required by the trait) it is unlikely that this situation will come up often in practice.
406
+
407
+
### Falling back to associated types
408
+
409
+
As mentioned above, associated types can have bounds, either on their exact value or with other traits:
410
+
411
+
```rust
412
+
fnfoo<T:Iterator<Item=u32>>(_:T) { ... }
413
+
fnbar<T:Iterator>(_:T) whereT::Item:Clone { ... }
414
+
```
415
+
416
+
Because associated types are the most flexible option **we may want to make it possible to add associated types to a trait backward-compatibly**. For example, given the following trait:
417
+
418
+
```rust
419
+
traitTrait {
420
+
fnfoo() ->implClone;
421
+
}
422
+
```
423
+
424
+
we want to be able to refactor to something like this:
425
+
426
+
```rust
427
+
traitTrait {
428
+
typeFoo:Clone;
429
+
fnfoo() ->Self::Foo;
430
+
}
431
+
```
432
+
433
+
There are least a couple of things needed for this:
434
+
435
+
1. Don't require implementations to specify associated type values when they can be inferred. For example:
436
+
```rust
437
+
traitTrait {
438
+
typeFoo;
439
+
fnfoo() ->Foo;
440
+
}
441
+
442
+
implTraitfor () {
443
+
fnfoo() ->usize;
444
+
// `type Foo = usize;` is not needed,
445
+
// since it can be inferred from the above.
446
+
}
447
+
```
448
+
1. Allow adding associated types without breaking existing usages of `dyn`. For example, let's say we had support for return-position `impl Trait` with dynamic dispatch. With [associated type defaults] and type alias `impl Trait`, you could write:
449
+
```rust
450
+
traitTrait {
451
+
typeFoo:Clone=implClone;
452
+
fnfoo() ->Foo;
453
+
}
454
+
```
455
+
and allow `dyn Trait` to mean `dyn Trait<Foo = impl Clone>`.
456
+
457
+
[associated type defaults]: https://github.com/rust-lang/rust/issues/29661
0 commit comments