Reputation: 447
I have a class that allocates an iterator on the heap and calls MoveNext()
on that iterator. I want to prove that if MoveNext()
returns true
, Valid()
holds for the iterator.
iterator Iter()
{}
class MyClass
{
var iter : Iter;
constructor ()
{
iter := new Iter();
}
method next() returns (more : bool)
requires iter.Valid();
modifies iter, iter._new, iter._modifies;
{
more := iter.MoveNext();
// This assertion fails:
assert more ==> iter.Valid();
}
}
I took a look at the output of /rprint
, and the method MoveNext()
contains ensures more ==> this.Valid()
, which seems to imply my desired assertion. If I change iter to be locally allocated within the method next()
, then Dafny verifies the assertion.
Upvotes: 0
Views: 86
Reputation: 2097
The problem is that nothing is known about what's in iter._new
and iter._modifies
. If this
is in one of those sets, then this.iter
may have changed during the call to MoveNext()
.
This body for next()
confirms what I just said:
var i := iter;
more := iter.MoveNext();
assert i == iter; // this assertion fails
assert more ==> iter.Valid();
So, under the assumption more
, Valid()
does still hold of the iterator, but the iterator may no longer referenced by iter
:
more := iter.MoveNext();
assert more ==> old(iter).Valid(); // this holds
Probably the way you want to solve this problem is to add a precondition to next()
:
method next() returns (more : bool)
requires iter.Valid()
requires this !in iter._new + iter._modifies // add this precondition
modifies iter, iter._new, iter._modifies
{
more := iter.MoveNext();
assert more ==> iter.Valid(); // this now verifies
}
Rustan
Upvotes: 1