mut refs & type invariants #1851
Replies: 3 comments 2 replies
-
This is obviously bad, not just because it's confusing but because it breaks API safety. I think we want to use the approach I described within functions, but type invariants still need to be enforced at function boundaries. So you just wouldn't be able to write this when Or, technically: You can still implement it if the validity of Still, I think the exact rules might be a little tricky to nail down ... |
Beta Was this translation helpful? Give feedback.
-
|
Assuming we have a way to temporarily break the type invariant, can we just require that programmers manually break the type invariant for |
Beta Was this translation helpful? Give feedback.
-
|
Recent paper by the creusot folks has a bunch to say on this issue: https://inria.hal.science/hal-05244847v1/document |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I have started working out mut refs need to interact with type invariants. A really basic example is like:
We'd ideally want this to pass; the invariant is temporarily "broken" when
a_refis set to 50, but it is restored by the timefoois called.At present, we check that a type invariant is preserved on every mutation. This is overly restrictive even today, but it is clearly unworkable in the above situation. In the mut_ref encoding, the value of
pis mutated as soon as themut_refis created.Instead, we can have a policy of always restoring the type invariant "as late as possible", which in this case, would be right before the
foocall. Here, I've annotated the function with the ideal locations to resolve the mut ref and assert the type invariant:Here, we have the
assume_resolveddirectives inserted as early as possible, and theassert_type_invariantdirective inserted as late as possible. This all works out nicely, since we need the resolution assumptions in order to prove the type invariant forp.And you can see why this would work out nicely in the general case: the earliest possible spots for the resolutions will always be before the lifetime ends and
pcan be used again.The problematic case is when we're working with reborrows, because in that case, the same location is subject to BOTH
assume_resolvedandassert_type_invariantat the same time, and these are in tension with each other. Let's look at a similar example, using a reborrow:Again, let's annotate this with all the directives, putting
assume_resolvedas early as possible, andassert_type_invariantas late as possible:This doesn't look good. The problem is that we aren't enforcing the type invariant until after
foohas been called, which will assume the type invariant.So we can add a rule, the
assert_type_invariantmust always go before theassume_resolved:This is now sound, but now the
assert_type_invariantdirective is too early: we won't be able to prove the type invariant at this point. The best point, of course, is here:However, there isn't an obvious (to me) way to infer this point. The descriptor I'd give this location would be something like "the latest possible point that doesn't break lifetime checking". However, this is difficult to calculate. One option would be to require an annotation from the user here.
Another option would be to take a step back and say, "no, actually, it's not the borrower's responsibility to maintain the type invariant, it's the lender's." (just like it would be if you were borrowing a field instead of the whole thing). Thus, we just assert the type invariant for
p, notp_ref:In some ways, this is metatheoretically the cleanest. It uses clean rules like "put
assume_resolvedas early as possible, andassert_type_invariantas late as possible". You don't even need toassert_type_invariantfor the*p_refat all, sincep_refis never used.The problem is that it's also full of surprises, like if you call
some_fn_taking_a_mut_ref(&mut p), you won't necessarily know that the type invariant holds forpafterwards, unless you explicitly put it in the postcondition forsome_fn_taking_a_mut_ref.Beta Was this translation helpful? Give feedback.
All reactions