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
|
// RUN: %dafny /compile:0 /print:"%t.print" /dprint:"%t.dprint" /autoTriggers:1 /printTooltips "%s" > "%t"
// RUN: %diff "%s.expect" "%t"
// This test shows that the loop detection engine makes compromises when looking
// for subexpressions matching a trigger; in particular, it allows a
// subexpression to match a trigger without reporting a loop and without being
// equal to that trigger, as long as the only differences are variable
predicate P(x: int, y: int)
predicate Q(x: int)
method Test(z: int) {
// P(x, y) and P(y, x) might look like they would cause a loop. Since they
// only differ by their variables, though, they won't raise flags.
assume forall x: int, y: int :: P(x, y) == P(y, x);
// This works independent of extra parentheses:
assume forall x: int, y: int :: P(x, y) == (P(y, x));
// Contrast with the following:
assume forall x: int, y: int :: P(x, y) == P(x, y+1);
// The following examples were made legal after an exchange where Chris
// pointed examples in the IronClad sources where things like this were
// incorrectly flagged.
assert forall x :: true || Q(x) || Q(0);
assert forall x :: true || Q(x) || Q(z);
assert forall x :: true || P(x, 1) || P(x, z);
// Support for the following was added following a discussion with Rustan; in
// the second one the expression `if z > 1 then z else 3 * z + 1` is not
// directly a constant expression, but it does not involve x, so it's ok:
assert forall x :: true || Q(x) || Q(0+1);
assert forall x :: true || Q(x) || Q(if z > 1 then z else 3 * z + 1);
// Sanity check:
assert forall x :: true || Q(x) || Q(if z > 1 then x else 3 * z + 1);
// WISH: It might also be good to zeta-reduce before loop detection.
assert forall x :: true || Q(x) || (var xx := x+1; Q(xx));
}
|