trait solver: Include implied outlives assumptions - #162238
Conversation
|
r? @jackh726 rustbot has assigned @jackh726. Use Why was this reviewer chosen?The reviewer was selected based on:
|
|
r? me |
158056d to
29846e5
Compare
|
Pushed some more changes after staring at this a bit longer, quick summary of what I did and why. Borrowck had the same gap I fixed at the regionck root. Its I couldn't come up with a test for the borrowck half. As far as I can tell borrowck still gets an empty solver constraint tree, so any test passes with or without this. Once the type-op constraints from #161423 reach borrowck it becomes testable and I'd add the regression over there. If you'd rather I drop this part until then, that's fine too. The last commit is the one I'm not sure belongs here, so I kept it separate and easy to drop. The free region map stores its edges as Small thing I noticed while writing comments is that the destructuring in cc @BoxyUwU :) |
`FreeRegionMap::relation` stores `'sub <= 'sup` edges while `Assumptions::region_outlives` expects `'longer: 'shorter` ones. The mismatch is not yet observable as nothing reads the region relation at the root, but `Assumptions::new` merges edges derived from type outlives clauses into the same relation, which would otherwise leave it with mixed edge directions.
29846e5 to
84c1b90
Compare
|
Hmm okay this all makes sense to me 🤔 I think we should definitely wait for #161423 so that the borrowck path can actually be tested.
this makes complete sense to me 🤔 can you remove the elaboration logic from the solver's logic for computing assumptions and instead rely on The other thing is that I'd actually prefer for the test suite to not rely on elaboration and instead hand write out all of the relevant requirements. When I'm looking at the custom test suite DSL I want to be able to see exactly what assumptions we have and not worry about there being "extra" ones hidden behind the scenes. Could you make it so that we have an |
| // Regions bound inside the type are ignored, but free regions still contribute outlives edges. | ||
| core::test_binder_constraints! { | ||
| impl<'b, 'd: 'b + 'static> { | ||
| forall<'a> where for<'c> fn(&'c (), &'b u8): 'a { |
There was a problem hiding this comment.
We should probably not be even letting you write such where clauses on forall since they don't do anything without elaboration (and I don't think we want to elaborate these).
| // The type outlives assumptions are still kept around as they are required for proving | ||
| // placeholder and alias outlives. | ||
| // | ||
| // This mirrors `elaborate`, in particular in how it deals with binders: they're simply |
There was a problem hiding this comment.
why not use elaborate directly here?
| // `FreeRegionMap::relation` stores `'sub <= 'sup` edges while | ||
| // `Assumptions::region_outlives` expects `'longer: 'shorter` ones, so the | ||
| // edges have to be inverted here. |
There was a problem hiding this comment.
Do we actually use region outlives assumptions in the root context like ever? I would have expect this to be more blatantly broken if we did, but I guess the only real root handling we do is destructuring type outlives constraints which doesn't care about region outlives assumptions 🤔
Part of rust-lang/project-assumptions-on-binders#19
Split out of #161988 after @BoxyUwU pointed out that these are about which assumptions we keep, not really about reflexive region constraints.
I went back through where each piece comes from and found two gaps. Inside a binder we kept
Ty: 'a, but the region relation only knew about explicit region clauses. That means something like&'b T: 'adid not also give us'b: 'a. At the root it was a slightly different version of the same problem:known_type_outliveshas the explicit where clauses, while implied bounds from things like&'b selflive inregion_bound_pairs, so constraint destructuring never saw them.Assumptions::newnow pulls the free region components out of type outlives clauses and adds those edges to the region relation. I think doing it there is the cleanest spot. All callers get the same view of an assumption, and the original type clauses stay around for placeholder and alias cases. Regions bound inside the type are ignored because they do not name anything we can use outside that binder.The root path now adds its implied type bounds to the same assumption set before destructuring. The regression uses an implied
I: 'bfrom a receiver and a separate'b: 'arelation, so it covers this without leaning on the reflexive fix from #161988. There are also binder checks for a reference and a higher-ranked function type. Those caught an easy testing trap here: a green direct constraint could have depended on the other PR, so the checks look at the lifted candidates instead.Personally, I think splitting this was the right call. It is really a change to how assumption data is built, and that is easier to reason about on its own than under the reflexive constraint fix.
cc @BoxyUwU, this is the pair of changes you asked me to pull out.