Skip to content

Optimize handling of solver errors - #160160

Open
ChayimFriedman2 wants to merge 2 commits into
rust-lang:mainfrom
ChayimFriedman2:if-empty-opt
Open

Optimize handling of solver errors#160160
ChayimFriedman2 wants to merge 2 commits into
rust-lang:mainfrom
ChayimFriedman2:if-empty-opt

Conversation

@ChayimFriedman2

@ChayimFriedman2 ChayimFriedman2 commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

View all comments

  • Check for the empty case in collect_remaining_errors().

  • Instead of representing trait errors as Vec<Error>, use a special type

    This has multiple advantages:

    • Performance. The new type is 1/3 the size of Vec (being equivalent in layout to Option<ThinVec>) and can be kept in a register.
    • Type safety. We mark the type #[must_use], and thinks requiring errors take ThinVec, which requires unwrapping the type and verifying there is indeed an error. We still provide conversions to slices, ThinVec, and iteration, because some code needs this and I saw no benefit in changing it, but we deliberately do not provide Deref<Target = [E]> or things like that.

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. 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 29, 2026
@ChayimFriedman2

Copy link
Copy Markdown
Contributor Author

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Jul 29, 2026
@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request Jul 29, 2026
Check for the empty case in `collect_remaining_errors()`
Comment on lines 184 to 191

fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> {
#[allow(clippy::iter_skip_zero)]
if self.obligations.pending.is_empty() && self.obligations.overflowed.is_empty() {
// In 99.983% this is true, so this helps perf.
return Vec::new();
}

self.obligations

@panstromek panstromek Jul 29, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One other thing I'd try later too is that sometimes it helps is to put #[inline] on the function and wrap the rest of the code after the fast path in outline(move || { ... })).

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, I also wanted to check if making this ThinVec will help since it will return in a register. It may cancel with outlining though.

@ChayimFriedman2

Copy link
Copy Markdown
Contributor Author

@bors cancel

@rust-bors

rust-bors Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

❗ There is currently no auto build in progress on this PR.

Hint: There is a pending try build on this PR. Maybe you meant to cancel it? You can do that using @bors try cancel.

@ChayimFriedman2

Copy link
Copy Markdown
Contributor Author

@bors try cancel

@rust-bors

rust-bors Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Try build cancelled. Cancelled workflows:

@ChayimFriedman2

Copy link
Copy Markdown
Contributor Author

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request Jul 29, 2026
Check for the empty case in `collect_remaining_errors()`
@the8472

the8472 commented Jul 29, 2026

Copy link
Copy Markdown
Member

I think it's worth checking this in std's TrustedLen specializations. The code is querying the size-hint anyway, it might as well bail early rather than invoking the next machinery.

@ChayimFriedman2

Copy link
Copy Markdown
Contributor Author

It might be interesting, but std's specialization applies to much more diverse range of behaviors. There we can't know if "empty most of the times" is the common case.

@rust-bors

rust-bors Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: f5bcd01 (f5bcd011d3725a90befeaac099c3fe9d56706db8)
Base parent: d366396 (d3663963ca08f465d01d283a7199778902623bb9)

@rust-timer

This comment has been minimized.

@rust-timer

Copy link
Copy Markdown
Collaborator

Finished benchmarking commit (f5bcd01): comparison URL.

Overall result: ✅ improvements - no action needed

Benchmarking means the PR may be perf-sensitive. Consider adding rollup=never if this change is not fit for rolling up.

@rustbot label: -S-waiting-on-perf -perf-regression

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
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-1.6% [-3.6%, -0.2%] 3
All ❌✅ (primary) - - 0

Max RSS (memory usage)

Results (primary -3.6%, secondary 0.7%)

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

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
0.7% [0.7%, 0.7%] 1
Improvements ✅
(primary)
-3.6% [-5.5%, -1.2%] 3
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) -3.6% [-5.5%, -1.2%] 3

Cycles

Results (primary 0.4%, secondary 0.5%)

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.5%, 1.4%] 9
Regressions ❌
(secondary)
1.6% [0.4%, 5.2%] 13
Improvements ✅
(primary)
-1.4% [-2.3%, -0.4%] 2
Improvements ✅
(secondary)
-1.6% [-5.5%, -0.5%] 7
All ❌✅ (primary) 0.4% [-2.3%, 1.4%] 11

Binary size

This perf run didn't have relevant results for this metric.

Bootstrap: 489.658s -> 489.161s (-0.10%)
Artifact size: 390.17 MiB -> 390.11 MiB (-0.01%)

@rustbot rustbot removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Jul 29, 2026
@ChayimFriedman2

Copy link
Copy Markdown
Contributor Author

Okay, so not only this does not regress #160073 this also has a non-negligible improvement. Seems worth to merge, but I'll try to see if I can use ThinVec or something similar before.

@panstromek

Copy link
Copy Markdown
Contributor

Yea, the large-workspace change is likely noise, but the other two are legit. ThinVec might help or not, because it stores len=0 in a static singleton, while Vec keeps it on a stack. Using Option<ThinVec> for the empty case can get around that (and it's the same size).

@ChayimFriedman2

Copy link
Copy Markdown
Contributor Author

Option<ThinVec> is what I'm doing (more precisely a custom enum with the same layout). But it's a slightly bigger change.

@rustbot rustbot added A-attributes Area: Attributes (`#[…]`, `#![…]`) T-clippy Relevant to the Clippy team. labels Jul 29, 2026
@ChayimFriedman2

Copy link
Copy Markdown
Contributor Author

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Jul 29, 2026
@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request Jul 29, 2026
Check for the empty case in `collect_remaining_errors()`
Comment thread compiler/rustc_trait_selection/src/solve/fulfill.rs Outdated
@rust-bors

rust-bors Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: 79906d6 (79906d6d0a86f5d6217ccecf0a9294440b328283)
Base parent: b5be620 (b5be620d5ac9824c4a6030df9fb72644ef4f459b)

@rust-timer

This comment has been minimized.

@rust-timer

Copy link
Copy Markdown
Collaborator

Finished benchmarking commit (79906d6): comparison URL.

Overall result: ❌✅ regressions and improvements - please read:

Benchmarking means the PR may be perf-sensitive. It's automatically marked not fit for rolling up. Overriding is possible but disadvised: it risks changing compiler perf.

Next, please: If you can, justify the regressions found in this try perf run in writing along with @rustbot label: +perf-regression-triaged. If not, fix the regressions and do another perf run. Neutral or positive results will clear the label automatically.

@bors rollup=never rustc-perf
@rustbot label: -S-waiting-on-perf +perf-regression

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
Regressions ❌
(secondary)
0.2% [0.2%, 0.3%] 6
Improvements ✅
(primary)
-0.3% [-0.5%, -0.1%] 68
Improvements ✅
(secondary)
-0.5% [-2.1%, -0.1%] 69
All ❌✅ (primary) -0.3% [-0.5%, -0.1%] 68

Max RSS (memory usage)

Results (primary -0.1%, secondary -0.1%)

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

mean range count
Regressions ❌
(primary)
2.9% [2.9%, 2.9%] 1
Regressions ❌
(secondary)
0.8% [0.8%, 0.8%] 1
Improvements ✅
(primary)
-1.6% [-2.5%, -0.6%] 2
Improvements ✅
(secondary)
-0.5% [-0.5%, -0.4%] 3
All ❌✅ (primary) -0.1% [-2.5%, 2.9%] 3

Cycles

Results (primary 0.1%, 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)
1.0% [0.4%, 2.0%] 5
Regressions ❌
(secondary)
1.5% [0.7%, 3.0%] 5
Improvements ✅
(primary)
-0.8% [-1.6%, -0.5%] 5
Improvements ✅
(secondary)
-0.8% [-1.1%, -0.4%] 5
All ❌✅ (primary) 0.1% [-1.6%, 2.0%] 10

Binary size

Results (secondary 0.0%)

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

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
0.0% [0.0%, 0.0%] 1
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) - - 0

Bootstrap: 489.76s -> 487.975s (-0.36%)
Artifact size: 390.94 MiB -> 390.13 MiB (-0.21%)

@rustbot rustbot added perf-regression Performance regression. and removed S-waiting-on-perf Status: Waiting on a perf run to be completed. labels Jul 30, 2026
@ChayimFriedman2

Copy link
Copy Markdown
Contributor Author

Improvements greatly outweigh regressions, including in non-next-solver benchmarks. Seems like this was a good idea.

@ChayimFriedman2
ChayimFriedman2 marked this pull request as ready for review July 30, 2026 00:04
@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jul 30, 2026
@rustbot

rustbot commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Some changes occurred in const_evaluatable.rs

cc @BoxyUwU

Some changes occurred to the core trait solver

cc @rust-lang/initiative-trait-system-refactor

clippy is developed in its own repository. If possible, consider making this change to rust-lang/rust-clippy instead.

cc @rust-lang/clippy

Some changes occurred to the CTFE machinery

cc @RalfJung, @oli-obk, @lcnr

Some changes occurred to MIR optimizations

cc @rust-lang/wg-mir-opt

Some changes occurred in engine.rs, potentially modifying the public API of ObligationCtxt.

cc @lcnr

HIR ty lowering was modified

cc @fmease

Some changes occurred to constck

cc @fee1-dead

Some changes occurred in compiler/rustc_passes/src/check_attr.rs

cc @jdonszelmann, @JonathanBrouwer

Some changes occurred to the CTFE / Miri interpreter

cc @rust-lang/miri

@rustbot rustbot removed the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Jul 30, 2026
@rustbot

rustbot commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

r? @TaKO8Ki

rustbot has assigned @TaKO8Ki.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: compiler, types
  • compiler, types expanded to 74 candidates
  • Random selection from 16 candidates

@ChayimFriedman2

Copy link
Copy Markdown
Contributor Author

To the reviewer: The commits are fully separate. I can create separate PRs, but the first commit is very small so I don't think it's needed.

@ChayimFriedman2 ChayimFriedman2 changed the title Check for the empty case in collect_remaining_errors() Optimize handling of solver errors Jul 30, 2026
This has multiple advantages:

 - Performance. The new type is 1/3 the size of `Vec` (being equivalent in layout to `Option<ThinVec>`) and can be kept in a register.
 - Type safety. We mark the type `#[must_use]`, and thinks requiring errors take `ThinVec`, which requires unwrapping the type and verifying there is indeed an error. We still provide conversions to slices, `ThinVec`, and iteration, because some code needs this and I saw no benefit in changing it, but we deliberately do not provide `Deref<Target = [E]>` or things like that.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-attributes Area: Attributes (`#[…]`, `#![…]`) perf-regression Performance regression. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-clippy Relevant to the Clippy team. 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)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants