Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stabilize associated type bounds (RFC 2289) #122055

Merged
merged 1 commit into from
Mar 19, 2024

Conversation

compiler-errors
Copy link
Member

@compiler-errors compiler-errors commented Mar 6, 2024

This PR stabilizes associated type bounds, which were laid out in RFC 2289. This gives us a shorthand to express nested type bounds that would otherwise need to be expressed with nested impl Trait or broken into several where clauses.

What are we stabilizing?

We're stabilizing the associated item bounds syntax, which allows us to put bounds in associated type position within other bounds, i.e. T: Trait<Assoc: Bounds...>. See RFC 2289 for motivation.

In all position, the associated type bound syntax expands into a set of two (or more) bounds, and never anything else (see "How does this differ[...]" section for more info).

Associated type bounds are stabilized in four positions:

  • where clauses (and APIT) - This is equivalent to breaking up the bound into two (or more) where clauses. For example, where T: Trait<Assoc: Bound> is equivalent to where T: Trait, <T as Trait>::Assoc: Bound.
  • Supertraits - Similar to above, trait CopyIterator: Iterator<Item: Copy> {}. This is almost equivalent to breaking up the bound into two (or more) where clauses; however, the bound on the associated item is implied whenever the trait is used. See Should associated type bounds on supertraits be implied? #112573/Make associated type bounds in supertrait position implied #112629.
  • Associated type item bounds - This allows constraining the nested rigid projections that are associated with a trait's associated types. e.g. trait Trait { type Assoc: Trait2<Assoc2: Copy>; }.
  • opaque item bounds (RPIT, TAIT) - This allows constraining associated types that are associated with the opaque without having to name the opaque. For example, impl Iterator<Item: Copy> defines an iterator whose item is Copy without having to actually name that item bound.

The latter three are not expressible in surface Rust (though for associated type item bounds, this will change in #120752, which I don't believe should block this PR), so this does represent a slight expansion of what can be expressed in trait bounds.

How does this differ from the RFC?

Compared to the RFC, the current implementation always desugars associated type bounds to sets of ty::Clauses internally. Specifically, it does not introduce a position-dependent desugaring as laid out in RFC 2289, and in particular:

  • It does not desugar to anonymous associated items in associated type item bounds.
  • It does not desugar to nested RPITs in RPIT bounds, nor nested TAITs in TAIT bounds.

This position-dependent desugaring laid out in the RFC existed simply to side-step limitations of the trait solver, which have mostly been fixed in #120584. The desugaring laid out in the RFC also added unnecessary complication to the design of the feature, and introduces its own limitations to, for example:

  • Conditionally lowering to nested impl Trait in certain positions such as RPIT and TAIT means that we inherit the limitations of RPIT/TAIT, namely lack of support for higher-ranked opaque inference. See this code example: Collect relevant item bounds from trait clauses for nested rigid projections #120752 (comment).
  • Introducing anonymous associated types makes traits no longer object safe, since anonymous associated types are not nameable, and all associated types must be named in dyn types.

This last point motivates why this PR is not stabilizing support for associated type bounds in dyn types, e.g, dyn Assoc<Item: Bound>. Why? Because dyn types need to have concrete types for all associated items, this would necessitate a distinct lowering for associated type bounds, which seems both complicated and unnecessary compared to just requiring the user to write impl Trait themselves. See #120719.

Implementation history:

Limited to the significant behavioral changes and fixes and relevant PRs, ping me if I left something out--

Closes #52662

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Mar 6, 2024
@compiler-errors compiler-errors added T-lang Relevant to the language team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue. and removed T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Mar 6, 2024
@rust-log-analyzer

This comment has been minimized.

@compiler-errors compiler-errors marked this pull request as ready for review March 6, 2024 15:13
@rustbot
Copy link
Collaborator

rustbot commented Mar 6, 2024

Some changes occurred in compiler/rustc_codegen_gcc

cc @antoyo, @GuillaumeGomez

@compiler-errors
Copy link
Member Author

r? types
@rustbot label: I-lang-nominated

@rustbot rustbot added the I-lang-nominated The issue / PR has been nominated for discussion during a lang team meeting. label Mar 6, 2024
@joshtriplett
Copy link
Member

Thank you to @compiler-errors and everyone else who has worked on this! It's wonderful seeing this brought to the point of stabilization. I know many people's fingers keep expecting that this already works. :)

@rfcbot merge

@rfcbot
Copy link

rfcbot commented Mar 6, 2024

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

No concerns currently listed.

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.

@rfcbot rfcbot added proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. labels Mar 6, 2024
@joshtriplett joshtriplett removed the I-lang-nominated The issue / PR has been nominated for discussion during a lang team meeting. label Mar 6, 2024
@nikomatsakis
Copy link
Contributor

@rfcbot reviewed

@jackh726
Copy link
Member

jackh726 commented Mar 6, 2024

For implementation history, its probably worth pointing out the PRs I made around the bound var refactoring. Its important in understanding how those are captured.

All in all though, I'm happy to see this stabilized. I also think its important to point out that other than in where clauses, you can't currently write these bounds, because they are more like the "ensures" clauses than the existing "where" clauses and thus have different effects on implied bounds.

@compiler-errors
Copy link
Member Author

@jackh726:

For implementation history [...]

Feel free to edit and add more commits to the impl history section, since I don't know which ones you're talking about specifically. If they don't have to do with ATB specifically, maybe also leave a little note beside them that talks about how it impacts the impls?

I also think its important to point out that other than in where clauses, you can't currently write these bounds [...]

Yep. I pointed this out a bit in the document. See "The latter three are not expressible in surface Rust", "however, the bound on the associated item is implied whenever the trait is used". Perhaps ping me if you'd like to request additions to this stabilization doc to make this more clear.

@pnkfelix
Copy link
Member

pnkfelix commented Mar 7, 2024

@rfcbot reviewed

@jdahlstrom
Copy link

[Associated type item bounds] are not expressible in surface Rust

I sort of had naively assumed that this would already work:

trait Foo {
    type Bar: Iterator 
    where 
        <Self::Bar as Iterator>::Item: Display;
}

but rather it just causes an overflow when evaluating an impl. Should it work and be equivalent to type Bar: Iterator<Item: Display>? It certainly feels a bit inconsistent if not.

@compiler-errors
Copy link
Member Author

compiler-errors commented Mar 7, 2024

I sort of had naively assumed that this would already work [...]

Keep in mind that item bounds on associated types are not equivalent to where clauses in general, i.e.

trait Foo {
    type Assoc: Iterator;
}

// is not:

trait Foo {
    type Assoc
    where
        Self::Assoc: Iterator;
}

They differ in what is implied and what is required to be proven:

trait Foo {
    type Assoc
    where
        Self::Assoc: Iterator;
}

fn foo<T: Foo>(xs: T::Assoc) {
    //~^ ERROR `<T as Foo>::Assoc` is not an iterator
    for x in xs {}
}

If we wanted to collect such bounds and make them implied, we certainly could, though. But currently, we don't collect item bounds from the where clauses of an associated type at all.


After the PR #120752 lands, a possible way to express this bound would be putting the where clause on the trait, since that's the only place we currently look to collect such item bounds:

trait Foo
where 
    <Self::Bar as Iterator>::Item: Display,
{
    type Bar: Iterator;
}

However, given this stabilization is forwards-compatible with #120752, I'd really rather not block this on that, or any other extensions of implied bounds.

@rfcbot rfcbot added the final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. label Mar 7, 2024
@rfcbot
Copy link

rfcbot commented Mar 7, 2024

🔔 This is now entering its final comment period, as per the review above. 🔔

@rfcbot rfcbot removed the proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. label Mar 7, 2024
@compiler-errors
Copy link
Member Author

@jackh726: Do you have a recommendation for where those docs would live?

@jackh726
Copy link
Member

Where do we currently talk about associate type bindings? Likely there. If we don't, then I guess it doesn't make sense to block on it.

@workingjubilee
Copy link
Contributor

If this isn't about the core implementation being stabilized here, can you open a new issue for addressing any followups? Thanks!

@bors
Copy link
Contributor

bors commented Mar 19, 2024

⌛ Testing commit c63f3fe with merge 21d94a3...

@bors
Copy link
Contributor

bors commented Mar 19, 2024

☀️ Test successful - checks-actions
Approved by: oli-obk
Pushing 21d94a3 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Mar 19, 2024
@bors bors merged commit 21d94a3 into rust-lang:master Mar 19, 2024
12 checks passed
@rustbot rustbot added this to the 1.79.0 milestone Mar 19, 2024
@rust-timer
Copy link
Collaborator

Finished benchmarking commit (21d94a3): comparison URL.

Overall result: no relevant changes - no action needed

@rustbot label: -perf-regression

Instruction count

This benchmark run did not return any relevant results for this metric.

Max RSS (memory usage)

Results

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
6.2% [6.2%, 6.2%] 1
Improvements ✅
(primary)
-2.4% [-2.4%, -2.3%] 2
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) -2.4% [-2.4%, -2.3%] 2

Cycles

This benchmark run did not return any relevant results for this metric.

Binary size

This benchmark run did not return any relevant results for this metric.

Bootstrap: 669.42s -> 670.018s (0.09%)
Artifact size: 312.82 MiB -> 312.86 MiB (0.01%)

taiki-e added a commit to taiki-e/easy-ext that referenced this pull request Mar 20, 2024
associated_type_bounds stabilized in Rust 1.79.
rust-lang/rust#122055
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Mar 26, 2024
…ound, r=compiler-errors

Suggest associated type bounds on problematic associated equality bounds

Fixes rust-lang#105056. TL;DR: Suggest `Trait<Ty: Bound>` on `Trait<Ty = Bound>` in Rust >=2021.

~~Blocked on rust-lang#122055 (stabilization of `associated_type_bounds`), I'd say.~~ (merged)
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request Mar 27, 2024
Rollup merge of rust-lang#122120 - fmease:sugg-assoc-ty-bound-on-eq-bound, r=compiler-errors

Suggest associated type bounds on problematic associated equality bounds

Fixes rust-lang#105056. TL;DR: Suggest `Trait<Ty: Bound>` on `Trait<Ty = Bound>` in Rust >=2021.

~~Blocked on rust-lang#122055 (stabilization of `associated_type_bounds`), I'd say.~~ (merged)
@apiraino apiraino removed the to-announce Announce this issue on triage meeting label Apr 4, 2024
@compiler-errors compiler-errors deleted the stabilize-atb branch April 18, 2024 21:58
bherrera pushed a commit to misttech/mist-os that referenced this pull request Jun 3, 2024
Now that associated type bounds are stabilized in rustc (see
rust-lang/rust#122055), we can remove the
workaround used in the IP crate to put filtering constraints on the
device ID type.

Change-Id: I80a9d6ce9553ff64f5f7a209dccb26d667a1753b
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/ /1055952
Fuchsia-Auto-Submit: Peter Johnston <[email protected]>
Reviewed-by: Bruno Dal Bo <[email protected]>
Commit-Queue: Auto-Submit <[email protected]>
artem pushed a commit to artem/fuchsia-mirror that referenced this pull request Jun 5, 2024
Now that associated type bounds are stabilized in rustc (see
rust-lang/rust#122055), we can remove the
workaround used in the IP crate to put filtering constraints on the
device ID type.

Change-Id: I80a9d6ce9553ff64f5f7a209dccb26d667a1753b
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/ /1055952
Fuchsia-Auto-Submit: Peter Johnston <[email protected]>
Reviewed-by: Bruno Dal Bo <[email protected]>
Commit-Queue: Auto-Submit <[email protected]>
github-merge-queue bot pushed a commit to bevyengine/bevy that referenced this pull request Jul 2, 2024
…4107)

# Objective

The bounds for query iterators are quite intimidating.

## Solution

With Rust 1.79, [associated type
bounds](rust-lang/rust#122055) stabilized,
which can simplify the bounds slightly.
zmbush pushed a commit to zmbush/bevy that referenced this pull request Jul 3, 2024
…vyengine#14107)

# Objective

The bounds for query iterators are quite intimidating.

## Solution

With Rust 1.79, [associated type
bounds](rust-lang/rust#122055) stabilized,
which can simplify the bounds slightly.
MrGVSV pushed a commit to MrGVSV/bevy that referenced this pull request Jul 5, 2024
…vyengine#14107)

# Objective

The bounds for query iterators are quite intimidating.

## Solution

With Rust 1.79, [associated type
bounds](rust-lang/rust#122055) stabilized,
which can simplify the bounds slightly.
GuillaumeGomez pushed a commit to GuillaumeGomez/rust that referenced this pull request Jul 10, 2024
…-obk

Stabilize associated type bounds (RFC 2289)

This PR stabilizes associated type bounds, which were laid out in [RFC 2289]. This gives us a shorthand to express nested type bounds that would otherwise need to be expressed with nested `impl Trait` or broken into several `where` clauses.

### What are we stabilizing?

We're stabilizing the associated item bounds syntax, which allows us to put bounds in associated type position within other bounds, i.e. `T: Trait<Assoc: Bounds...>`. See [RFC 2289] for motivation.

In all position, the associated type bound syntax expands into a set of two (or more) bounds, and never anything else (see "How does this differ[...]" section for more info).

Associated type bounds are stabilized in four positions:
* **`where` clauses (and APIT)** - This is equivalent to breaking up the bound into two (or more) `where` clauses. For example, `where T: Trait<Assoc: Bound>` is equivalent to `where T: Trait, <T as Trait>::Assoc: Bound`.
* **Supertraits** - Similar to above, `trait CopyIterator: Iterator<Item: Copy> {}`. This is almost equivalent to breaking up the bound into two (or more) `where` clauses; however, the bound on the associated item is implied whenever the trait is used. See rust-lang#112573/rust-lang#112629.
* **Associated type item bounds** - This allows constraining the *nested* rigid projections that are associated with a trait's associated types. e.g. `trait Trait { type Assoc: Trait2<Assoc2: Copy>; }`.
* **opaque item bounds (RPIT, TAIT)** - This allows constraining associated types that are associated with the opaque without having to *name* the opaque. For example, `impl Iterator<Item: Copy>` defines an iterator whose item is `Copy` without having to actually name that item bound.

The latter three are not expressible in surface Rust (though for associated type item bounds, this will change in rust-lang#120752, which I don't believe should block this PR), so this does represent a slight expansion of what can be expressed in trait bounds.

### How does this differ from the RFC?

Compared to the RFC, the current implementation *always* desugars associated type bounds to sets of `ty::Clause`s internally. Specifically, it does *not* introduce a position-dependent desugaring as laid out in [RFC 2289], and in particular:
* It does *not* desugar to anonymous associated items in associated type item bounds.
* It does *not* desugar to nested RPITs in RPIT bounds, nor nested TAITs in TAIT bounds.

This position-dependent desugaring laid out in the RFC existed simply to side-step limitations of the trait solver, which have mostly been fixed in rust-lang#120584. The desugaring laid out in the RFC also added unnecessary complication to the design of the feature, and introduces its own limitations to, for example:
* Conditionally lowering to nested `impl Trait` in certain positions such as RPIT and TAIT means that we inherit the limitations of RPIT/TAIT, namely lack of support for higher-ranked opaque inference. See this code example: rust-lang#120752 (comment).
* Introducing anonymous associated types makes traits no longer object safe, since anonymous associated types are not nameable, and all associated types must be named in `dyn` types.

This last point motivates why this PR is *not* stabilizing support for associated type bounds in `dyn` types, e.g, `dyn Assoc<Item: Bound>`. Why? Because `dyn` types need to have *concrete* types for all associated items, this would necessitate a distinct lowering for associated type bounds, which seems both complicated and unnecessary compared to just requiring the user to write `impl Trait` themselves. See rust-lang#120719.

### Implementation history:

Limited to the significant behavioral changes and fixes and relevant PRs, ping me if I left something out--
* rust-lang#57428
* rust-lang#108063
* rust-lang#110512
* rust-lang#112629
* rust-lang#120719
* rust-lang#120584

Closes rust-lang#52662

[RFC 2289]: https://rust-lang.github.io/rfcs/2289-associated-type-bounds.html
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. merged-by-bors This PR was explicitly merged by bors. relnotes Marks issues that should be documented in the release notes of the next release. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-lang Relevant to the language team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Tracking issue for RFC 2289, "Associated type bounds"