-
Notifications
You must be signed in to change notification settings - Fork 89
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 ensures into closures #3207
Conversation
Hey @pi314mm, thanks a lot for contributing to fix this. I also had some ideas on how to fix it and I wonder what you think about it. The issue is that while currently Now this function suffers from the same problem as Alternatively we could do it like the stdlib which as a What do we think about this? |
I believe we should remove the functionality which defaults the "result" variable to "result" and require that the user specify the result variable for every ensures statement. The ensures statement should be thought of as a closure rather than a statement where the argument to the function is the result of the computation. This can be achieved by changing this if statement into an error statement. It would require modifying currently existing ensures statements to For the case of "old" variables, it is best to think of it as a kani function, so using "kani::old(argument)" would be a good way to parse it. Since we specify that this is the kani::old instead of just "old" we avoid collisions that way. Or it may be reasonable to do "argument@old" without spaces to represent the same concept. But regardless, this issue is tangential to the result variable. |
I can see an argument for the likeness to a closure, but if that is the way we want to go, I would actually use closure syntax instead of introducing a new one. Sure the |
That is a great idea and a lot easier and cleaner to implement! This new commit now expects a closure, then applies the internal kani result variable to this function, essentially an eta expansion. Since we are now using the built-in support for parsing closures, we can do pattern matching on the result variable. For example, the following code works:
|
Nice. This should also make it quite easy to explain. The idea of providing a closure that gets applied to the result is quite intuitive. |
I'm in favor of the change. I had in fact thought I had seen precedent for |
It seems as this was harder to implement than expected. Changing the variable names to _renamed no longer seems to be working as it was before. Will look into it. Edit: fixed Additionally, the pass of the result to the closure must be a pass by reference. |
Hmm. I'm surprised by this. I might want to locally check out your work prior to 8e2e610 and try to understand why this is necessary. Update: Oh, I bet I know why; its probably because the closure isn't set up to return the result back to the caller after the predicate runs. (You could consider injecting code into the end of the closure to do that, but then the return type would have to be something like (We actually encountered something similar to this internally within the compiler itself, in that match-arm-guards, we treat uses of identifiers bound by the match-pattern as implicitly borrowed, and automatically inject derefs of them, see rust-lang/rust#49870 for that context ...) |
I don't think passing a reference is a bad thing though. We do want to restrict the result access to be read only and passing a constant reference is a clear indication of that. |
Please also make sure to update the following public documentation
as well as the internal "desugaring" documentation in https://github.com/model-checking/kani/blob/main/library/kani_macros/src/sysroot/contracts/mod.rs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this contribution! Could you also update our RFC to reflect this change?
This change now separates the front facing "result" name and the internal facing "result_kani_internal" ident where the user can specify with the keyword "result" but then the system replaces this with the internal representation.
If the user chooses to use a different variable name than result, this now supports the syntax of
#[kani::ensures(|result_var| expr)]
where result_var can be any arbitrary name.
For example, the following test now works:
In addition, the string "result_kani_internal" is now a global constant and can be updated in a single place if needed.
Resolves #2597 since the user can specify the variable name they want within the ensures binding
An important change is that the result is now a pass by reference instead, so as in the example an
&u32
instead ofu32
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.