owned this note
owned this note
Published
Linked with GitHub
---
title: RPITIT capture rules
url: https://hackmd.io/zgairrYRSACgTeZHP1x0Zg
---
# Introduction
This document lays out 5 motivating examples for combinations of RPITIT hidden types that we may want to support, and 5 different sets of capture rules.
# Background facts
## Refresher on the `Captures` trick
Consider the following trait definition.
```rust
trait Trait<'s, 't, Assoc> {
// ^^^^^
// ^ If we want to be explicit about the bounds of
// this generic parameter, what might go here?
fn foo(s: &'s (), t: &'t ()) -> Assoc;
// ^^^^^
// ^ The return type will contain the
// input lifetimes.
}
struct Foo<'s, 't>(*mut &'s (), *mut &'t ());
// ^^^^^^^^^^^^^^^^^^^^^^^^
// ^ We're using invariant lifetimes to help
// demonstrate the nature of the problem.
impl<'s, 't> Trait<'s, 't, Foo<'s, 't>> for () {
fn foo(mut s: &'s (), mut t: &'t ()) -> Foo<'s, 't> {
Foo(std::ptr::addr_of_mut!(s), std::ptr::addr_of_mut!(t))
}
}
```
[Playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=trait+Trait%3C%27s%2C+%27t%2C+Assoc%3E+%7B%0A++++%2F%2F++++++++++++++%5E%5E%5E%5E%5E%0A++++%2F%2F++++++++++++++%5E+If+we+want+to+be+explicit+about+the+bounds+of%0A++++%2F%2F++++++++++++++this+generic+parameter%2C+what+might+go+here%3F%0A++++fn+foo%28s%3A+%26%27s+%28%29%2C+t%3A+%26%27t+%28%29%29+-%3E+Assoc%3B%0A++++%2F%2F++++++++++++++++++++++++++++++%5E%5E%5E%5E%5E%0A++++%2F%2F++++++++++++++++++++++++++++++%5E+The+return+type+will+contain+the%0A++++%2F%2F++++++++++++++++++++++++++++++input+lifetimes.%0A%7D%0A%0Astruct+Foo%3C%27s%2C+%27t%3E%28%2Amut+%26%27s+%28%29%2C+%2Amut+%26%27t+%28%29%29%3B%0A%2F%2F+++++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A%2F%2F+++++++++++++++++%5E+We%27re+using+invariant+lifetimes+to+help%0A%2F%2F+++++++++++++++++demonstrate+the+nature+of+the+problem.%0Aimpl%3C%27s%2C+%27t%3E+Trait%3C%27s%2C+%27t%2C+Foo%3C%27s%2C+%27t%3E%3E+for+%28%29+%7B%0A++++fn+foo%28mut+s%3A+%26%27s+%28%29%2C+mut+t%3A+%26%27t+%28%29%29+-%3E+Foo%3C%27s%2C+%27t%3E+%7B%0A++++++++Foo%28std%3A%3Aptr%3A%3Aaddr_of_mut%21%28s%29%2C+std%3A%3Aptr%3A%3Aaddr_of_mut%21%28t%29%29%0A++++%7D%0A%7D%0A)
We're expecting that the return type of `foo` will contain the lifetimes `'s` and `'t`. If we want to express that explicitly as a bound on `Assoc`, how would we do that? We might think to write:
```rust
trait Trait<'s, 't, Assoc: 's + 't> {
// ^^^^^^^
// ^ This is wrong.
fn foo(s: &'s (), t: &'t ()) -> Assoc;
}
struct Foo<'s, 't>(*mut &'s (), *mut &'t ());
impl<'s, 't> Trait<'s, 't, Foo<'s, 't>> for () {
// ^^^^^^^^^^^^^^^^^^^^^^^^^^
// ^ Error: lifetime bound not satisfied.
fn foo(mut s: &'s (), mut t: &'t ()) -> Foo<'s, 't> {
Foo(std::ptr::addr_of_mut!(s), std::ptr::addr_of_mut!(t))
}
}
```
[Playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=trait+Trait%3C%27s%2C+%27t%2C+Assoc%3A+%27s+%2B+%27t%3E+%7B%0A++++%2F%2F+++++++++++++++++++++%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++++++++++++++++++++%5E+This+is+wrong.%0A++++fn+foo%28s%3A+%26%27s+%28%29%2C+t%3A+%26%27t+%28%29%29+-%3E+Assoc%3B%0A%7D%0A%0Astruct+Foo%3C%27s%2C+%27t%3E%28%2Amut+%26%27s+%28%29%2C+%2Amut+%26%27t+%28%29%29%3B%0Aimpl%3C%27s%2C+%27t%3E+Trait%3C%27s%2C+%27t%2C+Foo%3C%27s%2C+%27t%3E%3E+for+%28%29+%7B%0A++++%2F%2F+++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++++++%5E+Error%3A+lifetime+bound+not+satisfied.%0A++++fn+foo%28mut+s%3A+%26%27s+%28%29%2C+mut+t%3A+%26%27t+%28%29%29+-%3E+Foo%3C%27s%2C+%27t%3E+%7B%0A++++++++Foo%28std%3A%3Aptr%3A%3Aaddr_of_mut%21%28s%29%2C+std%3A%3Aptr%3A%3Aaddr_of_mut%21%28t%29%29%0A++++%7D%0A%7D%0A)
But that is wrong. If `Assoc` is to contain the lifetimes `'s` and `'t`, then those lifetimes must outlive `Assoc`, not the other way around. What we really want to say is this:
```rust
trait Trait<'s, 't, Assoc> where 's: Assoc, 't: Assoc {
// ^^^^^^^^^^^^^^^^^^^^
// ^ This is illegal.
fn foo(s: &'s (), t: &'t ()) -> Assoc;
}
```
But that's not legal in Rust today. So what we say instead is:
```rust
trait Captures2<'c1, 'c2>: Sized {}
impl<'c1, 'c2, T> Captures2<'c1, 'c2> for T {}
trait Trait<'s, 't, Assoc: Captures2<'s, 't>> {
// ^^^^^^^^^^^^^^^^^
// ^ This asserts that 's and 't must outlive
// Assoc.
fn foo(s: &'s (), t: &'t ()) -> Assoc;
}
struct Foo<'s, 't>(*mut &'s (), *mut &'t ());
impl<'s, 't> Trait<'s, 't, Foo<'s, 't>> for () {
fn foo(mut s: &'s (), mut t: &'t ()) -> Foo<'s, 't> {
Foo(std::ptr::addr_of_mut!(s), std::ptr::addr_of_mut!(t))
}
}
```
[Playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=trait+Captures2%3C%27c1%2C+%27c2%3E%3A+Sized+%7B%7D%0Aimpl%3C%27c1%2C+%27c2%2C+T%3E+Captures2%3C%27c1%2C+%27c2%3E+for+T+%7B%7D%0A%0Atrait+Trait%3C%27s%2C+%27t%2C+Assoc%3A+Captures2%3C%27s%2C+%27t%3E%3E+%7B%0A++++%2F%2F+++++++++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++++++++++++++++++++%5E+This+asserts+that+%27s+and+%27t+must+outlive%0A++++%2F%2F+++++++++++++++++++++Assoc.%0A++++fn+foo%28s%3A+%26%27s+%28%29%2C+t%3A+%26%27t+%28%29%29+-%3E+Assoc%3B%0A%7D%0A%0Astruct+Foo%3C%27s%2C+%27t%3E%28%2Amut+%26%27s+%28%29%2C+%2Amut+%26%27t+%28%29%29%3B%0Aimpl%3C%27s%2C+%27t%3E+Trait%3C%27s%2C+%27t%2C+Foo%3C%27s%2C+%27t%3E%3E+for+%28%29+%7B%0A++++fn+foo%28mut+s%3A+%26%27s+%28%29%2C+mut+t%3A+%26%27t+%28%29%29+-%3E+Foo%3C%27s%2C+%27t%3E+%7B%0A++++++++Foo%28std%3A%3Aptr%3A%3Aaddr_of_mut%21%28s%29%2C+std%3A%3Aptr%3A%3Aaddr_of_mut%21%28t%29%29%0A++++%7D%0A%7D%0A)
This is called the `Captures` trick. It asserts that the lifetimes must outlive the type parameter, which is the semantic that we want. It may be applied to generic parameters, associated types, GATs, and to the opaque types in TAIT, ATPIT, and RPITIT.
## Generic type parameter lifetime rules (no bounds required in the trait)
The impl of a trait for a type can substitute, for any generic parameter of the trait, a type that includes any lifetime that is in scope (within the impl) without an explicit bound on the generic parameter in the trait definition.
```rust
trait Trait<'t, Assoc> {
// ^^^^^
// ^ No lifetime bounds required even though the impl
// below substitutes a type for this generic parameter
// that contains lifetimes.
//
// That is, we did not have to say:
//
// Assoc: Captures2<'Self, `t>
fn foo(self, t: &'t ()) -> Assoc;
}
struct Foo<'s, 't>(&'s (), &'t ());
impl<'s, 't> Trait<'t, Foo<'s, 't>> for &'s () {
// ^^^^^^^^^^^
// ^ Lifetimes not included in bounds of generic
// are nonetheless part of the type substituted
// for the generic parameter here.
fn foo(self, t: &'t ()) -> Foo<'s, 't> {
Foo(self, t)
}
}
```
[Playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=trait+Trait%3C%27t%2C+Assoc%3E+%7B%0A++++%2F%2F++++++++++%5E%5E%5E%5E%5E%0A++++%2F%2F++++++++++%5E+No+lifetime+bounds+required+even+though+the+impl%0A++++%2F%2F++++++++++below+substitutes+a+type+for+this+generic+parameter%0A++++%2F%2F++++++++++that+contains+lifetimes.%0A++++%2F%2F%0A++++%2F%2F++++++++++That+is%2C+we+did+not+have+to+say%3A%0A++++%2F%2F%0A++++%2F%2F++++++++++++++Assoc%3A+Captures2%3C%27Self%2C+%60t%3E%0A++++fn+foo%28self%2C+t%3A+%26%27t+%28%29%29+-%3E+Assoc%3B%0A%7D%0A%0Astruct+Foo%3C%27s%2C+%27t%3E%28%26%27s+%28%29%2C+%26%27t+%28%29%29%3B%0Aimpl%3C%27s%2C+%27t%3E+Trait%3C%27t%2C+Foo%3C%27s%2C+%27t%3E%3E+for+%26%27s+%28%29+%7B%0A++++%2F%2F+++++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++++++++++++++++%5E+Lifetimes+not+included+in+bounds+of+generic%0A++++%2F%2F+++++++++++++++++are+nonetheless+part+of+the+type+substituted%0A++++%2F%2F+++++++++++++++++for+the+generic+parameter+here.%0A++++fn+foo%28self%2C+t%3A+%26%27t+%28%29%29+-%3E+Foo%3C%27s%2C+%27t%3E+%7B%0A++++++++Foo%28self%2C+t%29%0A++++%7D%0A%7D%0A)
Note that explicit bounds on generic parameters do not risk *overcapturing*. For example:
```rust
trait Captures<'c>: Sized {}
impl<'c, T> Captures<'c> for T {}
trait Trait<'s, Assoc: Captures<'s>> {
// ^^^^^^^^^^^^^^^^^^^
// ^ The generic parameter has an explicit bound.
fn foo(self) -> Assoc;
}
impl<'s> Trait<'s, ()> for &'s () {
// ^^
// ^ But the substituted type does not use the
// lifetime.
fn foo(self) -> () { () }
}
fn is_static<T: 'static>(_t: T) {}
fn test<'a>(a: &'a ()) {
is_static(<&'a () as Trait<'a, ()>>::foo(a));
// ^^^^^^^^^
// ^ And that "refinement" can be seen and used.
}
```
[Playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=trait+Captures%3C%27c%3E%3A+Sized+%7B%7D%0Aimpl%3C%27c%2C+T%3E+Captures%3C%27c%3E+for+T+%7B%7D%0A%0Atrait+Trait%3C%27s%2C+Assoc%3A+Captures%3C%27s%3E%3E+%7B%0A++++%2F%2F++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F++++++++++%5E+The+generic+parameter+has+an+explicit+bound.%0A++++fn+foo%28self%29+-%3E+Assoc%3B%0A%7D%0A%0Aimpl%3C%27s%3E+Trait%3C%27s%2C+%28%29%3E+for+%26%27s+%28%29+%7B%0A++++%2F%2F+++++++++++++%5E%5E%0A++++%2F%2F+++++++++++++%5E+But+the+substituted+type+does+not+use+the%0A++++%2F%2F+++++++++++++lifetime.%0A++++fn+foo%28self%29+-%3E+%28%29+%7B+%28%29+%7D%0A%7D%0A%0Afn+is_static%3CT%3A+%27static%3E%28_t%3A+T%29+%7B%7D%0Afn+test%3C%27a%3E%28a%3A+%26%27a+%28%29%29+%7B%0A++++is_static%28%3C%26%27a+%28%29+as+Trait%3C%27a%2C+%28%29%3E%3E%3A%3Afoo%28a%29%29%3B%0A%2F%2F++%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A%2F%2F++%5E+And+that+%22refinement%22+can+be+seen+and+used.%0A%7D%0A)
That is, if an impl substitutes a type for the generic parameter that does not use a lifetime present in the bounds, callers of thy type's trait methods can observe and rely on that.
## Associated type / GAT lifetime rules (no bounds required in the trait)
The impl of a trait for a type can substitute, for any GAT of the trait, a type that includes any lifetime that is in scope (within the impl) without an explicit bound on the GAT in the trait definition.
```rust
trait Trait<'t> {
type Assoc<'g>;
// ^^^^^^^^^
// ^ No lifetime bounds required even though the impl below
// substitutes a type for this GAT that contains lifetimes.
//
// That is, we did not have to say:
//
// type Assoc<'g>: Captures3<'Self, `t, 'g>;
}
impl<'s, 't> Trait<'t> for &'s () {
type Assoc<'g> = (&'s (), &'t (), &'g ());
// ^^^^^^^^^^^^^^^^
// ^ Lifetimes not included in bounds of GAT are
// nonetheless part of the type substituted for the
// GAT here.
}
```
[Playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=trait+Trait%3C%27t%3E+%7B%0A++++type+Assoc%3C%27g%3E%3B%0A++++%2F%2F+++%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++%5E+No+lifetime+bounds+required+even+though+the+impl+below%0A++++%2F%2F+++substitutes+a+type+for+this+GAT+that+contains+lifetimes.%0A++++%2F%2F%0A++++%2F%2F+++That+is%2C+we+did+not+have+to+say%3A%0A++++%2F%2F%0A++++%2F%2F+++++++type+Assoc%3C%27g%3E%3A+Captures3%3C%27Self%2C+%60t%2C+%27g%3E%3B%0A%7D%0A%0Aimpl%3C%27s%2C+%27t%3E+Trait%3C%27t%3E+for+%26%27s+%28%29+%7B%0A++++type+Assoc%3C%27g%3E+%3D+%28%26%27s+%28%29%2C+%26%27t+%28%29%2C+%26%27g+%28%29%29%3B%0A++++%2F%2F+++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++++++++++++++%5E+Lifetimes+not+included+in+bounds+of+GAT+are%0A++++%2F%2F+++++++++++++++nonetheless+part+of+the+type+substituted+for+the%0A++++%2F%2F+++++++++++++++GAT+here.%0A%7D%0A)
Note that explicit bounds on GATs do not risk *overcapturing*. For example:
```rust
trait Captures2<'c1, 'c2>: Sized {}
impl<'c1, 'c2, T> Captures2<'c1, 'c2> for T {}
trait Trait<'t> {
type Assoc<'g>: Captures2<'t, 'g>;
// ^^^^^^^^^^^^
// ^ The GAT has an explicit lifetime bound.
}
impl<'s> Trait<'s> for &'s () {
type Assoc<'g> = ();
// ^^
// ^ But the substituted type does not use the
// lifetime.
}
fn is_static<T: 'static>() {}
fn test<'a>() {
is_static::<<&'a () as Trait<'a>>::Assoc<'_>>();
// ^^^^^^^^^
// ^ And that "refinement" can be seen and used.
}
```
[Playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=trait+Captures2%3C%27c1%2C+%27c2%3E%3A+Sized+%7B%7D%0Aimpl%3C%27c1%2C+%27c2%2C+T%3E+Captures2%3C%27c1%2C+%27c2%3E+for+T+%7B%7D%0A%0Atrait+Trait%3C%27t%3E+%7B%0A++++type+Assoc%3C%27g%3E%3A+Captures2%3C%27t%2C+%27g%3E%3B%0A++++%2F%2F++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F++++++++++%5E+The+GAT+has+an+explicit+lifetime+bound.%0A%7D%0A%0Aimpl%3C%27s%3E+Trait%3C%27s%3E+for+%26%27s+%28%29+%7B%0A++++type+Assoc%3C%27g%3E+%3D+%28%29%3B%0A++++%2F%2F+++++++++++++++%5E%5E%0A++++%2F%2F+++++++++++++++%5E+But+the+substituted+type+does+not+use+the%0A++++%2F%2F+++++++++++++++lifetime.%0A%7D%0A%0Afn+is_static%3CT%3A+%27static%3E%28%29+%7B%7D%0Afn+test%3C%27a%3E%28%29+%7B%0A++++is_static%3A%3A%3C%3C%26%27a+%28%29+as+Trait%3C%27a%3E%3E%3A%3AAssoc%3C%27_%3E%3E%28%29%3B%0A%2F%2F++%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A%2F%2F++%5E+And+that+%22refinement%22+can+be+seen+and+used.%0A%7D%0A)
That is, if an impl substitutes a type for the GAT that does not use a lifetime present in the bounds, users of the GAT can observe and rely on that.
#### Other examples
<p><details>
<summary>Show</summary>
##### Other examples
```rust
trait Trait<'s> {
// ^^
// ^ The trait includes a lifetime parameter.
type Assoc;
// ^^^^^
// ^ No lifetime bounds are required on the associated type in
// the trait definition.
}
impl<'s> Trait<'s> for () {
// ^^
// ^ The Self type contains no lifetimes.
type Assoc = &'s ();
// ^^^^^^
// ^ The type substituted for the associated type
// includes the in-scope lifetime also used to populate
// the lifetime parameter of the trait.
}
```
[Playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=trait+Trait%3C%27s%3E+%7B%0A++++%2F%2F++++++%5E%5E%0A++++%2F%2F++++++%5E+The+trait+includes+a+lifetime+parameter.%0A++++type+Assoc%3B%0A++++%2F%2F+++%5E%5E%5E%5E%5E%0A++++%2F%2F+++%5E+No+lifetime+bounds+are+required+on+the+associated+type+in%0A++++%2F%2F+++the+trait+definition.%0A%7D%0A%0Aimpl%3C%27s%3E+Trait%3C%27s%3E+for+%28%29+%7B%0A++++%2F%2F+++++++++++++++++%5E%5E%0A++++%2F%2F+++++++++++++++++%5E+The+Self+type+contains+no+lifetimes.%0A++++type+Assoc+%3D+%26%27s+%28%29%3B%0A++++%2F%2F+++++++++++%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++++++++++%5E+The+type+substituted+for+the+associated+type%0A++++%2F%2F+++++++++++includes+the+in-scope+lifetime+also+used+to+populate%0A++++%2F%2F+++++++++++the+lifetime+parameter+of+the+trait.%0A%7D%0A)
In the above example, the lifetime is a parameter to the trait. In the impl, it is included in the type substituted for the associated type but it is not included in the `Self` type.
```rust
trait Trait {
// ^^
// ^ No lifetime parameters on trait.
type Assoc;
// ^^^^^
// ^ No lifetime bounds are required on the associated type in
// the trait definition.
}
struct Foo<'s>(&'s ());
impl<'s> Trait for Foo<'s> {
// ^^
// ^ The Self type contrains a lifetime.
type Assoc = Foo<'s>;
// ^^^^^^^
// ^ The type substituted for the associated type
// includes the in-scope lifetime also used to populate
// the lifetime parameter of the `Self` type.
}
```
[Playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=trait+Trait+%7B%0A++++%2F%2F++++%5E%5E%0A++++%2F%2F++++%5E+No+lifetime+parameters+on+trait.%0A++++type+Assoc%3B%0A++++%2F%2F+++%5E%5E%5E%5E%5E%0A++++%2F%2F+++%5E+No+lifetime+bounds+are+required+on+the+associated+type+in%0A++++%2F%2F+++the+trait+definition.%0A%7D%0A%0Astruct+Foo%3C%27s%3E%28%26%27s+%28%29%29%3B%0Aimpl%3C%27s%3E+Trait+for+Foo%3C%27s%3E+%7B%0A++++%2F%2F+++++++++++++++++%5E%5E%0A++++%2F%2F+++++++++++++++++%5E+The+Self+type+contrains+a+lifetime.%0A++++type+Assoc+%3D+Foo%3C%27s%3E%3B%0A++++%2F%2F+++++++++++%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++++++++++%5E+The+type+substituted+for+the+associated+type%0A++++%2F%2F+++++++++++includes+the+in-scope+lifetime+also+used+to+populate%0A++++%2F%2F+++++++++++the+lifetime+parameter+of+the+%60Self%60+type.%0A%7D%0A)
In the above example, the trait itself does not have a lifetime parameter. However, the `Self` type in the impl does contain a lifetime parameter, and that lifetime is included in the type substituted for the associated type.
</details></p>
## RPIT lifetime capture rules (bounds required on the opaque type)
The hidden type in RPIT can only capture a lifetime if that lifetime appears explicitly in the bounds of the opaque type.
### RPIT on inherent methods
On inherent methods, lifetimes in scope from the impl and lifetimes in scope from the method signature must both be stated explicitly in the bounds of the RPIT opaque type if they are to be captured by the hidden type.
```rust
trait Captures3<'c1, 'c2, 'c3>: Sized {}
impl<'c1, 'c2, 'c3, T> Captures3<'c1, 'c2, 'c3> for T {}
struct Foo<'s>(*mut &'s ());
impl<'s, 't> Foo<'s> {
fn foo<'f>(
self, f: &'f (), t: &'t ()
) -> impl Sized + Captures3<'f, 's, 't>
// ^^^^^^^^^^^^^^^^^^^^^^^
// ^ Explicit bounds are required on the RPIT opaque
// type.
{ (self, f, t) }
// ^^^^^^^^^^^^
// ^ The RPIT hidden type captures the lifetime on the Self type,
// the lifetime in the method signature, and another in-scope type
// parameter.
}
```
[Playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=trait+Captures3%3C%27c1%2C+%27c2%2C+%27c3%3E%3A+Sized+%7B%7D%0Aimpl%3C%27c1%2C+%27c2%2C+%27c3%2C+T%3E+Captures3%3C%27c1%2C+%27c2%2C+%27c3%3E+for+T+%7B%7D%0A%0Astruct+Foo%3C%27s%3E%28%2Amut+%26%27s+%28%29%29%3B%0Aimpl%3C%27s%2C+%27t%3E+Foo%3C%27s%3E+%7B%0A++++fn+foo%3C%27f%3E%28%0A++++++++self%2C+f%3A+%26%27f+%28%29%2C+t%3A+%26%27t+%28%29%0A++++%29+-%3E+impl+Sized+%2B+Captures3%3C%27f%2C+%27s%2C+%27t%3E%0A++++%2F%2F++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F++++++++++++++%5E+Explicit+bounds+are+required+on+the+RPIT+opaque%0A++++%2F%2F++++++++++++++type.%0A++++%7B+%28self%2C+f%2C+t%29+%7D%0A%2F%2F++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A%2F%2F++++%5E+The+RPIT+hidden+type+captures+the+lifetime+on+the+Self+type%2C%0A%2F%2F++++the+lifetime+in+the+method+signature%2C+and+another+in-scope+type%0A%2F%2F++++parameter.%0A%7D%0A)
Note that for RPIT, the bound on the opaque type does not just say what the hidden type *may* capture but it also says what the opaque type *does* capture. If the opaque type captures less than the bound allows, callers *cannot* rely on that.
### RPIT on free functions
On free functions, lifetimes in scope from the function signature must be stated explicitly in the bounds of the RPIT opaque type if they are to be captured by the hidden type.
```rust
trait Captures<'c>: Sized {}
impl<'c, T> Captures<'c> for T {}
struct Foo<'s>(&'s ());
fn foo<'s>(s: Foo<'s>) -> impl Sized + Captures<'s> {
s // ^^^^^^^^^^^^^^
// ^ ^ Explicit bounds are required on
// | the RPIT opaque type.
// |
// ^ The RPIT hidden type captures the lifetime in the method
// signature.
}
```
[Playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=trait+Captures%3C%27c%3E%3A+Sized+%7B%7D%0Aimpl%3C%27c%2C+T%3E+Captures%3C%27c%3E+for+T+%7B%7D%0A%0Astruct+Foo%3C%27s%3E%28%26%27s+%28%29%29%3B%0A%0Afn+foo%3C%27s%3E%28s%3A+Foo%3C%27s%3E%29+-%3E+impl+Sized+%2B+Captures%3C%27s%3E+%7B%0A++++s+%2F%2F+++++++++++++++++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A%2F%2F++%5E++++++++++++++++++++++++++++++++%5E+Explicit+bounds+are+required+on%0A%2F%2F++%7C++++++++++++++++++++++++++++++++the+RPIT+opaque+type.%0A%2F%2F++%7C%0A%2F%2F++%5E+The+RPIT+hidden+type+captures+the+lifetime+in+the+method%0A%2F%2F++signature.%0A%7D%0A)
## TAIT lifetime capture rules (bounds required on opaque type)
The current implementation of TAIT exactly matches the lifetime capture rules of RPIT. Explicit lifetime bounds are required on the opaque type for the lifetime to be captured by the hidden type.
```rust
#![feature(type_alias_impl_trait)]
trait Captures<'c>: Sized {}
impl<'c, T> Captures<'c> for T {}
type Hidden<'s> = impl Sized + Captures<'s>;
// ^^^^^^^^^^^^^^
// ^ Explicit bounds are required on the TAIT
// opaque type.
fn foo<'s>(s: &'s ()) -> Hidden<'s> { s }
// ^^^^^^^^^^^^^^^^
// ^ The TAIT hidden type captures the lifetime
// from the function signature.
```
[Playground link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&code=%23%21%5Bfeature%28type_alias_impl_trait%29%5D%0A%0Atrait+Captures%3C%27c%3E%3A+Sized+%7B%7D%0Aimpl%3C%27c%2C+T%3E+Captures%3C%27c%3E+for+T+%7B%7D%0A%0Atype+Hidden%3C%27s%3E+%3D+impl+Sized+%2B+Captures%3C%27s%3E%3B%0A%2F%2F+++++++++++++++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A%2F%2F+++++++++++++++++++++++++++%5E+Explicit+bounds+are+required+on+the+TAIT%0A%2F%2F+++++++++++++++++++++++++++++opaque+type.%0A%0Afn+foo%3C%27s%3E%28s%3A+%26%27s+%28%29%29+-%3E+Hidden%3C%27s%3E+%7B+s+%7D%0A%2F%2F+++++++++++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A%2F%2F+++++++++++++++++++++++%5E+The+TAIT+hidden+type+captures+the+lifetime%0A%2F%2F+++++++++++++++++++++++from+the+function+signature.%0A)
Note that for TAIT, like RPIT, the bound on the opaque type does not just say what the hidden type *may* capture but it also says what the opaque type *does* capture. If the opaque type captures less than the bound allows, callers *cannot* rely on that.
## ATPIT lifetime capture rules (bounds required on opaque type but not in trait)
The current implementation of ATPIT follows the existing lifetime rules of both RPIT and GATs. In the trait definition, no bounds are required on the GAT. In the impl, lifetimes in scope from the impl must be stated explicitly in the bounds of the ATPIT opaque type if they are to be captured by the hidden type.
```rust
#![feature(impl_trait_in_assoc_type)]
trait Captures3<'c1, 'c2, 'c3>: Sized {}
impl<'c1, 'c2, 'c3, T> Captures3<'c1, 'c2, 'c3> for T {}
trait Trait<'t> {
type Assoc<'g>;
// ^^^^^^^^^
// ^ No bounds are required on the GAT in the trait definition.
//
// That is, we did not have to say:
//
// type Assoc<'t>: Captures3<'Self, 't, 'g>;
fn foo<'m>(self, t: &'t (), m: &'m ()) -> Self::Assoc<'m>;
}
impl<'s, 't> Trait<'t> for &'s () {
type Assoc<'g> = impl Sized + Captures3<'s, 't, 'g>;
// ^^^^^^^^^^^^^^^^^^^^^^^
// ^ Explicit bounds are required on the
// ATPIT opaque type.
fn foo<'m>(self, t: &'t (), m: &'m ()) -> Self::Assoc<'m> {
(self, t, m)
// ^^^^^^^^^^^^
// ^ The ATPIT hidden type captures the lifetime in the Self
// type, the in-scope type parameter used to populate the trait
// input lifetime, and the lifetime in the method signature.
}
}
```
[Playground link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&code=%23%21%5Bfeature%28impl_trait_in_assoc_type%29%5D%0A%0Atrait+Captures3%3C%27c1%2C+%27c2%2C+%27c3%3E%3A+Sized+%7B%7D%0Aimpl%3C%27c1%2C+%27c2%2C+%27c3%2C+T%3E+Captures3%3C%27c1%2C+%27c2%2C+%27c3%3E+for+T+%7B%7D%0A%0Atrait+Trait%3C%27t%3E+%7B%0A++++type+Assoc%3C%27g%3E%3B%0A++++%2F%2F+++%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++%5E+No+bounds+are+required+on+the+GAT+in+the+trait+definition.%0A++++%2F%2F%0A++++%2F%2F+++That+is%2C+we+did+not+have+to+say%3A%0A++++%2F%2F%0A++++%2F%2F+++++++type+Assoc%3C%27t%3E%3A+Captures3%3C%27Self%2C+%27t%2C+%27g%3E%3B%0A++++fn+foo%3C%27m%3E%28self%2C+t%3A+%26%27t+%28%29%2C+m%3A+%26%27m+%28%29%29+-%3E+Self%3A%3AAssoc%3C%27m%3E%3B%0A%7D%0A%0Aimpl%3C%27s%2C+%27t%3E+Trait%3C%27t%3E+for+%26%27s+%28%29+%7B%0A++++type+Assoc%3C%27g%3E+%3D+impl+Sized+%2B+Captures3%3C%27s%2C+%27t%2C+%27g%3E%3B%0A++++%2F%2F++++++++++++++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F++++++++++++++++++++++++++%5E+Explicit+bounds+are+required+on+the%0A++++%2F%2F++++++++++++++++++++++++++ATPIT+opaque+type.%0A++++fn+foo%3C%27m%3E%28self%2C+t%3A+%26%27t+%28%29%2C+m%3A+%26%27m+%28%29%29+-%3E+Self%3A%3AAssoc%3C%27m%3E+%7B%0A++++++++%28self%2C+t%2C+m%29%0A++++%2F%2F++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F++%5E+The+ATPIT+hidden+type+captures+the+lifetime+in+the+Self%0A++++%2F%2F++type%2C+the+in-scope+type+parameter+used+to+populate+the+trait%0A++++%2F%2F++input+lifetime%2C+and+the+lifetime+in+the+method+signature.%0A++++%7D%0A%7D%0A)
Note that for ATPIT, like RPIT, the bound on the opaque type does not just say what the hidden type *may* capture but it also says what the opaque type *does* capture. If the opaque type captures less than the bound allows, callers *cannot* rely on that.
## Summary of background
Generic parameters, associated types, and GATs defined in traits may be substituted in impls with types that contain lifetimes that were not mentioned in the bound of the generic parameter or the GAT in the trait definition. If a generic parameter or GAT is bounded by a lifetime in the trait definition but the impl for a particular type does not use the lifetime in the type substituted for the generic parameter or GAT, then users of the impl for that type may observe and rely on that "refinement".
For an RPIT hidden type to capture a lifetime, that lifetime must appear in the bounds of the opaque type. If a lifetime does appear in the bounds of the opaque type, then even if the hidden type does not in fact use that lifetime, callers cannot rely on that; the opaque type is still bounded by the lifetime.
TAIT, as implemented and as proposed for stabilization, follows the current stable behavior of RPIT exactly.
ATPIT, as implemented and as proposed for stabilization, follows *both* the current stable behaviors of RPIT and GATs exactly.
For multiple lifetimes, particularly when those lifetimes are invariant, the `Captures` trick is required when dealing with generic parameters in traits, associated types, GATs, RPIT, TAIT, and ATPIT.
# Motivating examples
## Example A: Capturing a lifetime from the Self type
### Example A.1
```rust
#![feature(return_position_impl_trait_in_trait)]
trait Trait {
fn foo(self) -> impl Sized;
// ^^^^^^^^^^
// ^ No lifetime bounds on RPITIT opaque type in
// trait definition.
}
impl<'s> Trait for &'s () {
// ^^^^^^
// ^ Self type contains an in-scope lifetime.
fn foo(self) -> &'s () { self }
// ^^^^^^^^^^^^^
// ^ RPITIT hidden type captures the lifetime
// contained in Self type.
}
```
[Playground link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&code=%23%21%5Bfeature%28return_position_impl_trait_in_trait%29%5D%0A%0Atrait+Trait+%7B%0A++++fn+foo%28self%29+-%3E+impl+Sized%3B%0A++++%2F%2F++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F++++++++++++++%5E+No+lifetime+bounds+on+RPITIT+opaque+type+in%0A++++%2F%2F++++++++++++++trait+definition.%0A%7D%0A%0Aimpl%3C%27s%3E+Trait+for+%26%27s+%28%29+%7B%0A++++%2F%2F+++++++++++++%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++++++++++++%5E+Self+type+contains+an+in-scope+lifetime.%0A++++fn+foo%28self%29+-%3E+%26%27s+%28%29+%7B+self+%7D%0A++++%2F%2F++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F++++++++++++++%5E+RPITIT+hidden+type+captures+the+lifetime%0A++++%2F%2F++++++++++++++contained+in+Self+type.%0A%7D%0A)
#### Desugaring
<p><details>
<summary>Show</summary>
We can view it as *roughly* desugaring to:
```rust
trait Trait {
type Foo: Sized;
// ^^^^^^^^^^
// ^ We can think of the RPITIT hidden type as an
// associated type.
fn foo(self) -> Self::Foo;
}
impl<'s> Trait for &'s () {
type Foo = &'s ();
// ^^^^^^
// ^ We substitute the Self type containing the in-scope
// lifetime from the impl for the associated type.
fn foo(self) -> Self::Foo { self }
}
```
[Playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=trait+Trait+%7B%0A++++type+Foo%3A+Sized%3B%0A++++%2F%2F+++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++%5E+We+can+think+of+the+RPITIT+hidden+type+as+an%0A++++%2F%2F+++associated+type.%0A++++fn+foo%28self%29+-%3E+Self%3A%3AFoo%3B%0A%7D%0A%0Aimpl%3C%27s%3E+Trait+for+%26%27s+%28%29+%7B%0A++++type+Foo+%3D+%26%27s+%28%29%3B%0A++++%2F%2F+++++++++%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++++++++%5E+We+substitute+the+Self+type+containing+the+in-scope%0A++++%2F%2F+++++++++lifetime+from+the+impl+for+the+associated+type.%0A++++fn+foo%28self%29+-%3E+Self%3A%3AFoo+%7B+self+%7D%0A%7D%0A)
</details></p>
### Example A.2
Or equivalently (on nightly), using an RPIT in the impl[^1]:
```rust
#![feature(return_position_impl_trait_in_trait)]
trait Captures<'c>: Sized {}
impl<'c, T> Captures<'c> for T {}
trait Trait {
fn foo(self) -> impl Sized;
// ^^^^^^^^^^
// ^ No lifetime bounds on RPITIT opaque type in
// trait definition.
}
impl<'s> Trait for &'s () {
// ^^^^^^
// ^ Self type contains an in-scope lifetime.
fn foo(self) -> impl Sized + Captures<'s> { self }
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// ^ The RPIT opaque type is explicitly bounded by
// the in-scope lifetime that the RPIT hidden type
// captures.
}
```
[Playground link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&code=%23%21%5Bfeature%28return_position_impl_trait_in_trait%29%5D%0A%0Atrait+Captures%3C%27c%3E%3A+Sized+%7B%7D%0Aimpl%3C%27c%2C+T%3E+Captures%3C%27c%3E+for+T+%7B%7D%0A%0Atrait+Trait+%7B%0A++++fn+foo%28self%29+-%3E+impl+Sized%3B%0A++++%2F%2F++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F++++++++++++++%5E+No+lifetime+bounds+on+RPITIT+opaque+type+in%0A++++%2F%2F++++++++++++++trait+definition.%0A%7D%0A%0Aimpl%3C%27s%3E+Trait+for+%26%27s+%28%29+%7B%0A++++%2F%2F+++++++++++++%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++++++++++++%5E+Self+type+contains+an+in-scope+lifetime.%0A++++fn+foo%28self%29+-%3E+impl+Sized+%2B+Captures%3C%27s%3E+%7B+self+%7D%0A++++%2F%2F++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F++++++++++++++%5E+The+RPIT+opaque+type+is+explicitly+bounded+by%0A++++%2F%2F++++++++++++++the+in-scope+lifetime+that+the+RPIT+hidden+type%0A++++%2F%2F++++++++++++++captures.%0A%7D%0A)
Important to note here and below that we're only concerned with the capture rules of the RPITIT. Not (at least until examples D and E) the capture rules of the *totally separate* RPIT in the impl.
[^1]: This is ignoring `#[refine]`s rules right now, because they are an additional check and have no influence on the RPITIT type inference algorithm.
#### Desugaring
<p><details>
<summary>Show</summary>
We can view it as *roughly* desugaring to:
```rust
#![feature(impl_trait_in_assoc_type)]
trait Captures<'c>: Sized {}
impl<'c, T> Captures<'c> for T {}
trait Trait {
type Foo: Sized;
// ^^^^^^^^^^
// ^ We can think of the RPITIT hidden type as an
// associated type.
fn foo(self) -> Self::Foo;
}
impl<'s> Trait for &'s () {
type Foo = impl Sized + Captures<'s>;
// ^^^^^^^^^^^^^^^^^^^^^^^^^
// ^ The ATPIT opaque type is explicitly bounded by the
// in-scope lifetime that the ATPIT hidden type captures.
fn foo(self) -> Self::Foo { self }
}
```
[Playground link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&code=%23%21%5Bfeature%28impl_trait_in_assoc_type%29%5D%0A%0Atrait+Captures%3C%27c%3E%3A+Sized+%7B%7D%0Aimpl%3C%27c%2C+T%3E+Captures%3C%27c%3E+for+T+%7B%7D%0A%0Atrait+Trait+%7B%0A++++type+Foo%3A+Sized%3B%0A++++%2F%2F+++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++%5E+We+can+think+of+the+RPITIT+hidden+type+as+an%0A++++%2F%2F+++associated+type.%0A++++fn+foo%28self%29+-%3E+Self%3A%3AFoo%3B%0A%7D%0A%0Aimpl%3C%27s%3E+Trait+for+%26%27s+%28%29+%7B%0A++++type+Foo+%3D+impl+Sized+%2B+Captures%3C%27s%3E%3B%0A++++%2F%2F+++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++++++++%5E+The+ATPIT+opaque+type+is+explicitly+bounded+by+the%0A++++%2F%2F+++++++++in-scope+lifetime+that+the+ATPIT+hidden+type+captures.%0A++++fn+foo%28self%29+-%3E+Self%3A%3AFoo+%7B+self+%7D%0A%7D%0A)
</details></p>
### Example A.3
```rust
#![feature(return_position_impl_trait_in_trait)]
trait Trait: Sized {
fn foo(self) -> impl Sized { self }
// ^^^^^^^^^^
// ^ No lifetime bounds on RPTITI opaque type in
// trait definition.
}
impl<'s> Trait for &'s () {}
// ^^^
// ^ RPITIT hidden type captures the lifetime
// contained in the Self type.
```
[Playground link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&code=%23%21%5Bfeature%28return_position_impl_trait_in_trait%29%5D%0A%0Atrait+Trait%3A+Sized+%7B%0A++++fn+foo%28self%29+-%3E+impl+Sized+%7B+self+%7D%0A++++%2F%2F++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F++++++++++++++%5E+No+lifetime+bounds+on+RPTITI+opaque+type+in%0A++++%2F%2F++++++++++++++trait+definition.%0A%7D%0A%0Aimpl%3C%27s%3E+Trait+for+%26%27s+%28%29+%7B%7D%0A%2F%2F+++++++++++++++++%5E%5E%5E%0A%2F%2F+++++++++++++++++%5E+RPITIT+hidden+type+captures+the+lifetime%0A%2F%2F+++++++++++++++++contained+in+the+Self+type.%0A)
#### Desugaring
<p><details>
<summary>Show</summary>
We can view it as *roughly* desugaring to:
```rust
trait Trait {
type Foo: Sized;
// ^^^^^^^^^^
// ^ We can think of the RPITIT hidden type as an
// associated type.
fn foo(self) -> Self::Foo;
}
impl<'s> Trait for &'s () {
type Foo = &'s ();
// ^^^^^^
// ^ We substitute the Self type containing the in-scope
// lifetime from the impl for the associated type.
fn foo(self) -> Self::Foo { self }
// ^^^^^^^^^^^^^^^^^^^^^^
// ^ The compiler automatically produces this method
// implementation from the one in the trait definition.
}
```
[Playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=trait+Trait+%7B%0A++++type+Foo%3A+Sized%3B%0A++++%2F%2F+++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++%5E+We+can+think+of+the+RPITIT+hidden+type+as+an%0A++++%2F%2F+++associated+type.%0A++++fn+foo%28self%29+-%3E+Self%3A%3AFoo%3B%0A%7D%0A%0Aimpl%3C%27s%3E+Trait+for+%26%27s+%28%29+%7B%0A++++type+Foo+%3D+%26%27s+%28%29%3B%0A++++%2F%2F+++++++++%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++++++++%5E+We+substitute+the+Self+type+containing+the+in-scope%0A++++%2F%2F+++++++++lifetime+from+the+impl+for+the+associated+type.%0A++++fn+foo%28self%29+-%3E+Self%3A%3AFoo+%7B+self+%7D%0A++++%2F%2F+%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+%5E+The+compiler+automatically+produces+this+method%0A++++%2F%2F+implementation+from+the+one+in+the+trait+definition.%0A%7D%0A)
</details></p>
### Matrix
How each rule would affect this example:
- "Strict": Not supported.
- "Current": Supported.
- "Only Self": Supported.
- "Any in scope": Supported.
- "Current + Copyable signature": Supported.
- "Any in scope + Copyable signature": Supported.
## Example B: Capturing a non-Self trait input lifetime
### Example B.1
```rust
#![feature(return_position_impl_trait_in_trait)]
trait Trait<'a> {
// ^^
// ^ The trait definition includes an input lifetime
// parameter.
fn foo(&'a self) -> impl Sized;
}
impl<'a> Trait<'a> for () {
// ^^
// ^ The Self type does not include the lifetime.
fn foo(&'a self) -> &'a Self { self }
// ^^^^^^^^^^^^^^^^^
// ^ The RPITIT hidden type captures the in-scope
// lifetime from the impl.
}
```
[Playground link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&code=%23%21%5Bfeature%28return_position_impl_trait_in_trait%29%5D%0A%0Atrait+Trait%3C%27a%3E+%7B%0A++++%2F%2F++++++%5E%5E%0A++++%2F%2F++++++%5E+The+trait+definition+includes+an+input+lifetime%0A++++%2F%2F++++++parameter.%0A++++fn+foo%28%26%27a+self%29+-%3E+impl+Sized%3B%0A%7D%0A%0Aimpl%3C%27a%3E+Trait%3C%27a%3E+for+%28%29+%7B%0A++++%2F%2F+++++++++++++++++%5E%5E%0A++++%2F%2F+++++++++++++++++%5E+The+Self+type+does+not+include+the+lifetime.%0A++++fn+foo%28%26%27a+self%29+-%3E+%26%27a+Self+%7B+self+%7D%0A++++%2F%2F++++++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F++++++++++++++++++%5E+The+RPITIT+hidden+type+captures+the+in-scope%0A++++%2F%2F++++++++++++++++++lifetime+from+the+impl.%0A%7D%0A)
#### Desugaring
<p><details>
<summary>Show</summary>
We can view it as *roughly* desugaring to:
```rust
trait Trait<'a> {
type Foo: Sized;
// ^^^^^^^^^^
// ^ We can think of the RPITIT hidden type as an
// associated type.
fn foo(&'a self) -> Self::Foo;
}
impl<'a> Trait<'a> for () {
type Foo = &'a Self;
// ^^^^^^^^
// ^ We substitute a type containing the in-scope lifetime
// from the impl for the associated type.
fn foo(&'a self) -> Self::Foo { self }
}
```
[Playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=trait+Trait%3C%27a%3E+%7B%0A++++type+Foo%3A+Sized%3B%0A++++fn+foo%28%26%27a+self%29+-%3E+Self%3A%3AFoo%3B%0A%7D%0A%0Aimpl%3C%27a%3E+Trait%3C%27a%3E+for+%28%29+%7B%0A++++type+Foo+%3D+%26%27a+Self%3B%0A++++fn+foo%28%26%27a+self%29+-%3E+Self%3A%3AFoo+%7B+self+%7D%0A%7D%0A)
</details></p>
### Example B.2
Or equivalently, ignoring `#[refine]` rules which are not relevant for the RPITIT inference algorithm:
```rust
#![feature(return_position_impl_trait_in_trait)]
trait Captures<'c>: Sized {}
impl<'c, T> Captures<'c> for T {}
trait Trait<'a> {
// ^^
// ^ The trait definition includes an input lifetime
// parameter.
fn foo(&'a self) -> impl Sized;
}
impl<'a> Trait<'a> for () {
// ^^
// ^ The Self type does not include the lifetime.
fn foo(&'a self) -> impl Sized + Captures<'a> { self }
// ^^^^^^^^^^^^^^^^^^^^^^^^^
// ^ The RPIT opaque type is explicitly bounded
// by the in-scope lifetime that the RPIT hidden
// type captures.
}
```
[Playground link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&code=%23%21%5Bfeature%28return_position_impl_trait_in_trait%29%5D%0A%0Atrait+Captures%3C%27c%3E%3A+Sized+%7B%7D%0Aimpl%3C%27c%2C+T%3E+Captures%3C%27c%3E+for+T+%7B%7D%0A%0Atrait+Trait%3C%27a%3E+%7B%0A++++%2F%2F++++++%5E%5E%0A++++%2F%2F++++++%5E+The+trait+definition+includes+an+input+lifetime%0A++++%2F%2F++++++parameter.%0A++++fn+foo%28%26%27a+self%29+-%3E+impl+Sized%3B%0A%7D%0A%0Aimpl%3C%27a%3E+Trait%3C%27a%3E+for+%28%29+%7B%0A++++%2F%2F+++++++++++++++++%5E%5E%0A++++%2F%2F+++++++++++++++++%5E+The+Self+type+does+not+include+the+lifetime.%0A++++fn+foo%28%26%27a+self%29+-%3E+impl+Sized+%2B+Captures%3C%27a%3E+%7B+self+%7D%0A++++%2F%2F++++++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F++++++++++++++++++%5E+The+RPIT+opaque+type+is+explicitly+bounded%0A++++%2F%2F++++++++++++++++++by+the+in-scope+lifetime+that+the+RPIT+hidden%0A++++%2F%2F++++++++++++++++++type+captures.%0A%7D%0A)
#### Desugaring
<p><details>
<summary>Show</summary>
We can view it as *roughly* desugaring to:
```rust
#![feature(impl_trait_in_assoc_type)]
trait Captures<'c>: Sized {}
impl<'c, T> Captures<'c> for T {}
trait Trait<'a> {
type Foo: Sized;
// ^^^^^^^^^^
// ^ We can think of the RPITIT hidden type as an
// associated type.
fn foo(&'a self) -> Self::Foo;
}
impl<'a> Trait<'a> for () {
type Foo = impl Sized + Captures<'a>;
// ^^^^^^^^^^^^^^^^^^^^^^^^^
// ^ The ATPIT opaque type is explicitly bounded by the
// in-scope lifetime that the ATPIT hidden type captures.
fn foo(&'a self) -> Self::Foo { self }
}
```
[Playground link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&code=%23%21%5Bfeature%28impl_trait_in_assoc_type%29%5D%0A%0Atrait+Captures%3C%27c%3E%3A+Sized+%7B%7D%0Aimpl%3C%27c%2C+T%3E+Captures%3C%27c%3E+for+T+%7B%7D%0A%0Atrait+Trait%3C%27a%3E+%7B%0A++++type+Foo%3A+Sized%3B%0A++++%2F%2F+++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++%5E+We+can+think+of+the+RPITIT+hidden+type+as+an%0A++++%2F%2F+++associated+type.%0A++++fn+foo%28%26%27a+self%29+-%3E+Self%3A%3AFoo%3B%0A%7D%0A%0Aimpl%3C%27a%3E+Trait%3C%27a%3E+for+%28%29+%7B%0A++++type+Foo+%3D+impl+Sized+%2B+Captures%3C%27a%3E%3B%0A++++%2F%2F+++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++++++++%5E+The+ATPIT+opaque+type+is+explicitly+bounded+by+the%0A++++%2F%2F+++++++++in-scope+lifetime+that+the+ATPIT+hidden+type+captures.%0A++++fn+foo%28%26%27a+self%29+-%3E+Self%3A%3AFoo+%7B+self+%7D%0A%7D%0A)
</details></p>
### Example B.3
```rust
#![feature(return_position_impl_trait_in_trait)]
trait Captures<'c>: Sized {}
impl<'c, T> Captures<'c> for T {}
trait Trait<'a> {
// ^^
// ^ The trait definition includes an input lifetime
// parameter.
fn foo(&'a self) -> impl Sized + Captures<'a> { self }
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// ^ The trait definition includes a default implementation for
// the method that captures the input lifetime. We must use the
// Captures trick here.
}
impl<'a> Trait<'a> for () {}
// ^^^
// ^ RPITIT hidden type captures the lifetime
// contained in the Self type.
```
[Playground link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&code=%23%21%5Bfeature%28return_position_impl_trait_in_trait%29%5D%0A%0Atrait+Captures%3C%27c%3E%3A+Sized+%7B%7D%0Aimpl%3C%27c%2C+T%3E+Captures%3C%27c%3E+for+T+%7B%7D%0A%0Atrait+Trait%3C%27a%3E+%7B%0A++++%2F%2F++++++%5E%5E%0A++++%2F%2F++++++%5E+The+trait+definition+includes+an+input+lifetime%0A++++%2F%2F++++++parameter.%0A++++fn+foo%28%26%27a+self%29+-%3E+impl+Sized+%2B+Captures%3C%27a%3E+%7B+self+%7D%0A++++%2F%2F+%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+%5E+The+trait+definition+includes+a+default+implementation+for%0A++++%2F%2F+the+method+that+captures+the+input+lifetime.++We+must+use+the%0A++++%2F%2F+Captures+trick+here.%0A%7D%0A%0Aimpl%3C%27a%3E+Trait%3C%27a%3E+for+%28%29+%7B%7D%0A%2F%2F+++++++++++++%5E%5E%5E%0A%2F%2F+++++++++++++%5E+RPITIT+hidden+type+captures+the+lifetime%0A%2F%2F+++++++++++++contained+in+the+Self+type.%0A)
#### Desugaring
<p><details>
<summary>Show</summary>
We can view it as *roughly* desugaring to:
```rust
trait Trait<'a> {
type Foo: Sized;
// ^^^^^^^^^^
// ^ We can think of the RPITIT hidden type as an
// associated type.
fn foo(&'a self) -> Self::Foo;
}
impl<'a> Trait<'a> for () {
type Foo = &'a Self;
// ^^^^^^^^
// ^ We substitute a type containing the in-scope lifetime
// from the impl for the associated type.
fn foo(&'a self) -> Self::Foo { self }
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// ^ The compiler automatically produces this method
// implementation from the one in the trait definition.
}
```
[Playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=trait+Trait%3C%27a%3E+%7B%0A++++type+Foo%3A+Sized%3B%0A++++%2F%2F+++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++%5E+We+can+think+of+the+RPITIT+hidden+type+as+an%0A++++%2F%2F+++associated+type.%0A++++fn+foo%28%26%27a+self%29+-%3E+Self%3A%3AFoo%3B%0A%7D%0A%0Aimpl%3C%27a%3E+Trait%3C%27a%3E+for+%28%29+%7B%0A++++type+Foo+%3D+%26%27a+Self%3B%0A++++%2F%2F+++++++++%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++++++++%5E+We+substitute+a+type+containing+the+in-scope+lifetime%0A++++%2F%2F+++++++++from+the+impl+for+the+associated+type.%0A++++fn+foo%28%26%27a+self%29+-%3E+Self%3A%3AFoo+%7B+self+%7D%0A++++%2F%2F+%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+%5E+The+compiler+automatically+produces+this+method%0A++++%2F%2F+implementation+from+the+one+in+the+trait+definition.%0A%7D%0A)
</details></p>
### Matrix
How each rule would affect this example:
- "Strict": Not supported.
- "Current": Supported.
- "Only Self": Not supported.
- "Any in scope": Supported.
- "Current + Copyable signature": Supported.
- "Any in scope + Copyable signature": Supported.
## Example C: Capturing a method lifetime
### Example C.1
This example uses a late-bound lifetime, but I strongly believe that we should not be treating early- and late-bound lifetimes differently in RPITIT capture rules.
```rust
#![feature(return_position_impl_trait_in_trait)]
trait Trait {
fn foo<'a>(&'a self) -> impl Sized;
// ^^ ^^^^^^^^^^
// ^ The method signature includes a lifetime.
// |
// ^ The RPITIT opaque type is not bounded by
// any lifetimes.
}
impl Trait for () {
fn foo<'a>(&'a self) -> &'a Self { self }
// ^^^^^^^^^^^^^^^^^
// ^ The RPITIT hidden type captures the
// lifetime from the method's signature.
}
```
[Playground link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&code=%23%21%5Bfeature%28return_position_impl_trait_in_trait%29%5D%0A%0Atrait+Trait+%7B%0A++++fn+foo%3C%27a%3E%28%26%27a+self%29+-%3E+impl+Sized%3B%0A++++%2F%2F+++++%5E%5E+++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++++%5E+The+method+signature+includes+a+lifetime.%0A++++%2F%2F++++++++++++++++++++++%7C%0A++++%2F%2F++++++++++++++++++++++%5E+The+RPITIT+opaque+type+is+not+bounded+by%0A++++%2F%2F++++++++++++++++++++++any+lifetimes.%0A%7D%0A%0Aimpl+Trait+for+%28%29+%7B%0A++++fn+foo%3C%27a%3E%28%26%27a+self%29+-%3E+%26%27a+Self+%7B+self+%7D%0A++++%2F%2F++++++++++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F++++++++++++++++++++++%5E+The+RPITIT+hidden+type+captures+the%0A++++%2F%2F++++++++++++++++++++++lifetime+from+the+method%27s+signature.%0A%7D%0A)
#### Desugaring
<p><details>
<summary>Show</summary>
We can view it as *roughly* desugaring to:
```rust
trait Trait {
type Foo<'s>: Sized where Self: 's;
// ^^^^^^^^^^^^^^
// ^ We can think of the RPITIT hidden type as a GAT.
fn foo<'a>(&'a self) -> Self::Foo<'a>;
// ^^ ^^
// ^ The method signature includes a lifetime parameter that
// we'll use to parameterize the GAT.
}
impl Trait for () {
type Foo<'s> = &'s Self;
// ^^^^^^^^
// ^ We substitute a type containing the in-scope
// lifetime from the GAT.
fn foo<'a>(&'a self) -> Self::Foo<'a> { self }
}
```
[Playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=trait+Trait+%7B%0A++++type+Foo%3C%27s%3E%3A+Sized+where+Self%3A+%27s%3B%0A++++%2F%2F+++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++%5E+We+can+think+of+the+RPITIT+hidden+type+as+a+GAT.%0A++++fn+foo%3C%27a%3E%28%26%27a+self%29+-%3E+Self%3A%3AFoo%3C%27a%3E%3B%0A++++%2F%2F+++++%5E%5E+++++++++++++++++++++++++%5E%5E%0A++++%2F%2F+++++%5E+The+method+signature+includes+a+lifetime+parameter+that%0A++++%2F%2F+++++we%27ll+use+to+parameterize+the+GAT.%0A%7D%0A%0Aimpl+Trait+for+%28%29+%7B%0A++++type+Foo%3C%27s%3E+%3D+%26%27s+Self%3B%0A++++%2F%2F+++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++++++++++++%5E+We+substitute+a+type+containing+the+in-scope%0A++++%2F%2F+++++++++++++lifetime+from+the+GAT.%0A++++fn+foo%3C%27a%3E%28%26%27a+self%29+-%3E+Self%3A%3AFoo%3C%27a%3E+%7B+self+%7D%0A%7D%0A)
</details></p>
### Example C.2
Or equivalently, ignoring `#[refine]` rules which are not relevant for the RPITIT inference algorithm:
```rust
#![feature(return_position_impl_trait_in_trait)]
trait Captures<'c>: Sized {}
impl<'c, T> Captures<'c> for T {}
trait Trait {
fn foo<'a>(&'a self) -> impl Sized;
// ^^ ^^^^^^^^^^
// ^ The method signature includes a lifetime.
// |
// ^ The RPITIT opaque type is not bounded by
// any lifetimes.
}
impl Trait for () {
fn foo<'a>(&'a self) -> impl Sized + Captures<'a> { self }
// ^^^^^^^^^^^^^^^^^^^^^^^^^
// ^ The RPIT opaque type is explicitly
// bounded by the in-scope lifetime that the
// RPIT hidden type captures.
}
```
[Playground link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&code=%23%21%5Bfeature%28return_position_impl_trait_in_trait%29%5D%0A%0Atrait+Captures%3C%27c%3E%3A+Sized+%7B%7D%0Aimpl%3C%27c%2C+T%3E+Captures%3C%27c%3E+for+T+%7B%7D%0A%0Atrait+Trait+%7B%0A++++fn+foo%3C%27a%3E%28%26%27a+self%29+-%3E+impl+Sized%3B%0A++++%2F%2F+++++%5E%5E+++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++++%5E+The+method+signature+includes+a+lifetime.%0A++++%2F%2F++++++++++++++++++++++%7C%0A++++%2F%2F++++++++++++++++++++++%5E+The+RPITIT+opaque+type+is+not+bounded+by%0A++++%2F%2F++++++++++++++++++++++any+lifetimes.%0A%7D%0A%0Aimpl+Trait+for+%28%29+%7B%0A++++fn+foo%3C%27a%3E%28%26%27a+self%29+-%3E+impl+Sized+%2B+Captures%3C%27a%3E+%7B+self+%7D%0A++++%2F%2F++++++++++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F++++++++++++++++++++++%5E+The+RPIT+opaque+type+is+explicitly%0A++++%2F%2F++++++++++++++++++++++bounded+by+the+in-scope+lifetime+that+the%0A++++%2F%2F++++++++++++++++++++++RPIT+hidden+type+captures.%0A%7D%0A)
#### Desugaring
<p><details>
<summary>Show</summary>
We can view it as *roughly* desugaring to:
```rust
#![feature(impl_trait_in_assoc_type)]
trait Captures<'c>: Sized {}
impl<'c, T> Captures<'c> for T {}
trait Trait {
type Foo<'s>: Sized where Self: 's;
// ^^^^^^^^^^^^^^
// ^ We can think of the RPITIT hidden type as a GAT.
fn foo<'a>(&'a self) -> Self::Foo<'a>;
// ^^ ^^
// ^ The method signature includes a lifetime parameter that
// we'll use to parameterize the GAT.
}
impl Trait for () {
type Foo<'s> = impl Sized + Captures<'s>;
// ^^^^^^^^^^^^^^^^^^^^^^^^^
// ^ We substitute a type containing the in-scope
// lifetime from the GAT.
fn foo<'a>(&'a self) -> Self::Foo<'a> { self }
}
```
[Playground link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&code=%23%21%5Bfeature%28impl_trait_in_assoc_type%29%5D%0A%0Atrait+Captures%3C%27c%3E%3A+Sized+%7B%7D%0Aimpl%3C%27c%2C+T%3E+Captures%3C%27c%3E+for+T+%7B%7D%0A%0Atrait+Trait+%7B%0A++++type+Foo%3C%27s%3E%3A+Sized+where+Self%3A+%27s%3B%0A++++%2F%2F+++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++%5E+We+can+think+of+the+RPITIT+hidden+type+as+a+GAT.%0A++++fn+foo%3C%27a%3E%28%26%27a+self%29+-%3E+Self%3A%3AFoo%3C%27a%3E%3B%0A++++%2F%2F+++++%5E%5E+++++++++++++++++++++++++%5E%5E%0A++++%2F%2F+++++%5E+The+method+signature+includes+a+lifetime+parameter+that%0A++++%2F%2F+++++we%27ll+use+to+parameterize+the+GAT.%0A%7D%0A%0Aimpl+Trait+for+%28%29+%7B%0A++++type+Foo%3C%27s%3E+%3D+impl+Sized+%2B+Captures%3C%27s%3E%3B%0A++++%2F%2F+++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++++++++++++%5E+We+substitute+a+type+containing+the+in-scope%0A++++%2F%2F+++++++++++++lifetime+from+the+GAT.%0A++++fn+foo%3C%27a%3E%28%26%27a+self%29+-%3E+Self%3A%3AFoo%3C%27a%3E+%7B+self+%7D%0A%7D%0A)
</details></p>
### Example C.3
```rust
#![feature(return_position_impl_trait_in_trait)]
trait Captures<'c>: Sized {}
impl<'c, T> Captures<'c> for T {}
trait Trait {
fn foo<'a>(&'a self) -> impl Sized + Captures<'a>{ self }
// ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^
// ^ The method signature includes a lifetime.
// |
// ^ The trait definition includes a default
// implementation for the method that
// captures the lifetime in the method
// signature. We must use the Captures trick
// here.
}
impl Trait for () {}
```
[Playground link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&code=%23%21%5Bfeature%28return_position_impl_trait_in_trait%29%5D%0A%0Atrait+Captures%3C%27c%3E%3A+Sized+%7B%7D%0Aimpl%3C%27c%2C+T%3E+Captures%3C%27c%3E+for+T+%7B%7D%0A%0Atrait+Trait+%7B%0A++++fn+foo%3C%27a%3E%28%26%27a+self%29+-%3E+impl+Sized+%2B+Captures%3C%27a%3E%7B+self+%7D%0A++++%2F%2F+++++%5E%5E+++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++++%5E+The+method+signature+includes+a+lifetime.%0A++++%2F%2F++++++++++++++++++++++%7C%0A++++%2F%2F++++++++++++++++++++++%5E+The+trait+definition+includes+a+default%0A++++%2F%2F++++++++++++++++++++++implementation+for+the+method+that%0A++++%2F%2F++++++++++++++++++++++captures+the+lifetime+in+the+method%0A++++%2F%2F++++++++++++++++++++++signature.++We+must+use+the+Captures+trick%0A++++%2F%2F++++++++++++++++++++++here.%0A%7D%0A%0Aimpl+Trait+for+%28%29+%7B%7D%0A)
#### Desugaring
<p><details>
<summary>Show</summary>
We can view it as *roughly* desugaring to:
```rust
trait Trait {
type Foo<'s>: Sized where Self: 's;
// ^^^^^^^^^^^^^^
// ^ We can think of the RPITIT hidden type as a GAT.
fn foo<'a>(&'a self) -> Self::Foo<'a>;
// ^^ ^^
// ^ The method signature includes a lifetime parameter that
// we'll use to parameterize the GAT.
}
impl Trait for () {
type Foo<'s> = &'s Self;
// ^^^^^^^^
// ^ We substitute a type containing the in-scope
// lifetime from the GAT.
fn foo<'a>(&'a self) -> Self::Foo<'a> { self }
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// ^ The compiler automatically produces this method
// implementation from the one in the trait definition.
}
```
[Playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=trait+Trait+%7B%0A++++type+Foo%3C%27s%3E%3A+Sized+where+Self%3A+%27s%3B%0A++++%2F%2F+++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++%5E+We+can+think+of+the+RPITIT+hidden+type+as+a+GAT.%0A++++fn+foo%3C%27a%3E%28%26%27a+self%29+-%3E+Self%3A%3AFoo%3C%27a%3E%3B%0A++++%2F%2F+++++%5E%5E+++++++++++++++++++++++++%5E%5E%0A++++%2F%2F+++++%5E+The+method+signature+includes+a+lifetime+parameter+that%0A++++%2F%2F+++++we%27ll+use+to+parameterize+the+GAT.%0A%7D%0A%0Aimpl+Trait+for+%28%29+%7B%0A++++type+Foo%3C%27s%3E+%3D+%26%27s+Self%3B%0A++++%2F%2F+++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++++++++++++%5E+We+substitute+a+type+containing+the+in-scope%0A++++%2F%2F+++++++++++++lifetime+from+the+GAT.%0A++++fn+foo%3C%27a%3E%28%26%27a+self%29+-%3E+Self%3A%3AFoo%3C%27a%3E+%7B+self+%7D%0A++++%2F%2F+%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+%5E+The+compiler+automatically+produces+this+method%0A++++%2F%2F+implementation+from+the+one+in+the+trait+definition.%0A%7D%0A)
</details></p>
### Matrix
How each rule would affect this example:
- "Strict": Not supported.
- "Current": Not supported.
- "Only Self": Not supported.
- "Any in scope": Supported.
- "Current + Copyable signature": Not supported.
- "Any in scope + Copyable signature": Supported.
## Example D: Capturing a lifetime from the Self type (alt)
### Example D.1
This example explores one of the problems that was discussed during the "RPITIT stabilization ahoy" meeting, where inconsistencies between RPITIT and RPIT lifetime capture rules means that you can't just "copy and paste" `-> impl Sized` from the trait to the impl in all cases.
```rust
#![feature(return_position_impl_trait_in_trait)]
trait Trait {
fn foo(self) -> impl Sized;
// ^^^^^^^^^^
// ^ No lifetime bounds on RPITIT opaque type in
// trait definition.
}
impl<'s> Trait for &'s () {
// ^^^^^^
// ^ Self type contains an in-scope lifetime.
fn foo(self) -> impl Sized { self }
// ^^^^^^^^^^^^^^^^^^^
// ^ The RPIT opaque type is NOT explicitly bounded
// by the in-scope lifetime that the RPIT hidden type
// captures.
}
```
[Playground link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&code=%23%21%5Bfeature%28return_position_impl_trait_in_trait%29%5D%0A%0Atrait+Trait+%7B%0A++++fn+foo%28self%29+-%3E+impl+Sized%3B%0A++++%2F%2F++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F++++++++++++++%5E+No+lifetime+bounds+on+RPITIT+opaque+type+in%0A++++%2F%2F++++++++++++++trait+definition.%0A%7D%0A%0Aimpl%3C%27s%3E+Trait+for+%26%27s+%28%29+%7B%0A++++%2F%2F+++++++++++++%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++++++++++++%5E+Self+type+contains+an+in-scope+lifetime.%0A++++fn+foo%28self%29+-%3E+impl+Sized+%7B+self+%7D%0A++++%2F%2F++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F++++++++++++++%5E+The+RPIT+opaque+type+is+NOT+explicitly+bounded%0A++++%2F%2F++++++++++++++by+the+in-scope+lifetime+that+the+RPIT+hidden+type%0A++++%2F%2F++++++++++++++captures.%0A%7D%0A)
Note that the *trait* in this example is identical to the trait in [Example A](#Example-A). Only the `impl` is different.
#### Desugaring
<p><details>
<summary>Show</summary>
We can view it as *roughly* desugaring to:
```rust
#![feature(impl_trait_in_assoc_type)]
trait Captures<'c>: Sized {}
impl<'c, T> Captures<'c> for T {}
trait Trait {
type Foo: Sized;
// ^^^^^^^^^^
// ^ We can think of the RPITIT hidden type as an
// associated type.
fn foo(self) -> Self::Foo;
}
impl<'t> Trait for &'t () {
type Foo = impl Sized;
// ^^^^^^^^^^
// ^ The ATPIT opaque type is NOT explicitly bounded by
// the in-scope lifetime that the ATPIT hidden type
// captures.
fn foo(self) -> Self::Foo { self }
}
```
[Playground link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&code=%23%21%5Bfeature%28impl_trait_in_assoc_type%29%5D%0A%0Atrait+Captures%3C%27c%3E%3A+Sized+%7B%7D%0Aimpl%3C%27c%2C+T%3E+Captures%3C%27c%3E+for+T+%7B%7D%0A%0Atrait+Trait+%7B%0A++++type+Foo%3A+Sized%3B%0A++++%2F%2F+++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++%5E+We+can+think+of+the+RPITIT+hidden+type+as+an%0A++++%2F%2F+++associated+type.%0A++++fn+foo%28self%29+-%3E+Self%3A%3AFoo%3B%0A%7D%0A%0Aimpl%3C%27t%3E+Trait+for+%26%27t+%28%29+%7B%0A++++type+Foo+%3D+impl+Sized%3B%0A++++%2F%2F+++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++++++++%5E+The+ATPIT+opaque+type+is+NOT+explicitly+bounded+by%0A++++%2F%2F+++++++++the+in-scope+lifetime+that+the+ATPIT+hidden+type%0A++++%2F%2F+++++++++captures.%0A++++fn+foo%28self%29+-%3E+Self%3A%3AFoo+%7B+self+%7D%0A%7D%0A)
</details></p>
### Example D.2
```rust
#![feature(return_position_impl_trait_in_trait)]
trait Trait {
fn foo(self) -> impl Sized { self }
// ^^^^^^^^^^^^^^^^^^^
// ^ The trait definition includes a default
// implementation for the method that captures any
// lifetimes contained in the Self type.
//
// We do NOT use the Captures trick here.
}
impl<'s> Trait for &'s () {}
// ^^^
// ^ RPITIT hidden type captures the lifetime
// contained in the Self type.
```
[Playground link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&code=%23%21%5Bfeature%28return_position_impl_trait_in_trait%29%5D%0A%0Atrait+Trait+%7B%0A++++fn+foo%28self%29+-%3E+impl+Sized+%7B+self+%7D%0A++++%2F%2F++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F++++++++++++++%5E+The+trait+definition+includes+a+default%0A++++%2F%2F++++++++++++++implementation+for+the+method+that+captures+any%0A++++%2F%2F++++++++++++++lifetimes+contained+in+the+Self+type.%0A++++%2F%2F%0A++++%2F%2F++++++++++++++We+do+NOT+use+the+Captures+trick+here.%0A%7D%0A%0Aimpl%3C%27s%3E+Trait+for+%26%27s+%28%29+%7B%7D%0A%2F%2F+++++++++++++++++%5E%5E%5E%0A%2F%2F+++++++++++++++++%5E+RPITIT+hidden+type+captures+the+lifetime%0A%2F%2F+++++++++++++++++contained+in+the+Self+type.%0A)
Note that this is related to [Example A](#Example-A).
#### Desugaring
<p><details>
<summary>Show</summary>
We can view it as *roughly* desugaring to:
```rust
#![feature(impl_trait_in_assoc_type)]
trait Captures<'c>: Sized {}
impl<'c, T> Captures<'c> for T {}
trait Trait {
type Foo: Sized;
// ^^^^^^^^^^
// ^ We can think of the RPITIT hidden type as an
// associated type.
fn foo(self) -> Self::Foo;
}
impl<'t> Trait for &'t () {
type Foo = impl Sized;
// ^^^^^^^^^^
// ^ The ATPIT opaque type is NOT explicitly bounded by
// the in-scope lifetime that the ATPIT hidden type
// captures.
fn foo(self) -> Self::Foo { self }
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// ^ The compiler automatically produces this method
// implementation from the one in the trait definition.
}
```
[Playground link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&code=%23%21%5Bfeature%28impl_trait_in_assoc_type%29%5D%0A%0Atrait+Captures%3C%27c%3E%3A+Sized+%7B%7D%0Aimpl%3C%27c%2C+T%3E+Captures%3C%27c%3E+for+T+%7B%7D%0A%0Atrait+Trait+%7B%0A++++type+Foo%3A+Sized%3B%0A++++%2F%2F+++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++%5E+We+can+think+of+the+RPITIT+hidden+type+as+an%0A++++%2F%2F+++associated+type.%0A++++fn+foo%28self%29+-%3E+Self%3A%3AFoo%3B%0A%7D%0A%0Aimpl%3C%27t%3E+Trait+for+%26%27t+%28%29+%7B%0A++++type+Foo+%3D+impl+Sized%3B%0A++++%2F%2F+++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++++++++%5E+The+ATPIT+opaque+type+is+NOT+explicitly+bounded+by%0A++++%2F%2F+++++++++the+in-scope+lifetime+that+the+ATPIT+hidden+type%0A++++%2F%2F+++++++++captures.%0A++++fn+foo%28self%29+-%3E+Self%3A%3AFoo+%7B+self+%7D%0A++++%2F%2F+%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+%5E+The+compiler+automatically+produces+this+method%0A++++%2F%2F+implementation+from+the+one+in+the+trait+definition.%0A%7D%0A)
</details></p>
### Matrix
How each rule would affect this example:
- "Strict": Not supported.
- "Current": Not supported.
- "Only Self": Not supported.
- "Any in scope": Not supported.
- "Current + Copyable signature": Supported.
- "Any in scope + Copyable signature": Supported.
## Example E: Capturing a non-Self trait input lifetime (alt)
### Example E.1
```rust
#![feature(return_position_impl_trait_in_trait)]
trait Captures<'c>: Sized {}
impl<'c, T> Captures<'c> for T {}
trait Trait<'a> {
// ^^
// ^ The trait definition includes an input lifetime
// parameter.
fn foo(&'a self) -> impl Sized;
}
impl<'a> Trait<'a> for () {
// ^^
// ^ The Self type does not include the lifetime.
fn foo(&'a self) -> impl Sized { self }
// ^^^^^^^^^^
// ^ The RPIT opaque type is NOT explicitly
// bounded by the in-scope lifetime that the RPIT
// hidden type captures.
}
```
[Playground link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&code=%23%21%5Bfeature%28return_position_impl_trait_in_trait%29%5D%0A%0Atrait+Captures%3C%27c%3E%3A+Sized+%7B%7D%0Aimpl%3C%27c%2C+T%3E+Captures%3C%27c%3E+for+T+%7B%7D%0A%0Atrait+Trait%3C%27a%3E+%7B%0A++++%2F%2F++++++%5E%5E%0A++++%2F%2F++++++%5E+The+trait+definition+includes+an+input+lifetime%0A++++%2F%2F++++++parameter.%0A++++fn+foo%28%26%27a+self%29+-%3E+impl+Sized%3B%0A%7D%0A%0Aimpl%3C%27a%3E+Trait%3C%27a%3E+for+%28%29+%7B%0A++++%2F%2F+++++++++++++++++%5E%5E%0A++++%2F%2F+++++++++++++++++%5E+The+Self+type+does+not+include+the+lifetime.%0A++++fn+foo%28%26%27a+self%29+-%3E+impl+Sized+%7B+self+%7D%0A++++%2F%2F++++++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F++++++++++++++++++%5E+The+RPIT+opaque+type+is+NOT+explicitly%0A++++%2F%2F++++++++++++++++++bounded+by+the+in-scope+lifetime+that+the+RPIT%0A++++%2F%2F++++++++++++++++++hidden+type+captures.%0A%7D%0A)
Note that the *trait* in this example is identical to the trait in [Example B](#Example-B). Only the `impl` is different.
#### Desugaring
<p><details>
<summary>Show</summary>
We can view it as *roughly* desugaring to:
```rust
#![feature(impl_trait_in_assoc_type)]
trait Captures<'c>: Sized {}
impl<'c, T> Captures<'c> for T {}
trait Trait<'a> {
type Foo: Sized;
// ^^^^^^^^^^
// ^ We can think of the RPITIT hidden type as an
// associated type.
fn foo(&'a self) -> Self::Foo;
}
impl<'a> Trait<'a> for () {
type Foo = impl Sized;
// ^^^^^^^^^^
// ^ The ATPIT opaque type is NOT explicitly bounded by
// the in-scope lifetime that the ATPIT hidden type
// captures.
fn foo(&'a self) -> Self::Foo { self }
}
```
[Playground link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&code=%23%21%5Bfeature%28impl_trait_in_assoc_type%29%5D%0A%0Atrait+Captures%3C%27c%3E%3A+Sized+%7B%7D%0Aimpl%3C%27c%2C+T%3E+Captures%3C%27c%3E+for+T+%7B%7D%0A%0Atrait+Trait%3C%27a%3E+%7B%0A++++type+Foo%3A+Sized%3B%0A++++%2F%2F+++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++%5E+We+can+think+of+the+RPITIT+hidden+type+as+an%0A++++%2F%2F+++associated+type.%0A++++fn+foo%28%26%27a+self%29+-%3E+Self%3A%3AFoo%3B%0A%7D%0A%0Aimpl%3C%27a%3E+Trait%3C%27a%3E+for+%28%29+%7B%0A++++type+Foo+%3D+impl+Sized%3B%0A++++%2F%2F+++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++++++++%5E+The+ATPIT+opaque+type+is+NOT+explicitly+bounded+by%0A++++%2F%2F+++++++++the+in-scope+lifetime+that+the+ATPIT+hidden+type%0A++++%2F%2F+++++++++captures.%0A++++fn+foo%28%26%27a+self%29+-%3E+Self%3A%3AFoo+%7B+self+%7D%0A%7D%0A)
</details></p>
### Example E.2
```rust
#![feature(return_position_impl_trait_in_trait)]
trait Captures<'c>: Sized {}
impl<'c, T> Captures<'c> for T {}
trait Trait<'a> {
// ^^
// ^ The trait definition includes an input lifetime
// parameter.
fn foo(&'a self) -> impl Sized { self }
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// ^ The trait definition includes a default implementation for
// the method that captures the input lifetime. The lifetime is
// captured implicitly.
}
impl<'a> Trait<'a> for () {}
// ^^^
// ^ RPITIT hidden type captures the lifetime
// contained in the Self type.
```
[Playground link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&code=%23%21%5Bfeature%28return_position_impl_trait_in_trait%29%5D%0A%0Atrait+Captures%3C%27c%3E%3A+Sized+%7B%7D%0Aimpl%3C%27c%2C+T%3E+Captures%3C%27c%3E+for+T+%7B%7D%0A%0Atrait+Trait%3C%27a%3E+%7B%0A++++%2F%2F++++++%5E%5E%0A++++%2F%2F++++++%5E+The+trait+definition+includes+an+input+lifetime%0A++++%2F%2F++++++parameter.%0A++++fn+foo%28%26%27a+self%29+-%3E+impl+Sized+%7B+self+%7D%0A++++%2F%2F+%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+%5E+The+trait+definition+includes+a+default+implementation+for%0A++++%2F%2F+the+method+that+captures+the+input+lifetime.++The+lifetime+is%0A++++%2F%2F+captured+implicitly.%0A%7D%0A%0Aimpl%3C%27a%3E+Trait%3C%27a%3E+for+%28%29+%7B%7D%0A%2F%2F+++++++++++++%5E%5E%5E%0A%2F%2F+++++++++++++%5E+RPITIT+hidden+type+captures+the+lifetime%0A%2F%2F+++++++++++++contained+in+the+Self+type.%0A)
Note that this is related to [Example B](#Example-B).
#### Desugaring
<p><details>
<summary>Show</summary>
We can view it as *roughly* desugaring to:
```rust
trait Trait<'a> {
type Foo: Sized;
// ^^^^^^^^^^
// ^ We can think of the RPITIT hidden type as an
// associated type.
fn foo(&'a self) -> Self::Foo;
}
impl<'a> Trait<'a> for () {
type Foo = &'a Self;
// ^^^^^^^^
// ^ We substitute a type containing the in-scope lifetime
// from the impl for the associated type.
fn foo(&'a self) -> Self::Foo { self }
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// ^ The compiler automatically produces this method
// implementation from the one in the trait definition.
}
```
[Playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=trait+Trait%3C%27a%3E+%7B%0A++++type+Foo%3A+Sized%3B%0A++++%2F%2F+++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++%5E+We+can+think+of+the+RPITIT+hidden+type+as+an%0A++++%2F%2F+++associated+type.%0A++++fn+foo%28%26%27a+self%29+-%3E+Self%3A%3AFoo%3B%0A%7D%0A%0Aimpl%3C%27a%3E+Trait%3C%27a%3E+for+%28%29+%7B%0A++++type+Foo+%3D+%26%27a+Self%3B%0A++++%2F%2F+++++++++%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++++++++%5E+We+substitute+a+type+containing+the+in-scope+lifetime%0A++++%2F%2F+++++++++from+the+impl+for+the+associated+type.%0A++++fn+foo%28%26%27a+self%29+-%3E+Self%3A%3AFoo+%7B+self+%7D%0A++++%2F%2F+%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+%5E+The+compiler+automatically+produces+this+method%0A++++%2F%2F+implementation+from+the+one+in+the+trait+definition.%0A%7D%0A)
</details></p>
### Matrix
How each rule would affect this example:
- "Strict": Not supported.
- "Current": Not supported.
- "Only Self": Not supported.
- "Any in scope": Not supported.
- "Current + Copyable signature": Supported.
- "Any in scope + Copyable signature": Supported.
## Example F: Capturing a method lifetime (alt)
### Example F.1
```rust
#![feature(return_position_impl_trait_in_trait)]
trait Trait {
fn foo<'a>(&'a self) -> impl Sized;
// ^^ ^^^^^^^^^^
// ^ The method signature includes a lifetime.
// |
// ^ The RPITIT opaque type is not bounded by
// any lifetimes.
}
impl Trait for () {
fn foo<'a>(&'a self) -> impl Sized { self }
// ^^^^^^^^^^
// ^ The RPIT opaque type is NOT explicitly
// bounded by the in-scope lifetime that the
// RPIT hidden type captures.
}
```
[Playground link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&code=%23%21%5Bfeature%28return_position_impl_trait_in_trait%29%5D%0A%0Atrait+Trait+%7B%0A++++fn+foo%3C%27a%3E%28%26%27a+self%29+-%3E+impl+Sized%3B%0A++++%2F%2F+++++%5E%5E+++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++++%5E+The+method+signature+includes+a+lifetime.%0A++++%2F%2F++++++++++++++++++++++%7C%0A++++%2F%2F++++++++++++++++++++++%5E+The+RPITIT+opaque+type+is+not+bounded+by%0A++++%2F%2F++++++++++++++++++++++any+lifetimes.%0A%7D%0A%0Aimpl+Trait+for+%28%29+%7B%0A++++fn+foo%3C%27a%3E%28%26%27a+self%29+-%3E+impl+Sized+%7B+self+%7D%0A++++%2F%2F++++++++++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F++++++++++++++++++++++%5E+The+RPIT+opaque+type+is+NOT+explicitly%0A++++%2F%2F++++++++++++++++++++++bounded+by+the+in-scope+lifetime+that+the%0A++++%2F%2F++++++++++++++++++++++RPIT+hidden+type+captures.%0A%7D%0A)
Note that the *trait* in this example is identical to the trait in [Example C](#Example-C). Only the `impl` is different.
#### Desugaring
<p><details>
<summary>Show</summary>
We can view it as *roughly* desugaring to:
```rust
#![feature(impl_trait_in_assoc_type)]
trait Captures<'c>: Sized {}
impl<'c, T> Captures<'c> for T {}
trait Trait {
type Foo<'s>: Sized where Self: 's;
// ^^^^^^^^^^^^^^
// ^ We can think of the RPITIT hidden type as a GAT.
fn foo<'a>(&'a self) -> Self::Foo<'a>;
// ^^ ^^
// ^ The method signature includes a lifetime parameter that
// we'll use to parameterize the GAT.
}
impl Trait for () {
type Foo<'s> = impl Sized;
// ^^^^^^^^^^^^^^^^^^^^
// ^ The ATPIT opaque type is NOT explicitly bounded by the
// in-scope lifetime that the ATPIT hidden type captures.
fn foo<'a>(&'a self) -> Self::Foo<'a> { self }
}
```
[Playground link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&code=%23%21%5Bfeature%28impl_trait_in_assoc_type%29%5D%0A%0Atrait+Captures%3C%27c%3E%3A+Sized+%7B%7D%0Aimpl%3C%27c%2C+T%3E+Captures%3C%27c%3E+for+T+%7B%7D%0A%0Atrait+Trait+%7B%0A++++type+Foo%3C%27s%3E%3A+Sized+where+Self%3A+%27s%3B%0A++++%2F%2F+++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++%5E+We+can+think+of+the+RPITIT+hidden+type+as+a+GAT.%0A++++fn+foo%3C%27a%3E%28%26%27a+self%29+-%3E+Self%3A%3AFoo%3C%27a%3E%3B%0A++++%2F%2F+++++%5E%5E+++++++++++++++++++++++++%5E%5E%0A++++%2F%2F+++++%5E+The+method+signature+includes+a+lifetime+parameter+that%0A++++%2F%2F+++++we%27ll+use+to+parameterize+the+GAT.%0A%7D%0A%0Aimpl+Trait+for+%28%29+%7B%0A++++type+Foo%3C%27s%3E+%3D+impl+Sized%3B%0A++++%2F%2F+++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++%5E+The+ATPIT+opaque+type+is+NOT+explicitly+bounded+by+the%0A++++%2F%2F+++in-scope+lifetime+that+the+ATPIT+hidden+type+captures.%0A++++fn+foo%3C%27a%3E%28%26%27a+self%29+-%3E+Self%3A%3AFoo%3C%27a%3E+%7B+self+%7D%0A%7D%0A)
</details></p>
### Example F.2
```rust
#![feature(return_position_impl_trait_in_trait)]
trait Trait {
fn foo<'a>(&'a self) -> impl Sized { self }
// ^^ ^^^^^^^^^^^^^^^^^^^
// ^ The method signature includes a lifetime.
// |
// ^ The trait definition includes a default
// implementation for the method that
// captures the lifetime in the method
// signature.
//
// We do NOT use the Captures trick here.
}
impl Trait for () {}
```
[Playground link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&code=%23%21%5Bfeature%28return_position_impl_trait_in_trait%29%5D%0A%0Atrait+Trait+%7B%0A++++fn+foo%3C%27a%3E%28%26%27a+self%29+-%3E+impl+Sized+%7B+self+%7D%0A++++%2F%2F+++++%5E%5E+++++++++++++++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++++%5E+The+method+signature+includes+a+lifetime.%0A++++%2F%2F++++++++++++++++++++++%7C%0A++++%2F%2F++++++++++++++++++++++%5E+The+trait+definition+includes+a+default%0A++++%2F%2F++++++++++++++++++++++implementation+for+the+method+that%0A++++%2F%2F++++++++++++++++++++++captures+the+lifetime+in+the+method%0A++++%2F%2F++++++++++++++++++++++signature.%0A++++%2F%2F%0A++++%2F%2F++++++++++++++++++++++We+do+NOT+use+the+Captures+trick+here.%0A%7D%0A%0Aimpl+Trait+for+%28%29+%7B%7D%0A)
Note that this is related to [Example C](#Example-C).
#### Desugaring
<p><details>
<summary>Show</summary>
We can view it as *roughly* desugaring to:
```rust
#![feature(impl_trait_in_assoc_type)]
trait Captures<'c>: Sized {}
impl<'c, T> Captures<'c> for T {}
trait Trait {
type Foo<'s>: Sized where Self: 's;
// ^^^^^^^^^^^^^^
// ^ We can think of the RPITIT hidden type as a GAT.
fn foo<'a>(&'a self) -> Self::Foo<'a>;
// ^^ ^^
// ^ The method signature includes a lifetime parameter that
// we'll use to parameterize the GAT.
}
impl Trait for () {
type Foo<'s> = impl Sized;
// ^^^^^^^^^^^^^^^^^^^^
// ^ The ATPIT opaque type is NOT explicitly bounded by the
// in-scope lifetime that the ATPIT hidden type captures.
fn foo<'a>(&'a self) -> Self::Foo<'a> { self }
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// ^ The compiler automatically produces this method
// implementation from the one in the trait definition.
}
```
[Playground link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&code=%23%21%5Bfeature%28impl_trait_in_assoc_type%29%5D%0A%0Atrait+Captures%3C%27c%3E%3A+Sized+%7B%7D%0Aimpl%3C%27c%2C+T%3E+Captures%3C%27c%3E+for+T+%7B%7D%0A%0Atrait+Trait+%7B%0A++++type+Foo%3C%27s%3E%3A+Sized+where+Self%3A+%27s%3B%0A++++%2F%2F+++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++%5E+We+can+think+of+the+RPITIT+hidden+type+as+a+GAT.%0A++++fn+foo%3C%27a%3E%28%26%27a+self%29+-%3E+Self%3A%3AFoo%3C%27a%3E%3B%0A++++%2F%2F+++++%5E%5E+++++++++++++++++++++++++%5E%5E%0A++++%2F%2F+++++%5E+The+method+signature+includes+a+lifetime+parameter+that%0A++++%2F%2F+++++we%27ll+use+to+parameterize+the+GAT.%0A%7D%0A%0Aimpl+Trait+for+%28%29+%7B%0A++++type+Foo%3C%27s%3E+%3D+impl+Sized%3B%0A++++%2F%2F+++%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+++%5E+The+ATPIT+opaque+type+is+NOT+explicitly+bounded+by+the%0A++++%2F%2F+++in-scope+lifetime+that+the+ATPIT+hidden+type+captures.%0A++++fn+foo%3C%27a%3E%28%26%27a+self%29+-%3E+Self%3A%3AFoo%3C%27a%3E+%7B+self+%7D%0A++++%2F%2F+%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%5E%0A++++%2F%2F+%5E+The+compiler+automatically+produces+this+method%0A++++%2F%2F+implementation+from+the+one+in+the+trait+definition.%0A%7D%0A)
</details></p>
### Matrix
How each rule would affect this example:
- "Strict": Not supported.
- "Current": Not supported.
- "Only Self": Not supported.
- "Any in scope": Not supported.
- "Current + Copyable signature": Not supported.
- "Any in scope + Copyable signature": Supported.
# Matrix of possibilities
| | A | B | C | D | E | F |
| - | - | - | - | - | - | - |
| "strict" | N | N | N | N | N | N |
| "current" | Y | Y | N | N | N | N |
| "only self" | Y | N | N | N | N | N |
| "any in scope" | Y | Y | Y | N | N | N |
| "current+copyable" | Y | Y | N | Y | Y | N |
| "any+copyable" | Y | Y | Y | Y | Y | Y |
## "Strict"
This is strict adherence to the RPIT capture rules. This allows no lifetimes to be captured.
Advantages:
* Maximum consistency with RPIT rules now
Drawbacks:
* Very inflexible, essentially cannot use any impl whose self type is generic over lifetime.
Changes to be made to the compiler:
Need to modify rpitit lifetime mapping to deny all impl header lifetimes unless captured in bounds, which isn't difficult.
## "Current"
This is the current behavior implemented for RPITITs on master as of [#113182](https://github.com/rust-lang/rust/pull/113182). It allows an impl's RPITIT type to capture any lifetimes mentioned in the impl header, both from the self type and from the trait generic.
Advantages:
* Allows users to write impls that capture the self type of an impl, allowing users to write impls that are generic over lifetimes even if the trait isn't necessarily generic over lifetimes.
Drawbacks:
* Inconsistency with the outlives rules of an inherent impl.
* As demonstrated by example "D", this has no effect on the capture rules of *regular* RPITs that show up in impls. That is, the `-> impl Trait` in an impl still needs to explicitly say that it captures all of the lifetimes in its hidden type.
Changes to be made to the compiler:
* None
## "Only Self"
Modification to the above strategy to only allow capturing lifetimes that are mentioned directly in the impl's self type.
From last meeting, it seems we're not exactly keen of this solution, so I won't flesh it out too much.
Modifications to the compiler to enable this are not difficult, though.
## "Any in scope"
This allows users to write impls that capture lifetimes from the method inputs as well, as demonstrated by example "C".
Advantages:
* Can capture more lifetimes, which means more expressivity on the impl side
Disadvantages:
* The desugaring of an RPIT into a GAT needs to now capture *all* of the method lifetimes, rather than just the lifetimes that are mentioned in the method's bounds.
* This has the same problem as "current", which is that RPITs in the impl are still limited by their own set of captures rules.
Changes to the compiler:
* Lowering the RPITIT (in the trait) needs to be modified to capture all early- and late-bound lifetimes of the opaque, even if they're not mentioned in the bounds.
## "Current + Copyable signature"
"copyable signature" is what I call the property of being able to copy everything after the `->` in the trait directly into the impl without having to add extra lifetimes.
Advantages:
* Avoids having to add additional `+ Captures<'self_lifetime>` required in code like example "A".
Disadvantages:
* Same as "current"
* inconsistency with RPITs in free/inherent methods, since RPITs in impls are allowed to mention all of the lifetimes in an impl header without having to mention them in their bounds.
* No way to "opt out" of captures without `#[refine]`, and we don't have a syntax for that other than concrete types or `+ 'static`. Implication: Pushing more people toward explicit GATs, ATPIT.
Changes to the compiler:
* RPITs *in impls* are made to capture all of the lifetimes mentioned in their impl header.
## "Any in scope + Copyable signature"
Advantages:
* Maximum flexibility with lifetimes that a RPIT in a trait impl is able to capture.
* May move RPITITs + RPITs in trait impls to a space that we want to eventually move *all* RPITs.
Disadvantages:
* Same as "any in scope", except example "D" works.
* inconsistency with RPITs in free/inherent methods.
Changes to the compiler:
* Same as "any in scope" + "current + copyable signature".
# Feedback
## tmandry's opinion
Given that we rule out being consistent with inherent impls, there's a 2x2 matrix being decided right now: Copyable signature or no, Any in scope or no.
Argument for "copyable signature": It's much easier to explain and prevents people from _depending_ on particular behavior that you didn't know you were opting into when you copied the signature.[^opting-in] Plus, we don't think we can give you a serviceable error message if you copy the signature, which is important to consider.
We should go with "Current + Copyable signature", and consider the "Any in scope" separately as an edition question. Capture rules for generic lifetimes on TAIT/ITIAT items should be consistent with the "Any in scope" question.
ITIAT should be changed to allow capturing lifetimes in the parent scope, for consistency with the "Current" behavior. Users who do not want to capture any implicit lifetimes should use an associated type, or `#[refine]`, set to a TAIT outside the trait impl.
There's later decisions about changing the behavior of inherent impls, and (as I said before) changing the "any in scope" question.
[^opting-in]: Specifically, you as an impl author opted into not capturing any lifetimes from the impl when you failed to write `+ Captures<'a>` for those lifetimes. (In "Original" these would be allowed by the trait even though they are not made explicit.) Users of your impl are then allowed to rely on you not capturing those lifetimes, though you could have captured them if you wrote the Captures bound. This seems extremely surprising.
## TC summary
Here's how I would summarize things:
- If we view the RPITIT as similar to an associated type / GAT, then "any in scope" seems consistent with current stable behavior and the obvious desugaring. It seems conservative in that sense.
- In the presence of refinement, "any in scope" does not lead to overcapturing issues that must be resolved through desugaring (because it already essentially works like GATs/ATs).
- "Copyable signature" *does* raise overcapturing issues that users would need to address by manual desugaring to TAITs.
- Because "copyable signature" affects RPIT in the impl, that raises additional consistency questions.
- Adopting "copyable signature" probably commits us to a direction where RPIT (over an edition), TAIT, and ATPIT would automatically capture all in-scope lifetime parameters (the "big question").
- If that is or may be what we want to do, we need to answer the question of whether we should make RPITIT (RPIT in the trait impl), TAIT, and ATPIT work that way in this edition and accept the inconsistency with RPIT, or whether we should make RPITIT (RPIT in the trait impl), TAIT, and ATPIT work like RPIT does now for this edition and fix all of them together over an edition.
- If we wish for RPITIT to move quickly, we either need to answer that "big question" quickly or we need to decide quickly to punt the question to an edition and go with "any in scope" (without "copyable signature").