summaryrefslogtreecommitdiff
path: root/Test/triggers
diff options
context:
space:
mode:
authorGravatar Clément Pit--Claudel <clement.pitclaudel@live.com>2015-08-21 19:13:56 -0700
committerGravatar Clément Pit--Claudel <clement.pitclaudel@live.com>2015-08-21 19:13:56 -0700
commitff05bb6936d433e7be5ded41233214c0517dc2d2 (patch)
treecb7538388c1d3996d0fd4ac3fdc6b06b0633af91 /Test/triggers
parenta7d63787addef715ba8b77d3adf9455c8c174c48 (diff)
Make `old` a special case for trigger generation.
Old is particular, because in old(g(f(x))), the triggers are old(g(x)) and old(f(x)). This has a number of implications; see the new tests files for more information.
Diffstat (limited to 'Test/triggers')
-rw-r--r--Test/triggers/looping-is-hard-to-decide-modulo-equality.dfy32
-rw-r--r--Test/triggers/looping-is-hard-to-decide-modulo-equality.dfy.expect10
-rw-r--r--Test/triggers/old-is-a-special-case-for-triggers.dfy32
-rw-r--r--Test/triggers/old-is-a-special-case-for-triggers.dfy.expect22
4 files changed, 96 insertions, 0 deletions
diff --git a/Test/triggers/looping-is-hard-to-decide-modulo-equality.dfy b/Test/triggers/looping-is-hard-to-decide-modulo-equality.dfy
new file mode 100644
index 00000000..c54089f2
--- /dev/null
+++ b/Test/triggers/looping-is-hard-to-decide-modulo-equality.dfy
@@ -0,0 +1,32 @@
+// RUN: %dafny /compile:0 /print:"%t.print" /dprint:"%t.dprint" /autoTriggers:1 /printTooltips "%s" > "%t"
+// RUN: %diff "%s.expect" "%t"
+
+// This file shows cases where loops could hide behind equalities. In all three
+// cases we behave the same; that is, we don't warn for loops that would only
+// exist in the presence of an equality. The easiest way to understand the
+// issue, I (CPC) feel, is to look at the old case: f(x) could very well loop
+// with old(f(f(x))) if f(f(x)) did not change the heap at all.
+
+// This equality issue is generally undecidable. It could make sense to special
+// case `old`, but KRML and CPC decided against it on 2015-08-21. Future
+// experiences could cause a change of mind.
+
+class C { }
+function f(c: C): C
+function g(c: C): C
+function h(c: C, i: int): C
+
+// With explicit arguments
+method M0(i: int, j: int, sc: set<C>) {
+ assert forall c | c in sc :: true || h(c, i) == h(h(c, j), j);
+}
+
+// With implicit arguments (f and g respectively, to Apply)
+method M1(f: int -> int, g: int -> int) {
+ assert forall x :: true || f(x) == g(f(x));
+}
+
+// With implicit arguments (the heap, to old)
+method M2(sc: set<C>) {
+ assert forall c | c in sc :: true || f(c) == old(f(f(c)));
+}
diff --git a/Test/triggers/looping-is-hard-to-decide-modulo-equality.dfy.expect b/Test/triggers/looping-is-hard-to-decide-modulo-equality.dfy.expect
new file mode 100644
index 00000000..c0eebdba
--- /dev/null
+++ b/Test/triggers/looping-is-hard-to-decide-modulo-equality.dfy.expect
@@ -0,0 +1,10 @@
+looping-is-hard-to-decide-modulo-equality.dfy(21,9): Info: Selected triggers:
+ {h(h(c, j), j)}, {h(c, i)}, {c in sc}
+ Rejected triggers: {h(c, j)} (loops with {h(h(c, j), j)})
+looping-is-hard-to-decide-modulo-equality.dfy(26,9): Info: Selected triggers: {f(x)}
+ Rejected triggers: {g(f(x))} (more specific than {f(x)})
+looping-is-hard-to-decide-modulo-equality.dfy(31,9): Info: Selected triggers:
+ {old(f(f(c)))}, {f(c)}, {c in sc}
+ Rejected triggers: {old(f(c))} (loops with {old(f(f(c)))})
+
+Dafny program verifier finished with 9 verified, 0 errors
diff --git a/Test/triggers/old-is-a-special-case-for-triggers.dfy b/Test/triggers/old-is-a-special-case-for-triggers.dfy
new file mode 100644
index 00000000..4424e8d3
--- /dev/null
+++ b/Test/triggers/old-is-a-special-case-for-triggers.dfy
@@ -0,0 +1,32 @@
+// RUN: %dafny /compile:0 /print:"%t.print" /dprint:"%t.dprint" /autoTriggers:1 /printTooltips "%s" > "%t"
+// RUN: %diff "%s.expect" "%t"
+
+// This file ensures that `old()` receives the special treatment that it
+// requires; that is, `old(f(x))` is not less liberal than `f(x)`, and
+// old(f(f(x))) does not loop with f(x) (doesn't it?)
+
+class C { }
+function f(c: C): C
+function g(c: C): C
+function h(c: C, i: int): C
+
+method M(sc: set<C>)
+ // Ensure that old(c) does not get picked as a trigger
+ ensures forall c | c in sc :: true || c == old(f(c))
+
+ // This checks whether loop detection handles `old` expressions properly.
+ // In the first one f(c)/old(f(f(c))) is not reported as a loop. See
+ // looping-is-hard-to-decide-modulo-equalities.dfy for an explanation.
+ ensures forall c | c in sc :: true || f(c) == old(f(f(c)))
+ ensures forall c | c in sc :: true || old(f(f(c))) == old(g(f(c))) || old(f(g(c))) == g(f(c)) || f(g(c)) == g(f(c))
+
+ // These check that the final trigger filtering step doesn't get confused
+ // between old expressions and regular expressions.
+ ensures forall c | c in sc :: true || f(c) == old(g(f(c)))
+ ensures forall c | c in sc :: true || f(c) == old(f(c)) || old(g(f(c))) == g(f(c))
+
+ // WISH: A Dafny rewriter could cleanup expressions so that adding the
+ // expression forall c :: c == old(c) in a quantifier would cause a warning,
+ // instead of a trigger generation error as it does now.
+{
+}
diff --git a/Test/triggers/old-is-a-special-case-for-triggers.dfy.expect b/Test/triggers/old-is-a-special-case-for-triggers.dfy.expect
new file mode 100644
index 00000000..23ec089d
--- /dev/null
+++ b/Test/triggers/old-is-a-special-case-for-triggers.dfy.expect
@@ -0,0 +1,22 @@
+old-is-a-special-case-for-triggers.dfy(15,10): Info: Selected triggers:
+ {old(f(c))}, {c in sc}
+old-is-a-special-case-for-triggers.dfy(20,10): Info: Selected triggers:
+ {old(f(f(c)))}, {f(c)}, {c in sc}
+ Rejected triggers: {old(f(c))} (loops with {old(f(f(c)))})
+old-is-a-special-case-for-triggers.dfy(21,10): Info: Selected triggers:
+ {f(g(c))}, {g(f(c))}, {old(f(g(c)))}, {old(g(f(c)))}, {old(f(f(c)))}, {c in sc}
+ Rejected triggers:
+ {g(c)} (loops with {g(f(c))})
+ {f(c)} (loops with {f(g(c))})
+ {old(g(c))} (loops with {old(g(f(c)))})
+ {old(f(c))} (loops with {old(f(f(c)))}, {old(f(g(c)))})
+old-is-a-special-case-for-triggers.dfy(25,10): Info: Selected triggers:
+ {old(f(c))}, {f(c)}, {c in sc}
+ Rejected triggers: {old(g(f(c)))} (more specific than {old(f(c))})
+old-is-a-special-case-for-triggers.dfy(26,10): Info: Selected triggers:
+ {old(f(c))}, {f(c)}, {c in sc}
+ Rejected triggers:
+ {g(f(c))} (more specific than {f(c)})
+ {old(g(f(c)))} (more specific than {old(f(c))})
+
+Dafny program verifier finished with 5 verified, 0 errors