-
Consider the following example: #[requires(f.precondition(()))]
#[ensures(f.postcondition_once((), ()))]
fn apply_once<F: FnOnce()>(f: F) {
f()
}
#[requires(f.precondition(()))]
#[ensures(exists<g: F> f.postcondition_mut((), g, ()) && resolve(&g))]
fn apply_mut<F: FnMut()>(mut f: F) {
f()
}
fn foo() {
let mut x = 13;
let r = &mut x;
#[invariant((*r)@ == 13 + produced.len())]
for _ in 0 .. 42 - 13 {
// BEGIN loop body
let r = &mut *r;
apply_once(
#[cfg_attr(creusot, requires((*r)@ < 42))]
#[cfg_attr(creusot, ensures((^old(r))@ == (*old(r))@ + 1))]
move || *r += 1,
);
// END loop body
}
proof_assert!(x@ == 42);
} As written it passes
Thanks! |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 3 replies
-
This works (needs to relate the mutable reference of the capture before and after the call): #[cfg_attr(creusot, requires((*r)@ < 42))]
#[cfg_attr(creusot, ensures((*r)@ == (*old(r))@ + 1))]
#[cfg_attr(creusot, ensures((^r)@ == (^old(r))@))] |
Beta Was this translation helpful? Give feedback.
-
It seems to me the problem is that variables in the contract don't refer to the captured field in the closure but to the captured variable outside the closure. Maybe the problem is that non- |
Beta Was this translation helpful? Give feedback.
-
Your example reveals several problems in Creusot, thanks! 1- The annotation we would like to write is: #[requires((*r)@ < 42)]
#[ensures((*old(r))@ == (*r)@ + 1)]
|| *r += 1 However, for some reason, the borrow checker refuses it. It seems like variables used in But in fact, in this simple case, we don't need an annotation, Creusot can infer the specification of he closure. So we can simply remove 2- We usually have a static analysis which proves that prophecies of borrows in local variables are constant. But when a borrow is captured in a closure, then this analysis fails. Thus we need to insert the invariant manually: let snap_r = snapshot!{ r };
#[invariant((*r)@ == 13 + produced.len())]
#[invariant(^*snap_r == ^r)]
for _ in 0 .. 42 - 13 { And then, this works both with |
Beta Was this translation helpful? Give feedback.
Your example reveals several problems in Creusot, thanks!
1- The annotation we would like to write is:
However, for some reason, the borrow checker refuses it. It seems like variables used in
old
are not ignored by the borrow checker. I just reported it as #1396.But in fact, in this simple case, we don't need an annotation, Creusot can infer the specification of he closure. So we can simply remove
requires
/ensures
. But it does not work in you example because...2- We usually have a static analysis which proves that prophecies of borrows in local variables are constant. But when a borrow is captured in a closure, then …