Skip to content

Conversation

@davidtwco
Copy link
Member

@davidtwco davidtwco commented Jul 17, 2025

Fixes #143992

  • abd07de: Reverts trait_sel: MetaSized always holds temporarily #144016 so that MetaSized bounds are checked properly, and updates all the tests accordingly, including making tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs fail when it shouldn't
  • 90e61db: Prefer alias candidates over parameter environment candidates for sizedness, auto and default traits. tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs passes again, but tests/ui/generic-associated-types/issue-93262.rs starts failing when it shouldn't
  • e412062: No longer require that predicates of aliases hold in well-formedness checking of the alias. tests/ui/generic-associated-types/issue-93262.rs passes again

Each commit updates all the tests to their new output so it should be easy enough to see what the impact of each change individually is. After all of the changes, tests that pass when they didn't before or vice versa:

This had a crater run in #142712 (comment) alongside some other changes.

r? @lcnr
cc #142712 (this extracts part of that change)

@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. WG-trait-system-refactor The Rustc Trait System Refactor Initiative (-Znext-solver) labels Jul 17, 2025
@rustbot

This comment has been minimized.

@davidtwco davidtwco added the T-types Relevant to the types team, which will review and decide on the PR/issue. label Jul 17, 2025
@lcnr lcnr added beta-nominated Nominated for backporting to the compiler in the beta channel. and removed beta-nominated Nominated for backporting to the compiler in the beta channel. labels Jul 17, 2025
@lcnr
Copy link
Contributor

lcnr commented Jul 17, 2025

wrt 6aa3732 it's not that we stop to normalize the predicates of projections, it's that when comfirming alias-bound/Projection candidates, we required that the alias is well-formed. While we need to normalize these obligations before proving them, the normalize isn't the relevant part, the "we need to prove them at all" is.

wrt tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution-opaque-type.rs see https://rust-lang.zulipchat.com/#narrow/channel/144729-t-types/topic/sizedness.20bounds.20in.20explicit_implied_predicates_of.20.28.23142712.29/near/526987384. It's intended that this test changes to be ambiguous.

tests/ui/generic-associated-types/issue-92096.rs fails to prove C::Connecting<'placeholder>: Send which is required when proving that the generator is Send. This is 'just' an instance of #110338

Did you already crater run this behavior?

@davidtwco
Copy link
Member Author

Did you already crater run this behavior?

We did a crater run in #142712 (comment), which had all of these changes and included implying MetaSized on associated types.

@davidtwco davidtwco force-pushed the prefer-alias-over-env-for-sizedness branch from 6aa3732 to e412062 Compare July 17, 2025 13:02
@davidtwco
Copy link
Member Author

Updated the README and corrected the descriptions of everything per your comment

davidtwco added a commit to davidtwco/rust that referenced this pull request Jul 17, 2025
@bors

This comment was marked as resolved.

@davidtwco davidtwco force-pushed the prefer-alias-over-env-for-sizedness branch from e412062 to fa46ce0 Compare July 18, 2025 12:08
@davidtwco
Copy link
Member Author

Rebased following #143545

@davidtwco davidtwco added the I-types-nominated Nominated for discussion during a types team meeting. label Jul 18, 2025
@davidtwco
Copy link
Member Author

davidtwco added a commit to davidtwco/rust that referenced this pull request Jul 18, 2025
@lcnr lcnr changed the title trait_sel: sizedness goals prefer alias candidates trait_sel: sizedness + auto trait goals prefer alias candidates Jul 18, 2025
@bors

This comment was marked as resolved.

@davidtwco davidtwco force-pushed the prefer-alias-over-env-for-sizedness branch from fa46ce0 to f1e23b5 Compare July 21, 2025 12:36
davidtwco added a commit to davidtwco/rust that referenced this pull request Jul 21, 2025
@lcnr lcnr removed the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Jul 28, 2025
@lcnr
Copy link
Contributor

lcnr commented Jul 28, 2025

This PR does two relevant changes we need to FCP. We've already tried the first change before in #92191 and then reverted the PR as this caused a regression. The second change is necessary to avoid this regression and is also generally desirable.

Sized and auto trait goals now prefer alias-bound candidates over where-bounds

See #132325 for our existing candidate preference rules. We currently prefer where-bounds over alias-bounds for all candidates. This preference (like all preference) is arbitrary to some degree.

We need to do this for the following example:

trait Bound<'a> {}
trait Trait<'a> {
    type Assoc: Bound<'a>;
}

fn impls_bound<'b, T: Bound<'b>>() {}
fn foo<'a, 'b, 'c, T>()
where
    T: Trait<'a>,
    for<'hr> T::Assoc: Bound<'hr>,
{
    impls_bound::<'b, T::Assoc>();
    impls_bound::<'c, T::Assoc>();
}

We need to do so when normalizing:

trait Iterator {
    type Item;
}
trait IntoIterator {
    type Item;
    type IntoIter: Iterator<Item = Self::Item>;
}

fn normalize<I: Iterator<Item = ()>>() {}
fn foo<I>()
where
    I: IntoIterator,
    I::IntoIter: Iterator<Item = ()>,
{
    // normalizing `<I::IntoIter as Iterator>::Item` has two candidates:
    // - alias-bound normalizing to `<I as IntoIterator>::Item`
    // - where-bound normalizing to `()`
    normalize::<I::IntoIter>();
}

However, arbitrary candidate preference is a mess, so this is sometimes incorrect, either if the where-bound actually talks about a different alias, or different trait arguments:

trait Bound<'a> {}
trait Trait<'a> {
    type Assoc: Bound<'a>;
}

fn impls_bound<'b, T: Bound<'b>>() {}
fn foo<'a, 'b, T>()
where
    T: for<'hr> Trait<'hr>,
    <T as Trait<'b>>::Assoc: Bound<'a>,
{
    // Using the where-bound for `<T as Trait<'a>>::Assoc: Bound<'a>`
    // unnecessarily equates `<T as Trait<'a>>::Assoc` with the
    // `<T as Trait<'b>>::Assoc` from the env.
    impls_bound::<'a, <T as Trait<'a>>::Assoc>();
    // For a `<T as Trait<'b>>::Assoc: Bound<'b>` the self type of the
    // where-bound matches, but the arguments of the trait bound don't.
    impls_bound::<'b, <T as Trait<'b>>::Assoc>();
}

While figuring out whether where-bounds or alias-bounds have correct trait arguments isn't possible in general, we do know that alias-bound candidates always apply to exactly the right self type - the alias itself.

This means that in cases where the trait doesn't have any non-self parameters, prefering alias-bound candidates over where-bounds is always correct.

There is one edge case here, since #120752 we may also get alias-bound candidates from a nested self-type, so prefering alias-bound over where-bound candidates can be incorrect:

trait OtherTrait<'a> {
    type Assoc: ?Sized;
}

trait Trait
where
    <Self::Assoc as OtherTrait<'static>>::Assoc: Sized,
{
    type Assoc: for<'a> OtherTrait<'a>;
}

fn impls_sized<T: Sized>() {}
fn foo<'a, T>()
where
    T: Trait,
    for<'hr> <T::Assoc as OtherTrait<'hr>>::Assoc: Sized
{
    impls_sized::<<T::Assoc as OtherTrait<'a>>::Assoc>();
}

To avoid this issue, I propose limiting the preference of alias-bound over where-bound candidates only to the alias self-bounds, not indirect ones.

It also feels weird to me to implicitly change candidate preference depending on whether your trait has any generic arguments, so I propose to only change the preference rules for traits which are already special and guaranteed to not have any non-self arguments: Sized and auto traits.

To sum it up: we change our candidate preference rules to prefer alias self-bound candidates over where-bounds for Sized and auto traits. We continue to prefer where-bounds over alias bounds from nested self types and for all other traits.

Stop proving alias where-bounds when using alias-bounds

We currently prove the where-bounds of aliases when using an alias-bound candidate. This is generally redundant. We should have already proven these when checking whether the alias is well-formed.

However, we may have only ever proven well-formedness while the alias was still higher-ranked. If we then prove their where-bounds after instantiating this binder with placeholders, we get spurious errors due to missing implied bounds.

trait Bound {}
impl<'a, T> Bound for &'a T {}
trait Trait {
    type Assoc<'a>: Bound
    where
        Self: 'a;
}
impl<T> Trait for T {
    type Assoc<'a>
        = &'a T
    where
        Self: 'a;
}

// Using a higher ranked where-bound to prove itself succeeds,
// we don't check does not check whether it's WF after we've
// instantiated it. However, as normalizing an alias also requires
// proving its where-bounds, this function can only be called
// with types which are `'static`.
fn prove_hr<T: Trait>()
where
    for<'a> T::Assoc<'a>: Bound,
{
    prove_hr::<T>(); // ok
}
fn via_alias_bound<T: Trait>() {
    prove_hr::<T>(); // err, requires `T: 'static`, will compile with this PR
}
// Normalizing an associated item always checks its where-bounds.
fn via_impl_err<T>() {
    prove_hr::<T>(); // err, requires `T: 'static`
}

Ignoring the implied bounds of binders is generally unsound, e.g. #25860 and #84591.

The question is whether ignoring these implied bounds when using alias-bound candidates introduces any additional exploitable unsoundnesses:

  • This only enables us to prove a where-bound whose self type is a higher-ranked alias
  • To actually use this higher-ranked where-bound we need to instantiate the alias, at which point we should end up proving WF. As trait and alias parameters are all invariant, we can't hide erase the implied bound as in Implied bounds on nested references + variance = soundness hole #25860.
  • I cannot think of an alternative way to use this alias-bound in a bad way. I've spent a few hours playing with this and wasn't able to come up with an exploit

cc @steffahn would love for you to also take a look at this if you're interested. We already have the behavior of this PR with -Znext-solver.

I am not totally confident that it's impossible to exploit this in theory, even though it feels unlikely to me. However, I do feel quite confident that any such exploit will be highly artificial and will get fixed once we properly support implied bounds for the existing unsoundnesses without requiring any additional effort or consideration.

I personally think that checking WF of the alias when using its implied bounds feels somewhat arbitrary and am in favor of removing this check.

@rfcbot fcp merge

@rfcbot
Copy link

rfcbot commented Jul 28, 2025

Team member @lcnr 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!

See this document for info about what commands tagged team members can give me.

@rfcbot rfcbot added the proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. label Jul 28, 2025
@davidtwco
Copy link
Member Author

@bors rollup=never

Just so it's easier to bisect later if it causes issues

@bors
Copy link
Collaborator

bors commented Oct 15, 2025

⌛ Testing commit 8287fb0 with merge 27c2465...

bors added a commit that referenced this pull request Oct 15, 2025
…, r=lcnr

prefer alias candidates for sizedness + auto trait goals

Fixes #143992

- abd07de: Reverts #144016 so that `MetaSized` bounds are checked properly, and updates all the tests accordingly, including making `tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs` fail when it shouldn't
- 90e61db: Prefer alias candidates over parameter environment candidates for sizedness, auto and default traits. `tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs` passes again, but `tests/ui/generic-associated-types/issue-93262.rs` starts failing when it shouldn't
- e412062: No longer require that predicates of aliases hold in well-formedness checking of the alias. `tests/ui/generic-associated-types/issue-93262.rs` passes again

Each commit updates all the tests to their new output so it should be easy enough to see what the impact of each change individually is. After all of the changes, tests that pass when they didn't before or vice versa:

- `tests/ui/extern/extern-types-size_of_val.rs`
    - Previously passing, but only because of #144016, now correctly errors
- `tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs`
    - Previously failing on next solver, only because #144016 only applied to the old solver, passing now with 90e61db
- `tests/ui/sized-hierarchy/overflow.rs`
    - Previously passing, but only because of #144016, now correctly errors
- `tests/ui/generic-associated-types/issue-92096.rs`
    - Previously passing, due to e412062
    - Fails to prove `C::Connecting<'placeholder>: Send` which is required when proving that the generator is `Send`. This is an instance of #110338.
- `tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution-opaque-type.rs`
    - Previously passing, now failing in the next solver, due to 03e0fda
    - Expected that this test now fails as ambigious, see [Zulip](https://rust-lang.zulipchat.com/#narrow/channel/144729-t-types/topic/sizedness.20bounds.20in.20explicit_implied_predicates_of.20.28.23142712.29/near/526987384)

This had a crater run in #142712 (comment) alongside some other changes.

r? `@lcnr`
cc #142712 (this extracts part of that change)
@bors
Copy link
Collaborator

bors commented Oct 15, 2025

💔 Test failed - checks-actions

@bors bors added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Oct 15, 2025
@rust-log-analyzer

This comment has been minimized.

For sizedness, default and auto trait predicates, now prefer non-param
candidates if any exist. As these traits do not have generic parameters,
it never makes sense to prefer an non-alias candidate, as there can
never be a more permissive candidate.
No longer require that we prove that the predicates of aliases hold when
checking the well-formedness of the alias. This permits more uses of GATs
and changes the output of yet more tests.
@davidtwco davidtwco force-pushed the prefer-alias-over-env-for-sizedness branch from 8287fb0 to 519d6cd Compare October 15, 2025 09:00
@rustbot
Copy link
Collaborator

rustbot commented Oct 15, 2025

This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@davidtwco
Copy link
Member Author

@bors r=lcnr

@bors
Copy link
Collaborator

bors commented Oct 15, 2025

📌 Commit 519d6cd has been approved by lcnr

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Oct 15, 2025
@bors
Copy link
Collaborator

bors commented Oct 15, 2025

⌛ Testing commit 519d6cd with merge 57ef8d6...

@bors
Copy link
Collaborator

bors commented Oct 15, 2025

☀️ Test successful - checks-actions
Approved by: lcnr
Pushing 57ef8d6 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Oct 15, 2025
@bors bors merged commit 57ef8d6 into rust-lang:master Oct 15, 2025
12 checks passed
@rustbot rustbot added this to the 1.92.0 milestone Oct 15, 2025
@github-actions
Copy link
Contributor

What is this? This is an experimental post-merge analysis report that shows differences in test outcomes between the merged PR and its parent PR.

Comparing 3f2a592 (parent) -> 57ef8d6 (this PR)

Test differences

Show 78 test diffs

Stage 1

  • [ui] tests/ui/sized-hierarchy/bound-on-assoc-type-projection-1.rs#next: [missing] -> pass (J0)
  • [ui] tests/ui/sized-hierarchy/bound-on-assoc-type-projection-1.rs#old: [missing] -> pass (J0)
  • [ui] tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs#current_sized_hierarchy: pass -> [missing] (J0)
  • [ui] tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs#next_sized_hierarchy: pass -> [missing] (J0)
  • [ui] tests/ui/sized-hierarchy/prefer-non-nested-alias-bound.rs#current: [missing] -> pass (J0)
  • [ui] tests/ui/sized-hierarchy/prefer-non-nested-alias-bound.rs#next: [missing] -> pass (J0)

Stage 2

  • [ui] tests/ui/sized-hierarchy/bound-on-assoc-type-projection-1.rs#next: [missing] -> pass (J1)
  • [ui] tests/ui/sized-hierarchy/bound-on-assoc-type-projection-1.rs#old: [missing] -> pass (J1)
  • [ui] tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs#current_sized_hierarchy: pass -> [missing] (J1)
  • [ui] tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs#next_sized_hierarchy: pass -> [missing] (J1)
  • [ui] tests/ui/sized-hierarchy/prefer-non-nested-alias-bound.rs#current: [missing] -> pass (J1)
  • [ui] tests/ui/sized-hierarchy/prefer-non-nested-alias-bound.rs#next: [missing] -> pass (J1)

Additionally, 66 doctest diffs were found. These are ignored, as they are noisy.

Job group index

Test dashboard

Run

cargo run --manifest-path src/ci/citool/Cargo.toml -- \
    test-dashboard 57ef8d642d21965304bde849bab4f389b4353e27 --output-dir test-dashboard

And then open test-dashboard/index.html in your browser to see an overview of all executed tests.

Job duration changes

  1. pr-check-1: 1422.7s -> 1840.4s (29.4%)
  2. x86_64-gnu-llvm-20: 2348.5s -> 2741.9s (16.8%)
  3. dist-apple-various: 4102.4s -> 3601.4s (-12.2%)
  4. i686-gnu-1: 7346.1s -> 8086.4s (10.1%)
  5. x86_64-gnu-llvm-20-2: 5616.9s -> 6178.4s (10.0%)
  6. x86_64-gnu-gcc: 3067.4s -> 3368.7s (9.8%)
  7. x86_64-rust-for-linux: 2605.8s -> 2846.9s (9.3%)
  8. x86_64-gnu-llvm-20-1: 3305.1s -> 3566.7s (7.9%)
  9. x86_64-gnu-aux: 6487.5s -> 6986.4s (7.7%)
  10. aarch64-gnu-llvm-20-2: 2205.1s -> 2365.6s (7.3%)
How to interpret the job duration changes?

Job durations can vary a lot, based on the actual runner instance
that executed the job, system noise, invalidated caches, etc. The table above is provided
mostly for t-infra members, for simpler debugging of potential CI slow-downs.

@rust-timer
Copy link
Collaborator

Finished benchmarking commit (57ef8d6): comparison URL.

Overall result: ❌✅ regressions and improvements - please read the text below

Our benchmarks found a performance regression caused by this PR.
This might be an actual regression, but it can also be just noise.

Next Steps:

  • If the regression was expected or you think it can be justified,
    please write a comment with sufficient written justification, and add
    @rustbot label: +perf-regression-triaged to it, to mark the regression as triaged.
  • If you think that you know of a way to resolve the regression, try to create
    a new PR with a fix for the regression.
  • If you do not understand the regression or you think that it is just noise,
    you can ask the @rust-lang/wg-compiler-performance working group for help (members of this group
    were already notified of this PR).

@rustbot label: +perf-regression
cc @rust-lang/wg-compiler-performance

Instruction count

Our most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.

mean range count
Regressions ❌
(primary)
0.4% [0.1%, 0.8%] 16
Regressions ❌
(secondary)
0.5% [0.2%, 1.8%] 19
Improvements ✅
(primary)
-0.2% [-0.6%, -0.1%] 6
Improvements ✅
(secondary)
-0.5% [-0.7%, -0.3%] 8
All ❌✅ (primary) 0.2% [-0.6%, 0.8%] 22

Max RSS (memory usage)

Results (primary 0.8%, secondary 0.4%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
0.8% [0.8%, 0.8%] 1
Regressions ❌
(secondary)
2.3% [2.2%, 2.5%] 2
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-1.5% [-1.7%, -1.3%] 2
All ❌✅ (primary) 0.8% [0.8%, 0.8%] 1

Cycles

Results (primary 2.6%, secondary -3.2%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
2.6% [2.0%, 3.1%] 2
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-3.2% [-3.2%, -3.2%] 1
All ❌✅ (primary) 2.6% [2.0%, 3.1%] 2

Binary size

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

Bootstrap: 476.725s -> 476.546s (-0.04%)
Artifact size: 388.06 MiB -> 388.06 MiB (0.00%)

@rustbot rustbot added the perf-regression Performance regression. label Oct 16, 2025
@davidtwco davidtwco deleted the prefer-alias-over-env-for-sizedness branch October 16, 2025 09:05
@Mark-Simulacrum Mark-Simulacrum added the perf-regression-triaged The performance regression has been triaged. label Oct 21, 2025
@Mark-Simulacrum
Copy link
Member

Fix for a regression. Generally fairly neutral so further investigation doesn't seem warranted.

bors added a commit that referenced this pull request Oct 24, 2025
…nds, r=lcnr

hir_analysis: add missing sizedness bounds

Depends on #144064

Default sizedness bounds were not being added to `explicit_super_predicates_of` and `explicit_implied_predicates_of` which meant that a trait bound added to a associated type projection would be missing the implied predicate of the default sizedness supertrait of that trait.

An unexpected consequence of this change was that the check for multiple principals was now finding an additional `MetaSized` principal when eagerly expanding trait aliases - which is fixed by skipping `MetaSized` when elaborating trait aliases in lowering `dyn TraitAlias`.
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. I-types-nominated Nominated for discussion during a types team meeting. merged-by-bors This PR was explicitly merged by bors. perf-regression Performance regression. perf-regression-triaged The performance regression has been triaged. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. S-waiting-on-fcp Status: PR is in FCP and is awaiting for FCP to complete. T-types Relevant to the types team, which will review and decide on the PR/issue. to-announce Announce this issue on triage meeting WG-trait-system-refactor The Rustc Trait System Refactor Initiative (-Znext-solver)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

where bounds regression in beta+nightly