调用可能违反上下文的Modifys子句

时间:2019-11-19 02:24:42

标签: dafny

我正在编写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()时发生的。

2 个答案:

答案 0 :(得分:1)

方法HeadTail()说它修改了thisthis.buf。方法Main调用HeadTail上的q,这意味着该调用修改了qq.buf。方法Main执行new以获得q,因此允许Main修改q。但是没有有关q.buf是什么的信息。要修改q.bufMain必须证明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子句。