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/0000-return-position-impl-trait-in-traits.md
+39-26Lines changed: 39 additions & 26 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -21,7 +21,7 @@ title: Return position `impl Trait` in traits
21
21
22
22
The `impl Trait` syntax is currently accepted in a variety of places within the Rust language to mean "some type that implements `Trait`" (for an overview, see the [explainer] from the impl trait initiative). For function arguments, `impl Trait` is [equivalent to a generic parameter][apit] and it is accepted in all kinds of functions (free functions, inherent impls, traits, and trait impls).
23
23
24
-
In return position, `impl Trait`[corresponds to an opaque type whose value is inferred][rpit]. In that role, it is currently accepted only in free functions and inherent impls. This RFC extends the support for return position `impl Trait` in functions in traits and trait impls.
24
+
In return position, `impl Trait`[corresponds to an opaque type whose value is inferred][rpit]. This is necessary for returning unnameable types, like those created by closures and `async` blocks, and also a convenient way to avoid naming complicated types like nested iterators. In return position, `impl Trait`is currently accepted only in free functions and inherent impls. This RFC extends the support to traits and trait impls.
Each `impl Trait` notation appearing in a trait impl fn return type is desugared to the same anonymous associated type `$` defined in the trait along with a function that returns it. The value of this associated type `$` is an `impl Trait`.
@@ -176,7 +170,7 @@ impl NewIntoIterator for Vec<u32> {
176
170
177
171
implNewIntoIteratorforVec<u32> {
178
172
typeItem=u32;
179
-
173
+
180
174
type$=implIterator<Item=Self::Item>;
181
175
182
176
fninto_iter(self) -> <SelfasNewIntoIterator>::$ {
@@ -203,14 +197,14 @@ We say that a generic parameter is *captured* if it may appear in the hidden typ
203
197
204
198
When desugaring, captured parameters from the method are reflected as generic parameters on the `$` associated type. Furthermore, the `$` associated type brings whatever where clauses are declared on the method into scope, excepting those which reference parameters that are not captured.
205
199
206
-
This transformation is precisely the same as the one which is applied to other forms of `-> impl Trait`, except that it applies to an associated type and not a top-level type alias.
200
+
This transformation is precisely the same as the one which is applied to other forms of `-> impl Trait`, except that it applies to an associated type and not a top-level type alias.
@@ -221,11 +215,11 @@ trait RefIterator for Vec<u32> {
221
215
222
216
traitRefIteratorforVec<u32> {
223
217
typeItem<'me>
224
-
where
218
+
where
225
219
Self: 'me;
226
220
227
221
type$<'a>:implIterator<Item=Self::Item<'a>>
228
-
where
222
+
where
229
223
Self: 'a; // Implied bound from fn
230
224
231
225
fniter<'a>(&'aself) ->Self::$<'a>;
@@ -249,7 +243,7 @@ where `T_0 + ... + T_m` are bounds, for any impl of that trait to be valid, the
249
243
* The impl must use `impl Trait` syntax to name the corresponding type, and
250
244
* The return type in the trait must implement all bounds `I_0 + ... + I_n` specified in the impl return type. (Taken with the first outer bullet point, we can say that the bounds in the trait and the bounds in the impl imply each other.)
251
245
252
-
[^refine]: `#[refine]` was added in [RFC 3245: Refined trait implementations](https://rust-lang.github.io/rfcs/3245-refined-impls.html). This feature is not yet stable.
246
+
[^refine]: `#[refine]` was added in [RFC 3245: Refined trait implementations](https://rust-lang.github.io/rfcs/3245-refined-impls.html). This feature is not yet stable. Examples in this RFC requiring the use of `#[refine]` will not work until that feature is stabilized.
253
247
254
248
Additionally, using `-> impl Trait` notation in an impl is only legal if the trait also uses that notation.
255
249
@@ -285,7 +279,7 @@ impl NewIntoIterator for Vec<u32> {
285
279
}
286
280
}
287
281
288
-
// Not OK:
282
+
// Not OK (requires `#[refine]`):
289
283
implNewIntoIteratorforVec<u32> {
290
284
typeItem=u32;
291
285
fninto_iter(self) ->std::vec::IntoIter<u32> {
@@ -301,25 +295,25 @@ This RFC modifies the “Static async fn in traits” RFC so that async fn in tr
301
295
```rust
302
296
traitTrait {
303
297
asyncfnasync_fn();
304
-
298
+
305
299
asyncfnasync_fn_refined();
306
300
}
307
301
308
302
implTraitforMyType {
309
303
fnasync_fn() ->implFuture<Output= ()> + '_ { .. }
310
-
304
+
311
305
#[refine]
312
306
fnasync_fn_refined() ->BoxFuture<'_, ()> { .. }
313
307
}
314
308
```
315
309
316
310
Similarly, the equivalent `-> impl Future` signature in a trait can be satisfied by using `async fn` in an impl of that trait.
317
311
318
-
## Nested impl traits
312
+
## Legal positions for `impl Trait` to appear
319
313
320
-
Similarly to return-position impl trait in free functions, return position impl trait in traits may be nested in associated types bounds.
314
+
`impl Trait` can appear in the return type of a trait method in all the same positions as it can in a free function.
321
315
322
-
Example:
316
+
For example, return position impl trait in traits may be nested in associated types bounds:
323
317
324
318
```rust
325
319
traitNested {
@@ -330,14 +324,31 @@ trait Nested {
330
324
331
325
traitNested {
332
326
type$1<'a>:Deref<Target=Self::$2> + 'a;
333
-
327
+
334
328
type$2:Display;
335
-
329
+
336
330
fnderef(&self) ->Self::$1<'_>;
337
331
}
338
332
```
339
333
340
-
But following the same rules as the allowed positions for return-position impl trait, they are not allowed to be nested in trait generics, such as:
334
+
It may also be used in type argument position of a generic type, including tuples:
335
+
336
+
```rust
337
+
traitFoo {
338
+
fnbar(&self) -> (implDebug, implDebug);
339
+
}
340
+
341
+
// This desugars into:
342
+
343
+
traitFoo {
344
+
type$1:Debug;
345
+
type$2:Debug;
346
+
347
+
fnbar(&self) -> (Self::$1, Self::$2);
348
+
}
349
+
```
350
+
351
+
But following the same rules as the allowed positions for return-position impl trait, it is not allowed to be nested in trait generics:
341
352
342
353
```rust
343
354
traitNested {
@@ -371,7 +382,7 @@ trait NewIntoIterator {
371
382
}
372
383
```
373
384
374
-
into
385
+
into
375
386
376
387
```rust
377
388
traitNewIntoIterator {
@@ -416,7 +427,9 @@ Not compatibly, no, because they would no longer have a named associated type. T
416
427
417
428
### Can traits migrate from `impl Trait` to a named associated type?
418
429
419
-
Generally yes, but all impls would have to be rewritten to include the definition of the associated type. In many cases, some form of type-alias impl trait (or impl trait in associated type values) would also be required. For example, if we changed the `IntoIntIterator` trait from the motivation to use an explicit associated type..
430
+
Generally yes, but all impls would have to be rewritten to include the definition of the associated type. In many cases, some form of type-alias impl trait (or impl trait in associated type values) would also be required.
431
+
432
+
For example, if we changed the `IntoIntIterator` trait from the motivation to use an explicit associated type..
420
433
421
434
```rust
422
435
traitIntoIntIterator {
@@ -505,7 +518,7 @@ There are a number of crates that do desugaring like this manually or with proce
505
518
506
519
### Namingreturn types
507
520
508
-
ThisRFC does not include a way for generic code to name or bound the result of `->implTrait` return types.This means, for example, that for the `IntoIntIterator` trait introduced in the motivation, it is not possible to write a function that takes a `T:IntoIntIterator` which returns an `ExactLenIterator`; forasyncfunctions, themostcommontimethiscomesupiscodethatwishestotakeanasyncfunctionthatreturnsa `Send` future.WeexpectfutureRFCswilladdresstheseuse cases.
521
+
ThisRFC does not include a way for generic code to name or bound the result of `->implTrait` return types.This means, for example, that for the `IntoIntIterator` trait introduced in the motivation, it is not possible to write a function that takes a `T:IntoIntIterator` which returns an `ExactLenIterator`; forasyncfunctions, themostcommontimethiscomesupiscodethatwishestotakeanasyncfunctionthatreturnsa `Send` future.WeexpectfutureRFCswilladdresstheseuse cases.
0 commit comments