-
Notifications
You must be signed in to change notification settings - Fork 268
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Change the implementation of reveal/opaque to binary trigger, not fuel #3778
Comments
Thank you for the clear write-up and the clever suggestion. It would be very nice to, as you state, divorce the opaqueness encoding from the fuel encoding. I presume I have but one concern, which is what happens when this encoding is used inside a quantifier. Suppose a user writes a Dafny expression forall x :: 10 <= x < 20 ==> P(x) This would be translate into Boogie as (forall x: int ::
{ P(CanRevealFuel($LS($LZ), is_revealed_P), x) }
10 <= x && x < 20 ==> P(CanRevealFuel($LS($LZ), is_revealed_P), x)) I have filled in the trigger in the way that Dafny's auto-trigger would. Note that a trigger does not get massaged by the SMT solver. So, even if P(CanRevealFuel($LS($LZ), true), E) floating around in order for the SMT solver to instantiate the quantifier with It would be good to:
|
That's a very good observation. The thing I envision is that, for every call to P translated to Boogie, I'm using this CanBeRevealed wrapper.
So I wrote the following Dafny program
And I manually changed P(12) so that it does not use
Because of the observation above, erasing |
How opaque is currently implemented
To ensure recursive functions do not unroll indefinitely, Dafny uses a "fuel" attribute, which is set to 2 in the context of an assert, and 1 in the context of an assume. It ensures the axioms of the function do not unroll the function more than required.
For example:
Dafny is unable to prove the assertion. However, if we replace the 3s by 2s, Dafny would succeed.
The amount of fuel that can be used is currently an annotation on the function
{:fuel <lowfuel>,<highfuel>}
.Interestingly, if we set up this fuel to 0,0 or unknown constants, the function body is never available. This insight made it possible to figure out an opaque mechanism: Pretend the fuel is an unknown constant. To reveal it, assume this unknown constant is
1+another constant
for assumptions or1+(1+another constant)
for assertions, which let the axioms unfold the function as usual.For opaque functions, the attribute
{:fuel }
actually sets up the increase fromanother constant
. It's just that these values are revealed only when passed to reveal().Problems with opaque = assumption of non-zero fuel
opaque
function called within lambda is not opaque! #3719, the problem is that opaque functions are provided with constant non-zero fuel that comes from a lambda expression. Looking at the code, it looks like it's by design, as a lambda expression starts a built-in functionAtLayer
which automatically provides a global fuel for the expressions belowProposed solution
Currently, fuel is encoded as unary numbers:
0 = $LZ
and1 + fuel = $LS(<fuel>)
and uninterpreted variables for opaque functions.I suggest that the opaqueness of functions be not related to the fuel, so that there is no interference. Whenever we have an opaque function call
P(<fuel>, x)
, we would thus have as first fuel argument the following expression:is_revealed_p
is abool
constantThe axiom is that
meaning that without knowing is_revealed_p, it's never possible to extract fuel from a
CanRevealFuel()
expression.And the
reveal()
call would do nothing else than assumingis_revealed_p
The text was updated successfully, but these errors were encountered: