summaryrefslogtreecommitdiff
path: root/Test/dafny0/NonGhostQuantifiers.dfy
blob: dd730e9009c7815db6d8e9671aa5f9806cf18139 (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
// This file contains various tests of resolving quantifiers in ghost and non-ghost positions

class MyClass<T> {
  // This function is in a ghost context, so all is cool.
  function GhostF(): bool
  {
    (forall n :: 2 <= n ==> (exists d :: n < d && d < 2*n))
  }
  // But try to make it a non-ghost function, and Dafny will object because it cannot compile the
  // body into code that will terminate.
  function method NonGhostF(): bool
  {
    (forall n :: 2 <= n ==> (exists d :: n < d && d < 2*n))  // error: can't figure out how to compile
  }
  // Add an upper bound to n and things are cool again.
  function method NonGhostF_Bounded(): bool
  {
    (forall n :: 2 <= n && n < 1000 ==> (exists d :: n < d && d < 2*n))
  }
  // Although the heuristics applied are syntactic, they do see through the structure of the boolean
  // operators ==>, &&, ||, and !.  Hence, the following three variations of the previous function can
  // also be compiled.
  function method NonGhostF_Or(): bool
  {
    (forall n :: !(2 <= n && n < 1000) || (exists d :: n < d && d < 2*n))
  }
  function method NonGhostF_ImpliesImplies(): bool
  {
    (forall n :: 2 <= n ==> n < 1000 ==> (exists d :: n < d && d < 2*n))
  }
  function method NonGhostF_Shunting(): bool
  {
    (forall n :: 2 <= n ==> 1000 <= n || (exists d :: n < d && d < 2*n))
  }

  // Here are more tests

  function method F(a: array<T>): bool
    requires a != null;
    reads a;
  {
    (exists i :: 0 <= i && i < a.Length / 2 && (forall j :: i <= j && j < a.Length ==> a[i] == a[j]))
  }

  function method G0(a: seq<T>): bool
  {
    (exists t :: t in a && (forall u :: u in a ==> u == t))
  }
  function method G1(a: seq<T>): bool
  {
    (exists ti :: 0 <= ti && ti < |a| && (forall ui :: 0 <= ui && ui < |a| ==> a[ui] == a[ti]))
  }

  // Regrettably, the heuristics don't know about transitivity:
  function method IsSorted0(s: seq<int>): bool
  {
    (forall i, j :: 0 <= i && i < j && j < |s| ==> s[i] <= s[j])  // error: can't figure out how to compile
  }
  function method IsSorted1(s: seq<int>): bool
  {
    (forall j, i :: 0 <= i && i < j && j < |s| ==> s[i] <= s[j])  // error: can't figure out how to compile
  }
  // Add the redundant conjunct "i < |s|" and things are fine.
  function method IsSorted2(s: seq<int>): bool
  {
    (forall i, j :: 0 <= i && i < |s| && i < j && j < |s| ==> s[i] <= s[j])
  }
  // But if you switch the order of i and j, you need a different redundant conjunct.
  function method IsSorted3(s: seq<int>): bool
  {
    (forall j, i :: 0 <= i && i < |s| && i < j && j < |s| ==> s[i] <= s[j])  // error: can't figure out how to compile
  }
  function method IsSorted4(s: seq<int>): bool
  {
    (forall j, i  :: 0 <= i && 0 < j && i < j && j < |s| ==> s[i] <= s[j])
  }

  // The heuristics look at bound variables in the order given, as is illustrated by the following
  // two functions.
  function method Order0(S: seq<set<int>>): bool
  {
    (forall i, j :: 0 <= i && i < |S| && j in S[i] ==> 0 <= j)
  }
  function method Order1(S: seq<set<int>>): bool
  {
    (forall j, i :: 0 <= i && i < |S| && j in S[i] ==> 0 <= j)  // error: can't figure out how to compile
  }

  // Quantifiers can be used in other contexts, too.
  // For example, in assert statements and assignment statements.
  method M(s: seq<int>) returns (r: bool, q: bool) {
    assert (forall x :: x in s ==> 0 <= x);
    r := (forall x :: x in s ==> x < 100);
    q := (exists y :: y*y in s);  // error: can't figure out how to compile
  }
  // And if expressions.
  function method Select_Good(S: set<int>, a: T, b: T): T
  {
    if (forall x :: x in S ==> 0 <= x && x < 100) then a else b
  }
  function method Select_Bad(S: set<int>, a: T, b: T): T
  {
    if (forall x :: x*x in S ==> 0 <= x && x < 100) then a else b  // error: can't figure out how to compile
  }
  // (the same thing, but in a ghost function is fine, though)
  function Select_Bad_Ghost(S: set<int>, a: T, b: T): T
  {
    if (forall x :: x*x in S ==> 0 <= x && x < 100) then a else b
  }
  // And if statements
/****
  method N(s: seq<int>) returns (ghost g: int, h: int)
  {
    if ( (forall x :: x in s ==> 0 <= x) ) {
      h := 0;  g := 0;
    }
    if ( (forall x :: x*x in s ==> x < 100) ) {  // this is fine, since the whole statement is a ghost statement
      g := 2;
    }
    if ( (forall x :: x*x in s ==> x < 50) ) {  // error: cannot compile this guard of a non-ghost if statement
      h := 6;
    }
  }
****/
}