add a FCW for overflow errors with the next solver#159224
Conversation
|
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
[WIP] add FCW for overflow with the next solver
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Finished benchmarking commit (6eb68d9): comparison URL. Overall result: ❌ regressions - 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 @bors rollup=never rustc-perf Instruction countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
Max RSS (memory usage)Results (primary -2.1%, secondary -0.9%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (secondary -4.2%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeThis perf run didn't have relevant results for this metric. Bootstrap: 487.42s -> 490.943s (0.72%) |
725357d to
4a67928
Compare
This comment has been minimized.
This comment has been minimized.
4a67928 to
7640bb3
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
7640bb3 to
a69af77
Compare
This comment has been minimized.
This comment has been minimized.
a69af77 to
20e6271
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
The impl itself looks good to me 🤔 though I do really want to move the reevaluation out of evaluate_root_goal[_for_proof_tree] even if you need to have separate methods for root and proof tree.
I think this compat hack is non-trivial and having it be self-contained with a comment explaining why and what we do here feels very valuable for people looking at this while trying to understand how the trait solver works.
b72b605 to
a2cddc6
Compare
a2cddc6 to
4cf94be
Compare
This comment has been minimized.
This comment has been minimized.
4cf94be to
3eeca33
Compare
| .placeholder_assumptions_for_next_solver | ||
| .clone(), | ||
| next_trait_solver: self.next_trait_solver, | ||
| disable_next_solver_overflow_fcw: self.disable_next_solver_overflow_fcw, |
There was a problem hiding this comment.
change the flag to "enable_next_solver_overflow_fcw" negated booleans are always somewhat meh imo !disable_next_solver_overflow_fcw is harder to parse than !enable_next_solver_overflow_fcw
| /// The `recursion_depth_exceeding_limit` lint detects situations where the obligation evaluation | ||
| /// overflows with the next solver but not with the old solver. | ||
| /// | ||
| /// ### Example | ||
| /// ```text | ||
| /// rustc -Znext-solver example.rs | ||
| /// ``` | ||
| /// | ||
| /// ```rust,ignore (requires next solver) | ||
| /// #![recursion_limit = "8"] | ||
| /// struct Foo<T> { | ||
| /// t: T, | ||
| /// opt_t: Option<T>, | ||
| /// } | ||
| /// fn require_sync<T: Sync>() {} | ||
| /// fn main() { | ||
| /// require_sync::<Foo<Foo<Foo<Foo<Foo<Foo<()>>>>>>>(); | ||
| /// } | ||
| /// ``` | ||
| /// | ||
| /// This will produces: | ||
| /// ```text | ||
| /// error[E0275]: overflow evaluating the requirement `Foo<Foo<Foo<Foo<Foo<Foo<()>>>>>>: Sync` | ||
| /// --> example.rs:12:20 | ||
| /// | | ||
| /// | require_sync::<Foo<Foo<Foo<Foo<Foo<Foo<()>>>>>>>(); | ||
| /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| /// | | ||
| /// = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate | ||
| /// note: required by a bound in `require_sync` | ||
| /// --> example.rs:9:20 | ||
| /// | | ||
| /// | fn require_sync<T: Sync>() {} | ||
| /// | ^^^^ required by this bound in `require_sync` | ||
| /// ``` | ||
| /// | ||
| /// ### Explanation | ||
| /// | ||
| /// The trait solvers use a recursion limit to avoid hangs from deeply nested obligations. | ||
| /// They also use caches to avoid redundant computation. This is a performance optimization and | ||
| /// shouldn't affect the final evaluation result. | ||
| /// | ||
| /// However, the old solver doesn't validate depth requirement when looking up cache. This means | ||
| /// evaluation results depend on whether cache entries exists which in turn depends on cache | ||
| /// insertion order. | ||
| /// | ||
| /// The next solver correctly records and validates recursion depth requirements when using | ||
| /// the cache. This makes it more prone to overflow compared to the old solver. | ||
| /// | ||
| /// This is a [future-incompatible] lint to transition this to a hard error in the future. |
There was a problem hiding this comment.
similar to the lint name, we should not tell the user about implementation details here.
I think the focus should be "this lint detects cases where we previously did not correctly track the recursion depth"
I would now say that it happens in "obligation evaluation" and would put the explanation that this is because of the "new solver" to later in the explanation, not in the initial summary
| { | ||
| // We still check coherence typing mode because we don't use the next solver in orphan check | ||
| // by default yet and orphan check uses `TypingMode::Coherence`. | ||
| if delegate.disable_next_solver_overflow_fcw() || delegate.typing_mode_raw().is_coherence() { |
There was a problem hiding this comment.
don't need an || here as we can just set the flag in coherence?
|
r=me after nits |
ff3570f to
ddae312
Compare
This comment has been minimized.
This comment has been minimized.
ddae312 to
203ebf2
Compare
|
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. |
|
@bors r=lcnr |
This comment has been minimized.
This comment has been minimized.
add a FCW for overflow errors with the next solver The old solver doesn't check cache entry's depth requirement when looking up cache while the next solver correctly does so. It's necessary to behave correctly with respect to incremental compilation. As a result, the next solver is more likely to run into overflow errors. We try to catch such breakages by rerun the evaluation with doubled recursion limit and if that succeeds we emit a FCW. This PR is being discussed on [zulip](https://rust-lang.zulipchat.com/#narrow/channel/364551-t-types.2Ftrait-system-refactor/topic/The.20old.20solver.20don.27t.20record.20required.20depth.20on.20cache/with/604756008) The lint issue is #159228 r? @lcnr
|
💔 Test for 61842aa failed: CI. Failed job:
|
|
A job failed! Check out the build log: (web) (plain enhanced) (plain) Click to see the possible cause of the failure (guessed by this bot) |
|
@bors retry |
View all comments
The old solver doesn't check cache entry's depth requirement when looking up cache while the next solver correctly does so. It's necessary to behave correctly with respect to incremental compilation.
As a result, the next solver is more likely to run into overflow errors.
We try to catch such breakages by rerun the evaluation with doubled recursion limit and if that succeeds we emit a FCW.
This PR is being discussed on zulip
The lint issue is #159228
r? @lcnr