Skip to content

Commit 3361d8a

Browse files
committed
Specify how auto trait leakage works
1 parent 78e071e commit 3361d8a

File tree

1 file changed

+44
-1
lines changed

1 file changed

+44
-1
lines changed

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

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,6 @@ impl NewIntoIterator for Vec<u32> {
179179
}
180180
```
181181

182-
183182
## Generic parameter capture and GATs
184183

185184
Given a trait method with a return type like `-> impl A + ... + Z` and an implementation of that trait, the hidden type for that implementation is allowed to reference:
@@ -239,6 +238,7 @@ trait Trait {
239238
where `T_0 + ... + T_m` are bounds, for any impl of that trait to be valid, the following conditions must hold:
240239

241240
* The return type named in the corresponding impl method must implement all bounds `T_0 + ... + T_m` specified in the trait.
241+
* This must be proven using only the information in the signature, with the exception that if the impl uses `impl Trait` syntax for the return type, the usual auto trait leakage rules apply.
242242
* Either the impl method must have `#[refine]`,[^refine] OR
243243
* The impl must use `impl Trait` syntax to name the corresponding type, and
244244
* 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.)
@@ -288,6 +288,49 @@ impl NewIntoIterator for Vec<u32> {
288288
}
289289
```
290290

291+
An interesting consequence of auto trait leakage is that a trait is allowed to specify an auto trait in its return type bounds, but the impl does not have to _repeat_ that auto trait in its signature, as long as its return type actually implements the required bound. For example:
292+
293+
```rust
294+
/// Converts `self` into an iterator that is always `Send`.
295+
trait IntoSendIterator {
296+
type Item;
297+
fn into_iter(self) -> impl Iterator<Item = Self::Item> + Send;
298+
}
299+
300+
// OK (signatures match exactly):
301+
impl IntoSendIterator for Vec<u32> {
302+
type Item = u32;
303+
fn into_iter(self) -> impl Iterator<Item = u32> + Send {
304+
self.into_iter()
305+
}
306+
}
307+
308+
// OK (auto traits leak, so adding `+ Send` here is NOT required):
309+
impl IntoSendIterator for Vec<u32> {
310+
type Item = u32;
311+
fn into_iter(self) -> impl Iterator<Item = u32> {
312+
self.into_iter()
313+
}
314+
}
315+
316+
// OK:
317+
impl<T: Send> IntoSendIterator for Vec<T> {
318+
// ^^^^ Required for our iterator to be Send!
319+
type Item = T;
320+
fn into_iter(self) -> impl Iterator<Item = T> {
321+
self.into_iter()
322+
}
323+
}
324+
325+
// Not OK (returned iterator is not known to be `Send`):
326+
impl<T> IntoSendIterator for Vec<T> {
327+
type Item = T;
328+
fn into_iter(self) -> impl Iterator<Item = T> {
329+
self.into_iter()
330+
}
331+
}
332+
```
333+
291334
### Interaction with `async fn` in trait
292335

293336
This RFC modifies the “Static async fn in traits” RFC so that async fn in traits may be satisfied by implementations that return `impl Future<Output = ...>` as long as the return-position impl trait type matches the async fn's desugared impl trait with the same rules as above.

0 commit comments

Comments
 (0)