abby: always store nextgen region constraints in canonical form - #161306
abby: always store nextgen region constraints in canonical form#161306BoxyUwU wants to merge 10 commits into
Conversation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
d860264 to
c64bf00
Compare
This comment has been minimized.
This comment has been minimized.
c64bf00 to
57b2d5e
Compare
This comment has been minimized.
This comment has been minimized.
57b2d5e to
c17800a
Compare
This comment has been minimized.
This comment has been minimized.
aba4012 to
56320f9
Compare
This comment has been minimized.
This comment has been minimized.
5bedfe3 to
65f3b73
Compare
This comment has been minimized.
This comment has been minimized.
a10cd16 to
930ca67
Compare
This comment has been minimized.
This comment has been minimized.
930ca67 to
1bead00
Compare
|
The job Click to see the possible cause of the failure (guessed by this bot) |
|
☔ The latest upstream changes (presumably #161505) made this pull request unmergeable. Please resolve the merge conflicts by rebasing. |
| a.0.clone() | ||
| .into_iter() | ||
| .map(|a_and| And::new(a_and.0.into_iter().chain(b_and.0.clone()))), | ||
| ); | ||
| } |
There was a problem hiding this comment.
nit: IMO either have this whole thing be iterator-based, or have none of it be, not in between
let mut ands = Vec::new();
for b_and in b.0 {
for a_and in &a.0 {
ands.push(And::new(a_and.0.clone().into_iter().chain(b_and.0.clone())));
}
}or
let ands = b.0.into_iter().flat_map(|b_and| {
a.0.clone()
.into_iter()
.map(move |a_and| And::new(a_and.0.into_iter().chain(b_and.0.clone())))
});| .collect::<IndexSet<_>>() | ||
| .into_iter() | ||
| .collect::<Vec<_>>() | ||
| .into_boxed_slice(), |
There was a problem hiding this comment.
nit: .collect() works into Box<[_]>, so this can just be .collect() without .into_boxed_slice().
(unless there's some perf reason to do double? idk what exactly the collect impl for a boxed slice is, if it has excess elements at the end or whatever).
there's a few other places that could be more clever about iterators and collects and whatnot, e.g. Or::new, that would remove excess allocations, but tbh this is all wip perf hell anyway and probably doesn't matter at the moment
| /// | ||
| /// It should also already be "evaluated", as in if `or_constraint` is `false` then `and_constraint` should be | ||
| /// empty. Or if an element in the `or_constraint` is `true` then it should be the only constraint. | ||
| pub struct CanonicalFormRegionConstraint<I: Interner> { |
There was a problem hiding this comment.
nit: this struct is referred to in a bunch of places, and I personally kinda dislike having the implementation detail of the wording of "canonical form" splatted over the rest of the codebase where it kinda doesn't care that this is a bag of ands and an or of ands.
thinking of alternatives, hmm, RegionConstraints is kind of a bad name since it's just a single letter difference, but idk, some kind of bikeshed. But shrug, doesn't particularly matter, name is fine as-is too.
title. introduce an
And/Or/LeafConstraint/CanonicalFormRegionConstrainttypes to reason about the structure of our region constraints. Never produce arbitrarily nested or/ands and always have constraints in an evaluated form.I kinda mucked up this PR and accidentally did two things at the same time. Not only do we immediately put everything into canonical form, we also change what it means for a region constraint to be in canonical form. Whoops :>
Rough overview of what a
CanonicalFormRegionConstraintis:CanonicalFormRegionConstraintcontains two things: anAND of LEAFsand anOR of AND of LEAFs. Another way of thinking about it would be to say its anANDconsisting of arbitrarily many LEAFs and a singleOR of AND of LEAFsfalsethen we wipe the top levelANDas it doesn't matter what they are, the constraint is always going to be falsethis simplifies a lot of things conceptually as we now no longer need to worry about what state our region constraints are in. and our algorithms also don't need to handle arbitrary nesting of ors/ands :) and its a lot easier to read the debug logs 😅
I also wound up needing to do this while trying to compile
std/corewith-Zassumptions-on-bindersas we would otherwise OOM from having both:And('a: 'b, 'a: 'b))OR(e.g.Or(And('a: 'b, 'b: 'c), And('a: 'b, 'b: 'd)))Some future work:
CanonicalFormRegionConstraint::splatted_and_constraintsit's kind of weird to even need it and probably encourages bad-for-perf patternsCanonicalFormRegionConstraint. Perf stuff :3In theory this PR should mostly not have functional changes. In practice it might affect some things due to changing the exact repr of things affecting query responses. There's probably also some behaviour differences here due to us falling on our face more or less in WIP parts of abby now that we have different region constraints. I don't think any of this should be meaningful though. This PR is intended to not fundamentally change the abby algorithm :3
This PR should be reviewed commit-by-commit. There are a bunch of commits restructuring existing logic to assume their input is in canonical form as it will be by the end of the PR.
Then there's the core change in 70a8c63 which actually replaces
RegionConstraintwith all the new types and updates all the locations using them.Finally there's 1bead00 which deals with the leftover
evaluate_solver_constraintwhich was mostly unnecessary now due to moving its main logic into construction ofCanonicalFormRegionConstraintand friends. I didn't want to make actual bug fixes in this PR so I just left some FIXMEs about some of the issues thatpropagate_ambiguityhas instead of fixing them here.Fixes rust-lang/project-assumptions-on-binders#14
This will merge conflict with both #161443 and #158588. I don't expect this PR to get approved before those but if it does I intend to wait for those PRs to land first then merge this.