diff options
| author | bors <bors@rust-lang.org> | 2025-08-15 12:35:09 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2025-08-15 12:35:09 +0000 |
| commit | c018ae5389c49cc4bcb8343d80dd8e7323325410 (patch) | |
| tree | 8d8619118b84072672edec22e08dd394b2954274 /tests | |
| parent | ba412a6e70ac84641be7764d088acabd0eb3fa39 (diff) | |
| parent | 8afe306c381416d151f955981e7b4e47867e9d97 (diff) | |
| download | rust-c018ae5389c49cc4bcb8343d80dd8e7323325410.tar.gz rust-c018ae5389c49cc4bcb8343d80dd8e7323325410.zip | |
Auto merge of #144991 - lcnr:ignore-usages-from-ignored-candidates, r=BoxyUwU
ignore head usages from ignored candidates Fixes https://github.com/rust-lang/trait-system-refactor-initiative/issues/210. The test now takes 0.8s to compile, which seems good enough to me. We are actually still walking the entire graph here, we're just avoiding unnecessary reruns. The basic idea is that if we've only accessed a cycle head inside of a candidate which didn't impact the final result of our goal, we don't need to rerun that cycle head even if is the used provisional result differs from the final result. We also use this information when rebasing goals over their cycle heads. If a goal doesn't actually depend on the result of that cycle head, rebasing always succeeds. However, we still need to make sure we track the fact that we relied on the cycle head at all to avoid query instability. It is implemented by tracking the number of `HeadUsages` for every head while evaluating goals. We then also track the head usages while evaluating a single candidate, which the search graph returns as `CandidateHeadUsages`. If there is now an always applicable candidate candidate we know that all other candidates with that source did not matter. We then call `fn ignore_candidate_head_usages` to remove the usages while evaluating this single candidate from the total. If the final `HeadUsages` end up empty, we know that the result of this cycle head did not matter when evaluating its nested goals.
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/ui/traits/next-solver/cycles/many-where-clauses-with-aliases-hang.rs | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/tests/ui/traits/next-solver/cycles/many-where-clauses-with-aliases-hang.rs b/tests/ui/traits/next-solver/cycles/many-where-clauses-with-aliases-hang.rs new file mode 100644 index 00000000000..36fa8b85f7a --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/many-where-clauses-with-aliases-hang.rs @@ -0,0 +1,43 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// A regression test for trait-system-refactor-initiative#210. +// +// Trying to prove `T: Trait<...>` ends up trying to apply all the where-clauses, +// most of which require normalizing some `Alias<T, ...>`. This then requires us +// to prove `T: Trait<...>` again. +// +// This results in a lot of solver cycles whose initial result differs from their +// final result. Reevaluating all of them results in exponential blowup and hangs. +// +// With #144991 we now don't reevaluate cycle heads if their provisional value +// didn't actually impact the final result, avoiding these reruns and allowing us +// to compile this in less than a second. + +struct A; +struct B; +struct C; + +type Alias<T, U> = <T as Trait<U>>::Assoc; +trait Trait<T> { + type Assoc; +} + +fn foo<T>() +where + T: Trait<A> + Trait<B> + Trait<C>, + T: Trait<Alias<T, A>>, + T: Trait<Alias<T, B>>, + T: Trait<Alias<T, C>>, + T: Trait<Alias<T, Alias<T, A>>>, + T: Trait<Alias<T, Alias<T, B>>>, + T: Trait<Alias<T, Alias<T, C>>>, + T: Trait<Alias<T, Alias<T, Alias<T, A>>>>, + T: Trait<Alias<T, Alias<T, Alias<T, B>>>>, + T: Trait<Alias<T, Alias<T, Alias<T, C>>>>, + T: Trait<Alias<T, Alias<T, Alias<T, Alias<T, A>>>>>, + T: Trait<Alias<T, Alias<T, Alias<T, Alias<T, B>>>>>, + T: Trait<Alias<T, Alias<T, Alias<T, Alias<T, C>>>>>, +{ +} +fn main() {} |
