Type invariants #962
Replies: 2 comments 2 replies
-
FWIW, VCC allows you to associate a type invariant with a type definition, and it can be a one- or two-state predicate. I think you can rely on the invariant if you know the object is Chalice has a Java-like notion of certain classes being designated as "monitors" which have a monitor invariant that can hold onto implicit-dynamic-frame permissions. Hence this behaves like a lock invariant in Verus. |
Beta Was this translation helpful? Give feedback.
-
FWIW, it looks like Dominik Stolz wrote an MS thesis about type invariants in Creusot, which might be relevant. |
Beta Was this translation helpful? Give feedback.
-
Background
It's very common to have types to have "well-formedness" predicates that need to be carried around everywhere, usually called
wf(&self)
orwell_formed(&self)
or similar.It would be ideal to make these automatic so that we don't have to manually cart around the predicates everywhere, especially when 'wf' is 'closed'. Having these be automatic also makes it easier to use generic code (so the generic code doesn't have to reason about the well-formedness of its types) and makes it possible to specify "safe APIs" that rely on internal type invariants.
Broken invariants
One of the challenges with the feature is how to handle temporarily-broken invariants.
Suppose we wanted to do:
We might want to write a function where the invariant is temporarily broken and restored at the end:
Ordinarily, this wouldn't be an issue using the existing idiom of just putting
x.wf()
in the precondition and postcondition.Doing this soundly is somewhat difficult; as I understand it, it's especially nontrivial in the presence of &mut and prophecies.
However, I observe that we already have a sound way to handle temporarily broken invariants, which is the mask system we use for AtomicInvariant & LocalInvariant. Using this, it's possible to "encode" temporarily broken invariants if you already have always-on invariants.
The idea is to have an "invariant switch" that can enable or disable the invariant:
There's a problem here, which is that now we need to cart around the predicate
x.invariant_is_enabled == true
, which defeats the whole point. However, if were to treat the 'invariant_is_enabled' flag as a special Verus built-in thing, then Verus's mask system could serve as a lightweight way to disable the invariants.In fact, it's already possible to encode something like this using ghost objects:
I'm not saying we should actually do it like this, this is really cumbersome and involves lugging around a lot of ghost state. But I think we could use this as a sort of template for designing a more lightweight system.
Conclusion
I haven't made a concrete design for anything, but I propose that the design problem can be divided into roughly orthogonal components:
Beta Was this translation helpful? Give feedback.
All reactions