3

Is there a way to encode a function that reads the heap and returns a heap-independent snapshot? This would be very useful for an experiemental encoding I would like to develop.

For example, I tried writing a Dafny function called edges that I plan to use only for the specifications. It should take a set of Node objects and return a set of Edge objects.

class Node {
  var next: Node
  var val: int
  constructor (succ: Node, x: int) 
  {
    this.next := succ;
    this.val := x;
  }
} 

datatype Edge = Edge(x: Node, y: Node)

function{:axiom} edges(g: set<Node>): set<Edge>
  reads g
  ensures forall x:Node, y:Node {:trigger Edge(x,y)} ::
    x in g && x.next == y <==> Edge(x,y) in edges(g) 

However, I get the following error message from Dafny (using the online version of the tool):

Dafny 2.3.0.10506
stdin.dfy(26,10): Error: a quantifier involved in a function definition is not allowed to depend on the set of allocated references; Dafny's heuristics can't figure out a bound for the values of 'x'
stdin.dfy(26,10): Error: a quantifier involved in a function definition is not allowed to depend on the set of allocated references; Dafny's heuristics can't figure out a bound for the values of 'y'
2 resolution/type errors detected in stdin.dfy

It seems that the {:axiom} annotation does not have any effect in this context. Removing it will result in the same error message.

  • The `{:axiom}` annotation just tells the compiler that you intentionally omitted the body of the function. The verifier is happy with body-less declarations, but the compiler will complain about them unless they are marked `{:extern}` and `{:axiom}`. – Rustan Leino Oct 07 '19 at 19:51

1 Answers1

2

I don't know the answer to your general question, but I believe you can capture the postcondition for your concrete example with:

function{:axiom} edges(g: set<Node>): set<Edge>
  reads g
  ensures edges(g) == set x : Node | x in g :: Edge(x, x.next)

You can also just write that post condition as the function definition:

function{:axiom} edges(g: set<Node>): set<Edge>
reads g
{
  set x : Node | x in g :: Edge(x, x.next)
}

For completeness, here's the full example:

class Node {
  var next: Node
  var val: int
  constructor (succ: Node, x: int) 
  {
    this.next := succ;
    this.val := x;
  }
} 

datatype Edge = Edge(x: Node, y: Node)

function{:axiom} edges(g: set<Node>): set<Edge>
  reads g
  ensures edges(g) == set x : Node | x in g :: Edge(x, x.next)

function{:axiom} edges2(g: set<Node>): set<Edge>
reads g
{
  set x : Node | x in g :: Edge(x, x.next)
}
Daniel Ricketts
  • 447
  • 2
  • 8