summaryrefslogtreecommitdiff
path: root/Test/dafny0/Reads.dfy
blob: 7e0ca1c4259f2b3d2087699cc21aa0c9270afcbc (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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// RUN: %dafny /compile:0 "%s" > "%t"
// RUN: %diff "%s.expect" "%t"

// Checking that the reads clause also is checked over requires

class C { var u : int; }

function nope1(c : C):()
     requires c != null && c.u > 0;
{()}

function ok1(c : C):()
     requires c != null && c.u > 0;
     reads c;
{()}

function nope2(c : C):()
     requires c != null && c.u > 0;
     reads if c != null then {} else {c};
{()}

function ok2(c : C):()
     requires c != null && c.u > 0;
     reads if c != null then {c} else {};
{()}

function nope3(xs : seq<C>):()
     requires |xs| > 0 && xs[0] != null && xs[0].u > 0;
{()}

function ok3(xs : seq<C>):()
     requires |xs| > 0 && xs[0] != null && xs[0].u > 0;
     reads xs;
{()}

function nope4(c : C, xs : set<C>):()
     requires c != null && c !in xs ==> c.u > 0;
     reads xs;
{()}

function ok4(c : C, xs : set<C>):()
     requires c != null && c in xs ==> c.u > 0;
     reads xs;
{()}

// reads over itself

class R { var r : R; }

function nope5(r : R):()
  reads if r != null then {r.r} else {};
{()}

function ok5(r : R):()
  reads if r != null then {r, r.r} else {};
{()}

// Reads checking where there are circularities among the expressions

class CircularChecking {
  var Repr: set<object>
    
  function F(): int
    reads this, Repr

  function F'(): int
    reads Repr, this  // this is also fine

  function G0(): int
    reads this
    requires Repr == {} && F() == 100

  function G1(): int
    reads this
    requires F() == 100  // fine, since the next line tells us that Repr is empty
    requires Repr == {}

  function H0(cell: Cell): int
    reads Repr  // error: reads is not self-framing (unless "this in Repr")
    requires this in Repr  // lo and behold!  So, reads clause is fine, if we can assume the precondition

  function H1(cell: Cell): int
    reads this, Repr
    requires cell in Repr
    requires cell != null && cell.data == 10

  function H2(cell: Cell): int
    reads this, Repr
    requires cell != null && cell.data == 10  // this is okay, too, since reads checks are postponed
    requires cell in Repr
}

class Cell { var data: int }

// Test the benefits of the new reads checking for function checking

function ApplyToSet<X>(S: set<X>, f: X -> X): set<X>
  requires forall x :: x in S ==> f.reads(x) == {} && f.requires(x)
{
  if S == {} then {} else
    var x :| x in S;
    ApplyToSet(S - {x}, f) + {f(x)}
}

function ApplyToSet_AltSignature0<X>(S: set<X>, f: X -> X): set<X>
  requires forall x :: x in S ==> f.requires(x) && f.reads(x) == {}

function ApplyToSet_AltSignature1<X>(S: set<X>, f: X -> X): set<X>
  requires forall x :: x in S ==> f.reads(x) == {}
  requires forall x :: x in S ==> f.requires(x)

function ApplyToSet_AltSignature2<X>(S: set<X>, f: X -> X): set<X>
  requires (forall x :: x in S ==> f.reads(x) == {}) ==> forall x :: x in S ==> f.requires(x)
  // (this precondition would not be good enough to check the body above)

function FunctionInQuantifier0(): int
  requires exists f: int -> int :: f(10) == 100  // error (x2): precondition violation and insufficient reads

function FunctionInQuantifier1(): int
  requires exists f: int -> int :: f.requires(10) && f(10) == 100  // error: insufficient reads

function FunctionInQuantifier2(): int
  requires exists f: int -> int :: f.reads(10) == {} && f.requires(10) && f(10) == 100
  ensures FunctionInQuantifier2() == 100
{
  var f: int -> int :| f.reads(10) == {} && f.requires(10) && f(10) == 100;  // fine :) :)
  f(10)
}