尝试见证null:操作结果可能违反子集类型约束

时间:2018-03-01 00:52:19

标签: dafny

我编写了一个表示集合S上的二元关系的类,它有两个字段:set,S和从S中抽取的第二组值。该类定义了一堆关系属性,例如是单值(即,作为函数,如“isFunction()”谓词中定义的)。在类定义之后,我尝试定义一些子集类型。一种意思是定义这些关系的子类型,它们实际上也是“函数”。它不起作用,解码生成的错误代码有点困难。请注意,Valid()和isFunction()谓词确实声明“读取此内容”。关于我应该在哪里寻找的任何想法?是不是Dafny不能说子集类型是有人居住的?有没有办法说服它呢?

public class FindActivity extends FragmentActivity implements LoaderManager.LoaderCallbacks<Cursor>, ListChooserDialogListener
{

[Dafny VSCode]尝试见证null:操作结果可能违反'binRelOnS'的子集类型约束

1 个答案:

答案 0 :(得分:1)

子集类型和非空虚

表单的子集类型定义

type MySubset = x: BaseType | RHS(x)

引入MySubset作为一种类型,代表满足布尔表达式x的类型BaseType的值RHS(x)。由于Dafny中的每个类型都必须是非空的,因此有证据证明您声明的类型具有某个成员。 Dafny可能会找到一些候选值,并会尝试查看其中任何一个是否满足RHS。如果候选人没有,你会收到一条错误消息,就像你看到的那样。有时,错误消息会告诉您Dafny尝试了哪些候选值。

在您的情况下,Dafny尝试的唯一候选值是值null。正如James指出的那样,值null甚至没有达到一垒,因为示例中的BaseType是一种非空引用。如果您将binRelOnS<T>更改为binRelOnS?<T>,则null有可能成为可能的证人,表明您的子集类型是非空的。

用户提供的证人

由于Dafny对于提出候选人证人并不太聪明,你可能需要自己提供一个。您可以通过在声明末尾添加witness子句来完成此操作。例如:

type OddInt = x: int | x % 2 == 1 witness 73

由于73满足RHS约束x % 2 == 1,因此Dafny接受此类型。在某些程序中,您可能会想到只有鬼代码才能使用您的见证。然后,您可以编写ghost witness而不是witness,这允许后续表达式为ghost。 ghost见证可以用来说服Dafny验证器类型是非空的,但它不能帮助Dafny编译器初始化该类型的变量,因此您仍然需要自己初始化这些变量。

使用witness子句,您可以尝试使用子集类型func的原始定义来提供自己的见证。但是,见证子句采用表达式而不是语句,这意味着您无法使用new。如果你不关心编写你的程序,并且你愿意相信自己对证人的存在,你可以声明一个无体功能,承诺返回一个合适的证人:

type MySubset = x: BaseType | RHS(x) ghost witness MySubsetWitness()

function MySubsetWitness(): BaseType
  ensures RHS(MySubsetWitness())

您需要ghost witnessfunction method。函数MySubsetWitness将永远留在没有正文的情况下,因此您可以在某个值满足RHS的情况下犯错误。

Dafny版本2.0.0中引入了witness子句。 2.0.0 release notes提到了这一点,但显然没有给出太多解释。如果您想查看witness的更多示例,请在Dafny test suite中搜索该关键字。

类的子集类型

在您的示例中,如果将基本类型更改为可能为null的引用类型:

type func<T> = f: binRelOnS?<T> | f.Valid() && f.isFunction()

然后您的下一个问题是RHS解除引用f。您可以通过弱化子集类型约束来解决此问题,如下所示:

type func<T> = f: binRelOnS?<T> | f != null ==> f.Valid() && f.isFunction()

现在可能是交易破坏者的部分。子集类型不能依赖于可变状态。这是因为类型是一个非常静态的概念(与规范不同,通常取决于状态)。如果一个值可以满足一个类型的时刻,然后在程序中的一些状态更改之后,不满足该类型,那将是一场灾难。 (实际上,几乎所有具有子集/细化/依赖类型的类型系统都是用于函数式语言。)因此,如果您的ValidisFunction谓词具有reads子句,那么您无法定义{以你希望的方式{1}}但是,只要funcValid都只依赖于类中isFunction个字段的值,就不需要const子句,而且你都已经设置好了。< / p>

Rustan