Michael Goulet
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invitee
    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Versions and GitHub Sync Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
Invitee
Publish Note

Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

Your note will be visible on your profile and discoverable by anyone.
Your note is now live.
This note is visible on your profile and discoverable online.
Everyone on the web can find and read all notes of this public team.
See published notes
Unpublish note
Please check the box to agree to the Community Guidelines.
View profile
Engagement control
Commenting
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
  • Everyone
Suggest edit
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
Emoji Reply
Enable
Import from Dropbox Google Drive Gist Clipboard
   owned this note    owned this note      
Published Linked with GitHub
Subscribed
  • Any changes
    Be notified of any changes
  • Mention me
    Be notified of mention me
  • Unsubscribe
Subscribe
--- 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 https://hackmd.io/zgairrYRSACgTeZHP1x0Zg?both#// 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").

Import from clipboard

Paste your markdown or webpage here...

Advanced permission required

Your current role can only read. Ask the system administrator to acquire write and comment permission.

This team is disabled

Sorry, this team is disabled. You can't edit this note.

This note is locked

Sorry, only owner can edit this note.

Reach the limit

Sorry, you've reached the max length this note can be.
Please reduce the content or divide it to more notes, thank you!

Import from Gist

Import from Snippet

or

Export to Snippet

Are you sure?

Do you really want to delete this note?
All users will lose their connection.

Create a note from template

Create a note from template

Oops...
This template has been removed or transferred.
Upgrade
All
  • All
  • Team
No template.

Create a template

Upgrade

Delete template

Do you really want to delete this template?
Turn this template into a regular note and keep its content, versions, and comments.

This page need refresh

You have an incompatible client version.
Refresh to update.
New version available!
See releases notes here
Refresh to enjoy new features.
Your user state has changed.
Refresh to load new user state.

Sign in

Forgot password

or

By clicking below, you agree to our terms of service.

Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
Wallet ( )
Connect another wallet

New to HackMD? Sign up

Help

  • English
  • 中文
  • Français
  • Deutsch
  • 日本語
  • Español
  • Català
  • Ελληνικά
  • Português
  • italiano
  • Türkçe
  • Русский
  • Nederlands
  • hrvatski jezik
  • język polski
  • Українська
  • हिन्दी
  • svenska
  • Esperanto
  • dansk

Documents

Help & Tutorial

How to use Book mode

Slide Example

API Docs

Edit in VSCode

Install browser extension

Contacts

Feedback

Discord

Send us email

Resources

Releases

Pricing

Blog

Policy

Terms

Privacy

Cheatsheet

Syntax Example Reference
# Header Header 基本排版
- Unordered List
  • Unordered List
1. Ordered List
  1. Ordered List
- [ ] Todo List
  • Todo List
> Blockquote
Blockquote
**Bold font** Bold font
*Italics font* Italics font
~~Strikethrough~~ Strikethrough
19^th^ 19th
H~2~O H2O
++Inserted text++ Inserted text
==Marked text== Marked text
[link text](https:// "title") Link
![image alt](https:// "title") Image
`Code` Code 在筆記中貼入程式碼
```javascript
var i = 0;
```
var i = 0;
:smile: :smile: Emoji list
{%youtube youtube_id %} Externals
$L^aT_eX$ LaTeX
:::info
This is a alert area.
:::

This is a alert area.

Versions and GitHub Sync
Get Full History Access

  • Edit version name
  • Delete

revision author avatar     named on  

More Less

Note content is identical to the latest version.
Compare
    Choose a version
    No search result
    Version not found
Sign in to link this note to GitHub
Learn more
This note is not linked with GitHub
 

Feedback

Submission failed, please try again

Thanks for your support.

On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

Please give us some advice and help us improve HackMD.

 

Thanks for your feedback

Remove version name

Do you want to remove this version name and description?

Transfer ownership

Transfer to
    Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

      Link with GitHub

      Please authorize HackMD on GitHub
      • Please sign in to GitHub and install the HackMD app on your GitHub repo.
      • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
      Learn more  Sign in to GitHub

      Push the note to GitHub Push to GitHub Pull a file from GitHub

        Authorize again
       

      Choose which file to push to

      Select repo
      Refresh Authorize more repos
      Select branch
      Select file
      Select branch
      Choose version(s) to push
      • Save a new version and push
      • Choose from existing versions
      Include title and tags
      Available push count

      Pull from GitHub

       
      File from GitHub
      File from HackMD

      GitHub Link Settings

      File linked

      Linked by
      File path
      Last synced branch
      Available push count

      Danger Zone

      Unlink
      You will no longer receive notification when GitHub file changes after unlink.

      Syncing

      Push failed

      Push successfully