Skip to content

Optimize handling of solver errors - #160160

Merged
rust-bors[bot] merged 2 commits into
rust-lang:mainfrom
ChayimFriedman2:if-empty-opt
Aug 7, 2026
Merged

Optimize handling of solver errors#160160
rust-bors[bot] merged 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

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
@rust-bors

This comment has been minimized.

@rustbot

This comment has been minimized.

@rust-bors

This comment has been minimized.

@rustbot

This comment has been minimized.

@rust-bors

This comment has been minimized.

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 commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main 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.

@TaKO8Ki

TaKO8Ki commented Aug 6, 2026

Copy link
Copy Markdown
Member

@bors r+

@rust-bors

rust-bors Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

📌 Commit 5491ec8 has been approved by TaKO8Ki

It is now in the queue for this repository.

🌲 The tree is currently closed for pull requests below priority 6. This pull request will be tested once the tree is reopened.

Reason for tree closure: Github problems

@rust-bors rust-bors Bot 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 Aug 6, 2026
@rust-bors

This comment has been minimized.

@rust-bors rust-bors Bot added merged-by-bors This PR was explicitly merged by bors. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Aug 7, 2026
@rust-bors

rust-bors Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

☀️ Test successful - CI
Approved by: TaKO8Ki
Duration: 2h 59m 40s
Pushing ae45457 to main...

@rust-bors
rust-bors Bot merged commit ae45457 into rust-lang:main Aug 7, 2026
14 checks passed
@rustbot rustbot added this to the 1.99.0 milestone Aug 7, 2026
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
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 88f7399 (parent) -> ae45457 (this PR)

Test differences

Show 44 test diffs

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

Test dashboard

Run

cargo run --manifest-path src/ci/citool/Cargo.toml -- \
    test-dashboard ae45457594a670c59cd4d5591eaa243d9a3d44d5 --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. dist-aarch64-apple: 1h 28m -> 2h 10m (+47.7%)
  2. x86_64-gnu-aux: 1h 51m -> 2h 34m (+38.5%)
  3. i686-msvc-2: 1h 31m -> 2h 4m (+36.2%)
  4. aarch64-apple-2: 1h 58m -> 2h 40m (+34.9%)
  5. i686-gnu-nopt-1: 2h 18m -> 1h 36m (-30.6%)
  6. dist-riscv64-linux-gnu: 1h 6m -> 1h 26m (+29.0%)
  7. dist-riscv64-linux-musl: 1h 7m -> 1h 27m (+29.0%)
  8. dist-powerpc64-linux-gnu: 1h 7m -> 1h 26m (+28.6%)
  9. test-various: 1h 36m -> 2h 2m (+26.9%)
  10. dist-arm-linux-musl: 1h 20m -> 1h 42m (+26.9%)
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.

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

Labels

A-attributes Area: Attributes (`#[…]`, `#![…]`) merged-by-bors This PR was explicitly merged by bors. perf-regression Performance regression. 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