Impl Trait Everywhere Initiative
      • 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
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • 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
    • Note Insights New
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Help
Menu
Options
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
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Write
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • 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
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    --- title: ITE meeting 2023-10-26 tags: impl-trait-everywhere, triage-meeting, minutes date: 2023-10-26 discussion: https://rust-lang.zulipchat.com/#narrow/stream/315482-t-compiler.2Fetc.2Fopaque-types/topic/ITE.20triage.20meeting.202023-10-26 url: https://hackmd.io/qiy4_I3WRYyhpYvjbYBrew --- # ITE meeting agenda - Meeting date: 2023-10-26 ## Attendance - People: TC, CE, tmandry ## Meeting roles - Minutes: TC ## Announcements or custom items ### Minimal TAIT stabilization proposal from T-types (Mini-TAIT) [TC:] The T-types meetup on 2023-10-11 included a discussion over the challenges that TAIT presents for the new trait solver and how to overcome those challenges. The result of the session was a consensus proposal for a minimal stabilization of TAIT that satisfies all T-types concerns. We'll describe that consensus proposal below. #### Signature restriction In the [last push](https://hackmd.io/oTC4J-2XRnukxC7lSq_PVA) to stabilize TAIT, we had introduced a signature restriction. This restriction requires that for functions and methods that constrain a hidden type, the opaque type must fall within a type that appears in the signature of the function or method. This was done, among other reasons, as it improves the performance of the compiler and other tools such as rust-analyzer. In the implementation, it was later decided that, for now, projections would not be normalized ahead of performing this check. This was done to make the implementation simpler. In the original proposal, this signature restriction was carefully specified such that it could be removed in a backward compatible way. That is, we were leaving the door open for T-lang to later decide to remove the signature restriction and allow any function within the defining scope to constrain the hidden type. The main cost of leaving this door open is that, under the current implementation, we would emit cycle errors that would not be emitted if we were to close this door. In the T-types proposal, we would close this door. The signature restriction would become a part of TAIT that could not be removed in a backward compatible way. This seems safe as, even aside from type system concerns, it's unlikely that T-lang would ever want to walk through this door for tooling and other reasons. The signature restriction does not limit expressiveness, and nearly all common uses of TAIT trivially pass the signature restriction. <details> <summary>Caveat on "nearly"</summary> --- There are two main cases where the signature restriction has to be explicitly considered. On is when defining static items from within a function. The other is when attempting to define an opaque type by passing a concrete type to a function that accepts the opaque type as an argument. In both cases, there are two main solutions. One is to add `where Opaqque: Any` bounds on the function that wants to be defining. The other is to use the builder pattern. --- </details><br/> As we'll describe below, combined with the other aspects of this proposal, the net result is that we would not emit *any* spurious cycle errors in the new solver. Any cycle error emitted would be a *real* cycle error, similar to the other ones that we emit in Rust today. #### Normalizes to opaque restriction As mentioned, for implementation reasons, the signature restriction has been constrained such that projections are not normalized ahead of the check. We want to leave room to later make this check smarter and to allow some level of normalization to occur. Consequently, under this proposal, we would reject code with an error if any projection within the signature of an item normalized to an opaque type for which the item is within the defining scope. E.g., this would be an error: ```rust,compile_fail #![feature(type_alias_impl_trait)] type Opaque = impl Sized; trait Trait { type Assoc; } struct Type; impl Trait for Type { type Assoc = Opaque; } fn define() -> Opaque {} fn error(_: <Type as Trait>::Assoc) {} // ~^ ERROR item signature contains opaque type through projection ``` We would plan to lift this restriction incrementally for any classes of projections that the signature restriction was later extended to allow. #### Once modulo regions restriction Consider: ```rust #![feature(type_alias_impl_trait)] type Tait<'x> = impl Sized; fn define<'a, 'b>(x: &'a (), y: &'b ()) -> (Tait<'a>, Tait<'b>) { (x, y) } ``` Conceptually, this function is constraining the hidden type for the opaque `for<'x> Tait<'x>` to `&'x ()`. It constrains the hidden type twice, but that should be OK because each constraint is to the same type. The current trait solver accepts this code. <details> <summary>Details</summary> --- For the example above, the old trait solver works as follows: In `typeck`, we observe that: ``` Tait<'a> := &'a () Tait<'b> := &'b () ``` Then, in `borrowck`, we perform remapping and observe that: ``` Tait<'a> := &'a () ~~> Tait<'x> := &'x () Tait<'b> := &'b () ~~> Tait<'x> := &'x () ``` Since these types are equal after remapping, `borrowck` is happy and this code is accepted. --- </details><br/> The new solver does not. Furthermore, it's anticipated that the new solver will *never* accept this code for architectural reasons. In the new trait solver, we canonicalize all lifetimes to unique existential lifetimes in the root universe. This is to make sure that we avoid any lifetime dependence when proving obligations. This is architecturally required for `borrowck` and codegen to be sane and to not have responses that change between those steps and HIR `typeck`. As a bonus, this approach is also better for caching. <details> <summary>Details</summary> --- For the example above, the new trait solver works as follows: It observes that `Tait<'a>` must be equal to `&'a ()`. Since we haven't inferred anything yet for `Tait<'a>`, we register the definition `Tait<'a> := &'a ()` in our opaque type storage. We then notice that `Tait<'b>` must be equal to `&'b ()`. Since we've already inferred that `Tait<'a> := &'a ()`, we do two things: First, we require that the opaque signatures `Tait<'b> = Tait<'a>`. This requires that `'b = 'a`. Next, we set the hidden types `&'b () = &'a ()`. Note that this also requires `'b = 'a`. As in the old solver, this happens twice, once during `typeck` and once during `borrowck`. During `typeck`, we throw away the regions. However, during `borrowck`, we fail to prove that `'a = 'b`, which results in the error. E.g.: ```rust,compile_fail #![feature(type_alias_impl_trait)] type Tait<'x> = impl Sized; fn define<'a, 'b>(x: &'a (), y: &'b ()) -> (Tait<'a>, Tait<'b>) { // ~^ ERROR lifetime may not live long enough // ~| NOTE requires that `'a` must outlive `'b` // ~| NOTE requires that `'b` must outlive `'a` (x, y) } ``` --- ```rust type Tait<'a> = impl Sized; fn foo<'a: 'b, 'b: 'a>() -> Tait<'a> { let x: Tait<'a> = [1, 2, 3]; { let y = foo::<'b, 'a>(); // we know y is [i32; 3] y.into_iter(); } x } ``` </details><br/> We propose a restriction such that, within a single item, multiple defining uses of an opaque type that only differ by lifetime arguments, you must be able to prove that the those lifetime arguments are equal. The restriction is scoped within a single item because borrow checking happens at the level of single items and that is where we do opaque type inference. This decision would not, strictly speaking, close a door on the *language* side to later allowing this. However, T-types is asking for T-lang to consider this door as closed in a practical sense given the design of the new trait solver. <details> <summary>Examples</summary> --- This is the canonical example of what cannot be accepted by the new trait solver and that we will consequently disallow: ```rust,compile_fail #![feature(type_alias_impl_trait)] type Tait<'x> = impl Sized; fn define<'a, 'b>(_: &'a (), _: &'b ()) -> (Tait<'a>, Tait<'b>) { // ~^ ERROR lifetime may not live long enough // ~| NOTE requires that `'a` must outlive `'b` // ~| NOTE requires that `'b` must outlive `'a` ((), ()) } ``` Note that it doesn't matter whether or not the hidden type actually uses these regions. If due to the bounds, we can prove that these regions are in fact equal, then we will allow the code. E.g.: ```rust #![feature(type_alias_impl_trait)] type Tait<'x> = impl Sized; fn define<'a: 'b, 'b: 'a>(_: &'a (), _: &'b ()) -> (Tait<'a>, Tait<'b>) { ((), ()) } ``` Note that this restriction only applies to lifetime parameters. It's OK for defined opaque types to be equal modulo types. E.g, this is OK: ```rust #![feature(type_alias_impl_trait)] type Tait<X> = impl Sized; fn define<A, B>(_: A, _: B) -> (Tait<A>, Tait<B>) { ((), ()) } ``` Note that, aside from the proposed temporary restriction that only one item may define an opaque type, it would be OK for two separate items to independently define an opaque type twice in a way that is equal modulo regions. E.g., this would be OK aside from the other restriction: ```rust #![feature(type_alias_impl_trait)] type Tait<'x> = impl Sized; fn define_1<'x>(_: &'x ()) -> Tait<'x> {} fn define_2<'x>(_: &'x ()) -> Tait<'x> {} ``` Note that it's OK for non-defining uses of the opaque type to use the opaque types in a way that is equal modulo regions. E.g., this is OK and works in both the new and the old solver: ```rust #![feature(type_alias_impl_trait)] use inner::*; mod inner { pub type Tait<'x> = impl Sized; pub fn define<'x>(_: &'x ()) -> Tait<'x> {} } pub fn non_defining<'a, 'b>( x: &'a (), y: &'b (), ) -> (Tait<'a>, Tait<'b>) { (define(x), define(y)) } ``` Even if `non_defining` were in the defining scope, this would be allowed under this rule because the opaque type is only defined once, though it would be currently disallowed because of the rule that requires items that mention opaque types in their signatures within the defining scope to define them. E.g., this would be allowed once the other restriction is lifted: ```rust #![feature(type_alias_impl_trait)] pub type Tait<'x> = impl Sized; pub fn define<'x>(_: &'x ()) -> Tait<'x> {} pub fn non_defining<'a, 'b>( x: &'a (), y: &'b (), ) -> (Tait<'a>, Tait<'b>) { (define(x), define(y)) } ``` Note, however, that this currently results in an overflow on the new solver. We believe this will be fixed by [#116369](https://github.com/rust-lang/rust/pull/116369). In any case, this would be supported on a best-effort basis and may be subject to compiler limitations. --- </details> #### Mention must define restriction Currently a function that passes the signature restriction *may* or *may not* actually constrain the hidden type. Such a function may, e.g., simply pass through the opaque type without constraining its hidden type. E.g.: ```rust #![feature(type_alias_impl_trait)] type Tait = impl Sized; fn define() -> Tait {} fn passthrough(x: Tait) -> Tait { x } ``` There are many use-cases for this. However, we propose that, for now, any function or method within the defining scope that passes the signature restriction *must* constrain the hidden type of any opaque type contained within a type that appears in the signature. This restriction is helpful because, due to lazy normalization and the new trait solver being more *complete*, this is an area where there could be various subtle differences in what code might be accepted by the new and old trait solver. This is also an area where the old trait solver is underspecified, though it's believed that *could* be fixed. We would plan to later lift this restriction. #### Only one item may define restriction Currently any number of items may constrain the hidden type of an opaque. E.g.: ```rust #![feature(type_alias_impl_trait)] type Tait = impl Sized; fn wrap(x: ()) -> Tait { x } fn unwrap(x: Tait) -> () { x } ``` There are many use-cases for this. However, we propose that, for now, only one item may constrain any single opaque type to a particular hidden type. This restriction is somewhat arbitrary. We have the machinery to allow this. However, adding this restriction will for now help us to more easily craft helpful error messages. We would plan to later lift this restriction. #### Properties of this proposal The main virtues of this proposal are twofold: 1. All code that might be accepted by the old trait solver but rejected by the new trait solver is disallowed. 2. All cycle errors produced by the new trait solver will be *real* cycle errors. One of the major pain points of TAIT has been the presence of surprising cycle errors within the defining scope due to current implementation limitations surrounding the leakage of auto traits. Under this proposal, these surprising cycle errors will disappear *entirely* under the new solver, even after we lift the restrictions that we plan to lift. #### Future work: Constraining outside of the defining scope This proposal is forward compatible with future work that would allow the hidden type to be constrained within the same crate but outside of the defining scope using a new syntax. E.g.: ```rust #![feature(type_alias_impl_trait)] #![feature(todo_define_tait_anywhere_in_crate)] use taits::*; mod taits { type Tait<T> = impl Sized; } fn define<T>() where constrains(Tait<T>) {} ``` One useful property of such future work is that those who wish to not rely on the signature restriction and wish to always explicitly annotate which functions may constrain the hidden type of some opaque may do so simply by placing their TAITs in a submodule as above. #### Acknowledgments Thanks to Oli (@oli) and Michael Goulet (@compiler-errors) for helpful discussions and insights on this topic. All errors and omissions remain those of the author alone. ## Project board issues ### "AFIT: impl can't add extra lifetime restrictions, unlike non-async" #104689 - **Link:** https://github.com/rust-lang/rust/issues/104689 ### "Weird interaction between specialization and RPITITs" #108309 - **Link:** https://github.com/rust-lang/rust/issues/108309 ### "RPITIT with Send trait marker breaks borrow checker" #111105 - **Link:** https://github.com/rust-lang/rust/issues/111105 ### "`Failed to normalize` `async_fn_in_trait` ICE for indirect recursion of async trait method calls" #112047 - **Link:** https://github.com/rust-lang/rust/issues/112047 ### "Exponential compile times for chained RPITIT" #102527 - **Link:** https://github.com/rust-lang/rust/issues/102527 ### "Mysterious "higher-ranked lifetime error" with async fn in trait and return-type notation" #110963 - **Link:** https://github.com/rust-lang/rust/issues/110963 ### "AFIT: strange errors on circular impls" #112626 - **Link:** https://github.com/rust-lang/rust/issues/112626 ### "Nightly (warning): Async traits Self return requires type specification" #113538 - **Link:** https://github.com/rust-lang/rust/issues/113538 ### "hrtb + infer types break auto traits with return type notation " #109924 - **Link:** https://github.com/rust-lang/rust/issues/109924 ### "`async_fn_in_trait` and `return_type_notation` cause awkward awaits" #112569 - **Link:** https://github.com/rust-lang/rust/issues/112569 ## Pending PRs on the impl-trait-initiative repo None. ## Open PRs ### "stricter hidden type wf-check" rust#115008 - **Link:** https://github.com/rust-lang/rust/pull/115008 - **Labels:** S-waiting-on-review, A-impl-trait, proposed-final-comment-period, disposition-merge, T-types, WG-trait-system-refactor ### "Consider alias bounds when computing liveness in NLL (but this time sound hopefully)" rust#116733 - **Link:** https://github.com/rust-lang/rust/pull/116733 - **Labels:** final-comment-period, S-waiting-on-review, A-impl-trait, disposition-merge, F-type_alias_impl_trait, F-generic_associated_types, T-types

    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