summaryrefslogtreecommitdiff
path: root/Test/dafny1/ListCopy.dfy
blob: 4bb2645cfd4cb4529b8a67335ce7349fa463fcc3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// RUN: %dafny /compile:0 /dprint:"%t.dprint" "%s" > "%t"
// RUN: %diff "%s.expect" "%t"

class Node {
  var nxt: Node;

  method Init()
    modifies this;
    ensures nxt == null;
  {
    nxt := null;
  }

  method Copy(root: Node) returns (result: Node)
    decreases *;
  {
    var existingRegion: set<Node>;
    assume root == null || root in existingRegion;
    assume (forall o: Node :: o != null && o in existingRegion && o.nxt != null ==> o.nxt in existingRegion);

    var newRoot := null;
    var oldListPtr := root;
    var newRegion: set<Node> := {};

    if (oldListPtr != null) {
      newRoot := new Node.Init();
      newRegion := newRegion + {newRoot};
      var prev := newRoot;

      while (oldListPtr != null)
        invariant newRoot in newRegion;
        invariant (forall o: Node :: o in newRegion ==> o != null);
        invariant (forall o: Node :: o in newRegion && o.nxt != null ==> o.nxt in newRegion);
        invariant prev in newRegion;
        invariant fresh(newRegion);
        invariant newRegion !! existingRegion;
        decreases *;  // omit loop termination check
      {
        var tmp := new Node.Init();

        newRegion := newRegion + {tmp};
        prev.nxt := tmp;

        prev := tmp;
        oldListPtr := oldListPtr.nxt;
      }
    } 
    result := newRoot;
    assert result == null || result in newRegion;
    
    // everything in newRegion is fresh
    assert fresh(newRegion);

    // newRegion # exisitingRegion
    assert newRegion !! existingRegion; 
  }
}