-
#[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 = [0; 10];
let r = &mut x;
#[invariant((*r)@.len() == 10)]
#[invariant(forall<i: Int> 0 <= i && i < produced.len() ==> (*r)@[i]@ == i)]
for i in 0 .. 10 {
apply_mut({
let r = &mut *r;
#[cfg_attr(creusot, requires(i@ < (*r)@.len()))]
#[cfg_attr(creusot, requires((*r)@.len() == 10))]
#[cfg_attr(creusot, ensures((*r)@.len() == (*old(r))@.len()))]
// #[cfg_attr(creusot, ensures(
// forall<k: Int> 0 <= k && k < i@ ==> (*r)@[k] == (*old(r))@[k]))]
#[cfg_attr(creusot, ensures(
forall<k: Int> 0 <= k && k < (*r)@.len() && k != i@ ==> (*r)@[k] == (*old(r))@[k]))]
#[cfg_attr(creusot, ensures((*r)@[i@] == i))]
#[cfg_attr(creusot, ensures((^r)@ == (^old(r))@))]
move || r[i] = i
});
// This fails with the commented ensures above (which should be enough).
proof_assert!(forall<k: Int> 0 <= k && k < i@ ==> (*r)@[k]@ == k);
// This always fails.
proof_assert!((*r)@[i@] == i);
}
proof_assert!(forall<i: Int> 0 <= i && i < 10 ==> x@[i]@ == i);
} I have 2 questions:
For context, ultimately I want to prove a program that abstract over the loop: fn apply_mut<F: FnMut(usize)>(n: usize, f: F) {
(0..n).for_each(f)
} |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 15 replies
-
Both questions have the same answer: you should add The reason is that because of the |
Beta Was this translation helpful? Give feedback.
-
In the end, the following works, and is much simpler than your code: #[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 = [0; 10];
let r = &mut x;
let snap_r = snapshot! { r };
#[invariant((*r)@.len() == 10)]
#[invariant(forall<i: Int> 0 <= i && i < produced.len() ==> (*r)@[i]@ == i)]
#[invariant(^r == ^*snap_r)]
for i in 0 .. 10 {
apply_mut(|| r[i] = i);
proof_assert!(forall<k: Int> 0 <= k && k < i@ ==> (*r)@[k]@ == k);
proof_assert!((*r)@[i@] == i);
}
proof_assert!(forall<i: Int> 0 <= i && i < 10 ==> x@[i]@ == i);
} |
Beta Was this translation helpful? Give feedback.
Both questions have the same answer: you should add
#[ensures(i == old(i))]
as an additional postcondition, or not use any specification (i.e., use closure specification inference).The reason is that because of the
move
keyword, the variablei
in the closure (and its specification) is really a different object than the variablei
in the outer function.