// RUN: %dafny /compile:0 /print:"%t.print" /dprint:"%t.dprint" "%s" > "%t" // RUN: %diff "%s.expect" "%t" // -------------------------------------------------- module TestInductiveDatatypes { // The following types test for cycles that go via instantiated type arguments datatype Record = Ctor(T); datatype RecInt = Ctor(Record); // this is fine datatype Rec_Forever = Ctor(Record); // error datatype Rec_Stops = Cons(Record, Rec_Stops) | Nil; // this is okay datatype D = Ctor(E>); // error: illegal cycle datatype E = Ctor(T); // the following is okay datatype MD = Ctor(ME); datatype ME = Ctor(T); method M() { var d: MD>; } datatype A = Ctor(B); // superficially looks like a cycle, but can still be constructed datatype B = Ctor(List); datatype List = Nil | Cons(T, List); } module MoreInductive { datatype Tree = Node(G, List>); datatype List = Nil | Cons(T, List); datatype M = All(List); datatype H<'a> = HH('a, Tree<'a>); datatype K<'a> = KK('a, Tree>); // error datatype L<'a> = LL('a, Tree>>); } // -------------------------------------------------- module TestCoinductiveDatatypes { codatatype InfList = Done | Continue(T, InfList); codatatype Stream = More(T, Stream); codatatype BinaryTreeForever = BNode(val: T, left: BinaryTreeForever, right: BinaryTreeForever); datatype List = Nil | Cons(T, List); codatatype BestBushEver = Node(value: T, branches: List>); codatatype LazyRecord = Lazy(contents: T); class MyClass { } datatype GenericDt = Blue | Green(T); datatype GenericRecord = Rec(T); datatype FiniteEnough_Class = Ctor(MyClass); datatype FiniteEnough_Co = Ctor(LazyRecord); datatype FiniteEnough_Dt = Ctor(GenericDt); // fine datatype NotFiniteEnough_Dt = Ctor(GenericRecord); // error } // --------------- CoPredicates -------------------------- module CoPredicateResolutionErrors { codatatype Stream = StreamCons(head: T, tail: Stream); function Upward(n: int): Stream { StreamCons(n, Upward(n + 1)) } function Doubles(n: int): Stream { StreamCons(2*n, Doubles(n + 1)) } copredicate Pos(s: Stream) { 0 < s.head && Pos(s.tail) && Even(s) } copredicate Even(s: Stream) { s.head % 2 == 0 && Even(s.tail) && (s.head == 17 ==> Pos(s)) && (Pos(s) ==> s.head == 17) // error: cannot make recursive copredicate call in negative position && !Even(s) // error: cannot make recursive copredicate call in negative position && (Even(s) <==> Even(s)) // error (x2): recursive copredicate calls allowed only in positive positions } copredicate CP(i: int) { CP(i) && !CP(i) && // error: not in a positive position (forall j :: CP(j)) && (exists k :: 0 <= k < i*i && CP(k)) && (exists k :: 0 <= k && CP(k)) && // error: unbounded range (exists k :: k < i*i && CP(k)) && // error: unbounded range (exists l :: CP(l)) // error: unbounded range } copredicate CQ(i: int, j: int) { exists i :: i == 6 && if j % 2 == 0 then CQ(i, i) else CQ(j, j) } copredicate CR(i: int, j: int) { exists i :: i == if CR(i, j) then 6 else j // error: not allowed to call CR recursively here } copredicate CS(i: int, j: int) { exists i :: i <= (if CS(i, j) then 6 else j) && // error: not allowed to call CS recursively here (if CS(i, j) then 6 else j) <= i // error: not allowed to call CS recursively here } copredicate Another(s: Stream) { !Even(s) // here, negation is fine } ghost method Lemma(n: int) ensures Even(Doubles(n)); { } copredicate CoStmtExpr_Good(s: Stream) { s.head > 0 && (MyLemma(s.head); CoStmtExpr_Good(s.tail)) } lemma MyLemma(x: int) { } copredicate CoStmtExpr_Bad(s: Stream) { s.head > 0 && (MyRecursiveLemma(s.head); // error: cannot call method recursively from copredicate CoStmtExpr_Bad(s.tail)) } lemma MyRecursiveLemma(x: int) { var p := CoStmtExpr_Bad(Upward(x)); } } // -------------------------------------------------- module UnfruitfulCoLemmaConclusions { codatatype Stream = Cons(head: T, tail: Stream); copredicate Positive(s: Stream) { s.head > 0 && Positive(s.tail) } colemma BadTheorem(s: Stream) ensures false; { BadTheorem(s.tail); } colemma CM(s: Stream) ensures true && !false; ensures s.head == 8 ==> Positive(s); ensures s.tail == s; ensures s.head < 100; ensures Positive(s) ==> s.tail == s; ensures Positive(s) ==> s.head > 88; ensures !Positive(s) ==> s.tail == s; ensures !(true && !false ==> Positive(s) && !Positive(s)); ensures !(false && !true ==> Positive(s) && !Positive(s)); { } }