You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Dafny循环调用push_back触发modifies子句违反错误解决咨询

问题原因分析
  • 核心报错根源:Dafny的循环默认拥有空的modifies集合,即默认不允许修改任何堆上的对象/字段。你没有给for循环显式声明允许修改的内容,调用会修改Vector字段和数组内容的push_back自然会触发modifies clause违反错误,和你是否加sameBuffer谓词无关。
  • push_back的modifies子句设计不规范:原声明modifies this粒度太粗,虽然逻辑上不算错,但你去掉this后没有把push_back实际修改的thiscapacity、thisbuffer字段补上,自然会在调用同样会修改字段的extend_buffer时报错。
  • 新增的sameBuffer@L(arr)不变量本身逻辑不成立:你的循环会执行16次(初始capacity为16,循环范围是0到15),第16次调用push_back时会触发扩容,buffer会被替换为新的数组,这时候必然不满足和初始buffer相等的条件,所以这个不变量不可能保持到循环结束。
可行解决步骤
  1. 首先修正push_back的modifies子句,显式列出所有实际会修改的内容,原有ensures和实现逻辑保持不动即可:
method push_back(value:T)
requires Valid()
// 原有ensures子句全部保留
modifies this`size, this`capacity, this`buffer, this.buffer
{
  // 原有实现全部保留
}
  1. 给for循环补充modifies子句和缺失的不变量,让Dafny明确循环允许修改的范围,以及size和循环变量的对应关系:
method push_back_should_extend()
{
    var arr := new Vector(0);
    label L:
    var oracleValue := 7;

    for i : int := 0 to arr.capacity - 1
    modifies arr`size, arr`capacity, arr`buffer, arr.buffer // 显式声明循环允许修改的内容
    invariant arr.Valid()
    invariant arr.size == i // 明确size和循环变量的对应关系,帮助Dafny推导扩容触发时机
    {
        arr.push_back(oracleValue);
    }
}
  1. 如果你需要验证前15次调用确实没有触发扩容,可以额外加一个分支式的不变量:
invariant if i < old(arr.capacity) then arr.buffer == old@L(arr.buffer) else true
额外优化建议

如果想要进一步简化验证,可以把push_back的ensures子句中重复的fresh(buffer)相关判断合并为一行,减少Dafny的重复推导开销。

内容的提问来源于stack exchange,提问作者twhatm9

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 17:54:04