Skip to content

TAIT defining scope options #107645

Closed
Closed

Description

@oli-obk

during the stabilization of TAITs (type alias impl trait) in #63063 (comment) a concern was raised: it's not obvious for the compiler (and IDEs), which items' bodies are allowed to register hidden types for TAITs. For RPIT (return position impl trait) it was obvious: the body of the function in whose return type the impl Trait was in. For TAITs the status quo is point 1 in the list of options below. This may require some interesting module juggling to avoid cycle errors that can occur due to revealing the hidden type to prove Send or Sync bounds, and that revealing again looking at the item to look for things registering the hidden type (see example and passing example).

The possible schemes we know about currently are:

  1. any item that is (recursively) within the parent of the TAIT is allowed to register the hidden type
  2. any item that follows the rules of 1. and additionally has the TAIT in its signature or where bounds is allowed to register the hidden type. this change has a prospective impl at
  3. same as 2. but not permitting where bounds to register hidden types
  4. any item in the defining scope can register hidden types, but we error out if the TAIT is not mentioned in the signature or where bounds
  5. same as 4. but not permitting where bounds to register hidden types
    • forward compatible with choosing 4. later

Ruled out schemes:

  1. any item that follows the rules of 1. and has a #[defines(NameOfTheTypeAlias)] attribute is allowed to register the hidden type
    • probably undesirable due to the verbosity in "obvious" cases (like using a TAIT in function return position)
  2. only allow explicitly registering hidden types with a magic libcore function that syntactically mentions the TAIT by its path. This will still require looking at the body, but we don't need to typecheck the body, just do name resolution on it.
    • this option is just listed for completeness, it's the worst option :)

I am nominating this issue for T-lang to discuss which options they prefer.

Activity

  1. added
    A-impl-traitArea: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch.
    I-lang-nominatedNominated for discussion during a lang team meeting.
    on Feb 3, 2023
  2. pnkfelix commented on Feb 21, 2023

    @pnkfelix
    Contributor

    Discussing T-lang triage. We want/need to resolve choice between options provided asynchronously.

    After we come to some conclusion, we'll FCP merge/close this to demarcate that conclusion.

  3. pnkfelix commented on Feb 21, 2023

    @pnkfelix
    Contributor
  4. nikomatsakis commented on Mar 14, 2023

    @nikomatsakis
  5. nikomatsakis commented on Mar 14, 2023

    @nikomatsakis
    Contributor

    @rfcbot fcp merge

    I propose that we accept #107809. It implements a conservative path forward. Basically any function that constraints a TAIT but doesn't list the TAIT in its arguments/return type is a hard error, giving us room to change the behavior in the future.

    Final behavior as I understand it

    • A TAIT has a defining scope that corresponds to the enclosing module or item.
    • A defining use for a TAIT is any item that (a) is within the defining scope and (b) contains a function that lists the TAIT in the argument or return types, either before or after normalization (*see edge case below).
    • Within the defining scope, an item is called constraining if it puts constraints on the value of the TAIT. i.e., for the item to type check, the hidden type of the TAIT must have a particular value. This could occur because of a let (e.g., let x: TAIT = 22_u32), a return (e.g., return 22_u32 in a function whose return type is TAIT), or in other ways.
    • Any constraining item within the defining scope that is not a defining use is a hard error. This means we can later opt to allow such a use; or to allow it with an annotation of some kind; or to make other such changes.
    • All defining uses must fully infer the hidden type of the TAIT and must infer the same type for the TAIT.
    • WIthin the defining scope, TAITs must always be given generic arguments (e.g., fn foo<T>() -> TAIT<T> and not fn foo() -> TAIT<u32>). This ensures inference is tractable and well-defined.

    Current bugs and limitations (forwards compatible to change)

    • Within the defining scope, attempts to check whether TAIT implements an auto-trait will yield a cycle error unless the auto-trait is listed in the TAIT's bounds. This is suboptimal, but the ideal fix is unclear.
    • A function that has an argument which is an associated type referencing a TAIT (e.g. <TAIT as SomeTrait>::SomeItem) ought to be considered a defining use. However, in the compiler today, if that associated type can be normalized, and the normalized form does not reference the TAIT, the function is not. This can only cause more errors.

    @rustbot labels -I-lang-nominated

  6. rfcbot commented on Mar 14, 2023

    @rfcbot

    Team member @nikomatsakis has proposed to merge this. The next step is review by the rest of the tagged team members:

    Concerns:

    Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

    cc @rust-lang/lang-advisors: FCP proposed for lang, please feel free to register concerns.
    See this document for info about what commands tagged team members can give me.

  7. removed
    I-lang-nominatedNominated for discussion during a lang team meeting.
    on Mar 14, 2023
  8. added
    proposed-final-comment-periodProposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off.
    disposition-mergeThis issue / PR is in PFCP or FCP with a disposition to merge it.
    on Mar 14, 2023
  9. tmandry commented on Mar 14, 2023

    @tmandry
    Member

    @rfcbot concern why-not-just-the-return-type

    Can we restrict to only the return type, instead of the return type and arguments? Are there major use cases that wouldn't be satisfied by this?

    cc @oli-obk

  10. oli-obk commented on Mar 14, 2023

    @oli-obk
    ContributorAuthor

    Not that I know of, though it may feel like a very artificial limitation to users

  11. RalfJung commented on Mar 14, 2023

    @RalfJung
    Member

    We allow impl Trait consistently in argument and return position, so why should TAIT not work in both? Is the concern the polarity of quantification which is common between TAIT and return types but not argument types?

  12. 116 remaining items

  13. Dirbaio commented on Nov 7, 2023

    @Dirbaio
    Contributor

    I've collected all my thoughts on TAIT defining scope design in a document. It goes through the possible designs and pros and cons of explicit (defines-like) and implicit (like "parent mod + signature restriction") designs, and what data we have about their use cases.

    https://hackmd.io/i-xpzf-LR7q75pSRTDVSaA

    zulip thread: https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/TAIT.20defining.20scope.20implicit.20vs.20explicit

  14. added and removed
    final-comment-periodIn the final comment period and will be merged soon unless new substantive objections are raised.
    on Nov 11, 2023
  15. rfcbot commented on Nov 11, 2023

    @rfcbot

    The final comment period, with a disposition to merge, as per the review above, is now complete.

    As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed.

    This will be merged soon.

  16. GoldsteinE commented on Nov 20, 2023

    @GoldsteinE
    Contributor

    I don’t think @Dirbaio points were properly addressed? Zulip threads seems dead and I don’t see a proper argument against points in Hackmd, only clarifying questions/answers.

  17. added a commit that references this issue on Jan 22, 2024
  18. added 2 commits that reference this issue on Jan 23, 2024
  19. added a commit that references this issue on Jan 24, 2024
  20. BatmanAoD commented on Dec 19, 2024

    @BatmanAoD
    Contributor

    The status of this issue is confusing -- what actually got approved & merged by the FCP ('m assuming this), and should this issue have been closed once the merge occurred?

  21. traviscross commented on Dec 19, 2024

    @traviscross
    Contributor

    The status is that we have a pending stabilization for ATPIT (#120700) that is waiting on implementation work, and that for TAIT more broadly, we're likely to do some kind of #[defines(..)]-like scheme, with the details of that still to be decided.

    It's probably reasonable to leave this issue open until we close it in favor of another, e.g. perhaps one that settles those details.

  22. oli-obk commented on Mar 12, 2025

    @oli-obk
    ContributorAuthor

    Resolved by #128440

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-impl-traitArea: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch.F-type_alias_impl_trait`#[feature(type_alias_impl_trait)]`T-langRelevant to the language teamdisposition-mergeThis issue / PR is in PFCP or FCP with a disposition to merge it.finished-final-comment-periodThe final comment period is finished for this PR / Issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions