Skip to content

Commit 78e071e

Browse files
committed
Respond to review comments
1 parent 7f1f9f1 commit 78e071e

File tree

1 file changed

+39
-26
lines changed

1 file changed

+39
-26
lines changed

text/0000-return-position-impl-trait-in-traits.md

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ title: Return position `impl Trait` in traits
2121

2222
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).
2323

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.
2525

2626
[explainer]: https://rust-lang.github.io/impl-trait-initiative/explainer.html
2727
[apit]: https://rust-lang.github.io/impl-trait-initiative/explainer/apit.html
@@ -84,7 +84,7 @@ impl IntoIntIterator for Vec<u32> {
8484
fn into_int_iter(self) -> impl Iterator<Item = u32> + ExactSizeIterator {
8585
self.into_iter()
8686
}
87-
87+
8888
// ..or even..
8989

9090
#[refine]
@@ -153,12 +153,6 @@ trait NewIntoIterator {
153153
}
154154
```
155155

156-
```rust
157-
trait SomeTrait {
158-
fn method<P0, ..., Pm>()
159-
}
160-
```
161-
162156
## Equivalent desugaring for trait impls
163157

164158
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> {
176170

177171
impl NewIntoIterator for Vec<u32> {
178172
type Item = u32;
179-
173+
180174
type $ = impl Iterator<Item = Self::Item>;
181175

182176
fn into_iter(self) -> <Self as NewIntoIterator>::$ {
@@ -203,14 +197,14 @@ We say that a generic parameter is *captured* if it may appear in the hidden typ
203197

204198
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.
205199

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.
207201

208202
Example:
209203

210204
```rust
211205
trait RefIterator for Vec<u32> {
212206
type Item<'me>
213-
where
207+
where
214208
Self: 'me;
215209

216210
fn iter<'a>(&'a self) -> impl Iterator<Item = Self:Item<'a>>;
@@ -221,11 +215,11 @@ trait RefIterator for Vec<u32> {
221215

222216
trait RefIterator for Vec<u32> {
223217
type Item<'me>
224-
where
218+
where
225219
Self: 'me;
226220

227221
type $<'a>: impl Iterator<Item = Self::Item<'a>>
228-
where
222+
where
229223
Self: 'a; // Implied bound from fn
230224

231225
fn iter<'a>(&'a self) -> Self::$<'a>;
@@ -249,7 +243,7 @@ where `T_0 + ... + T_m` are bounds, for any impl of that trait to be valid, the
249243
* The impl must use `impl Trait` syntax to name the corresponding type, and
250244
* 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.)
251245

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.
253247

254248
Additionally, using `-> impl Trait` notation in an impl is only legal if the trait also uses that notation.
255249

@@ -285,7 +279,7 @@ impl NewIntoIterator for Vec<u32> {
285279
}
286280
}
287281

288-
// Not OK:
282+
// Not OK (requires `#[refine]`):
289283
impl NewIntoIterator for Vec<u32> {
290284
type Item = u32;
291285
fn into_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
301295
```rust
302296
trait Trait {
303297
async fn async_fn();
304-
298+
305299
async fn async_fn_refined();
306300
}
307301

308302
impl Trait for MyType {
309303
fn async_fn() -> impl Future<Output = ()> + '_ { .. }
310-
304+
311305
#[refine]
312306
fn async_fn_refined() -> BoxFuture<'_, ()> { .. }
313307
}
314308
```
315309

316310
Similarly, the equivalent `-> impl Future` signature in a trait can be satisfied by using `async fn` in an impl of that trait.
317311

318-
## Nested impl traits
312+
## Legal positions for `impl Trait` to appear
319313

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.
321315

322-
Example:
316+
For example, return position impl trait in traits may be nested in associated types bounds:
323317

324318
```rust
325319
trait Nested {
@@ -330,14 +324,31 @@ trait Nested {
330324

331325
trait Nested {
332326
type $1<'a>: Deref<Target = Self::$2> + 'a;
333-
327+
334328
type $2: Display;
335-
329+
336330
fn deref(&self) -> Self::$1<'_>;
337331
}
338332
```
339333

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+
trait Foo {
338+
fn bar(&self) -> (impl Debug, impl Debug);
339+
}
340+
341+
// This desugars into:
342+
343+
trait Foo {
344+
type $1: Debug;
345+
type $2: Debug;
346+
347+
fn bar(&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:
341352

342353
``` rust
343354
trait Nested {
@@ -371,7 +382,7 @@ trait NewIntoIterator {
371382
}
372383
```
373384

374-
into
385+
into
375386

376387
```rust
377388
trait NewIntoIterator {
@@ -416,7 +427,9 @@ Not compatibly, no, because they would no longer have a named associated type. T
416427

417428
### Can traits migrate from `impl Trait` to a named associated type?
418429

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..
420433

421434
```rust
422435
trait IntoIntIterator {
@@ -505,7 +518,7 @@ There are a number of crates that do desugaring like this manually or with proce
505518

506519
### Naming return types
507520

508-
This RFC does not include a way for generic code to name or bound the result of `-> impl Trait` 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`; for async functions, the most common time this comes up is code that wishes to take an async function that returns a `Send` future. We expect future RFCs will address these use cases.
521+
This RFC does not include a way for generic code to name or bound the result of `-> impl Trait` 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`; for async functions, the most common time this comes up is code that wishes to take an async function that returns a `Send` future. We expect future RFCs will address these use cases.
509522

510523
### Dynamic dispatch
511524

0 commit comments

Comments
 (0)