我正在编写dafny代码以验证函数,该代码更改了队列的头部和尾部,该函数本身得到了验证,但是当我添加main函数时,我得到了错误:调用可能违反了上下文的modify子句,我的方法没有任何新方法,因此无需编写确保最新的方法。我不知道问题出在哪里,任何人都可以帮助我。
class Quack<Data>
{
var buf: array<Data>;
var m: int, n: int;
ghost var shadow: seq<Data>;
predicate Valid() reads this, this.buf
{ buf!=null && buf.Length!=0 && 0<=m<=n<=buf.Length && shadow==buf[m..n] }
...
method HeadTail() modifies this, this.buf
requires Valid()
ensures Valid()
ensures buf.Length == old(buf.Length)
ensures |shadow| == |old(shadow)|
ensures n == old(n) && m == old(m)
ensures if n-m > 1 then (shadow[0] == buf[m] == old(buf[n-1])) && (shadow[|shadow| - 1] == buf[n-1] == old(buf[m]))
&& shadow[1..|shadow| - 1] == old(shadow[1..|shadow| - 1])
&& forall i:: (0 <= i < buf.Length && i != m && i != n-1) ==> (buf[i] == old(buf[i]))
else buf == old(buf) && shadow == old(shadow)
{
if(n-m > 1){
buf[n-1], buf[m] := buf[m], buf[n-1];
shadow := [buf[m]] + shadow[1..|shadow| - 1] + [buf[n - 1]];
}
}
}
method Main()
{ var q:= new Quack<char>(10);
var l: char;
q.Push('r'); q.Push('s'); q.Push('k'); q.Push('o'); q.Push('w');
l:= q.Pop(); assert l=='w'; print l;
q.HeadTail();
l:= q.Qop(); assert l=='o'; print l;
l:= q.Pop(); assert l=='r'; print l;
q.HeadTail();
l:= q.Qop(); assert l=='k'; print l;
q.HeadTail();
l:= q.Qop(); assert l=='s'; print l;
var e: bool:= q.Empty();
if e {print "\nqueue empty\n";} else {print "\nqueue not empty\n";}
}
错误是在第二次和第三次我在main中调用q.HeadTail()时发生的。
答案 0 :(得分:1)
方法HeadTail()
说它修改了this
和this.buf
。方法Main
调用HeadTail
上的q
,这意味着该调用修改了q
和q.buf
。方法Main
执行new
以获得q
,因此允许Main
修改q
。但是没有有关q.buf
是什么的信息。要修改q.buf
,Main
必须证明q.buf
是新分配的(也就是说,自Main
的开头开始分配;换句话说,q.buf
必须是新鲜Main
。
我看不到您对构造函数和Push
的说明,但我怀疑您需要在构造函数的后置条件中说出fresh(buf)
。然后,作为Push
的后置条件,您可以编写
ensures buf == old(buf) || fresh(buf)
但是,如果您的Quack
类从不更改buf
(我无法确定它是否不变),那么将buf
声明为不可变的会更简单:< / p>
const buf: array<Data>
Rustan
答案 1 :(得分:1)
Dafny仅会修改已确保新鲜的数组,这意味着它会分配数组本身-请记住buf
只是一个指针!您必须在ensures buf == old(buf)
中包含HeadTail
才能告诉Dafny buf
仍然是最新的(这样,断言将从以前的方法中使用ensures fresh(buf)
继承)。>
如您所见,HeadTail
不会因先前fresh(buf)
被断言而在第一次调用时失败,但是在此知识丢失之后立即发生-导致{{1 }}违反了modify子句。