// RUN: %dafny /compile:0 /print:"%t.print" /dprint:"%t.dprint" "%s" > "%t" // RUN: %diff "%s.expect" "%t" module A { datatype Explicit = Nil | Cons(set, Explicit) datatype Inferred = Nil | Cons(set, Inferred) class C { method M(x: Explicit) method N(x: Inferred) } } module B refines A { class C { method M(x: Explicit) method N(x: Inferred) } } // ---------------------------- module C { type X(==) type Y(==) } module D refines C { class X { } datatype Y = Red | Green | Blue } module E refines C { codatatype X = Next(int, X) // error: X requires equality and codatatypes don't got it datatype Y = Nil | Something(Z) | More(Y, Y) // error: Y does not support equality codatatype Z = Red | Green(X) | Blue } module F refines C { datatype X = Nil | Cons(T, X) // error: not allowed to add a type parameter to type X class Y { } // error: not allowed to add a type parameter to type Y } module G refines C { datatype X = Nil | Next(Z, X) // error: X does not support equality datatype Y = Nil | Something(Z) | More(Y, Y) // error: Y does not support equality codatatype Z = Red | Green | Blue } // ---------------------------- module H { datatype Dt = Nil | Cons(T, Dt) datatype BulkyList = Nothing | Wrapper(T, BulkyListAux) datatype BulkyListAux = Kons(set, BulkyListAuxAux) datatype BulkyListAuxAux = GoBack(BulkyList) codatatype Stream = Next(head: T, tail: Stream) method M(x: T) { } function method F(x: BulkyList, y: BulkyList): int { if x == y then 5 else 7 } // this equality is allowed function method G(x: Dt, y: Dt): int { if x == y then 5 else 7 } // error: the equality is not allowed, because Dt may not support equality function method G'(x: Dt, y: Dt): int { if x == y then 5 else 7 } // fine method Caller0(b: BulkyList, y: int) { match (b) { case Nothing => case Wrapper(t, bla) => var u; if (y < 100) { u := t; } // The following call is allowed, because it will be inferred that // 'u' is of a type that supports equality M(u); } } method Caller1(d: Dt) { match (d) { case Nil => case Cons(t, rest) => M(t); // error: t may be of a type that does not support equality } } method Caller2(co: Stream) { var d := Cons(co, Nil); Caller1(d); // case in point for the error in Caller1 } } // ---------------------------- module Gh { datatype D = Nil | Cons(head: int, tail: D, ghost x: int) method M(n: nat, b: bool, d: D, e: D, ghost g: bool) ensures b ==> d == e; // fine, this is a ghost declaration { ghost var g := 0; var h := 0; if d == e { // fine, this is a ghost statement g := g + 1; } else { assert !b; } if d == e { // error: not allowed to compare D's in a non-ghost context h := h + 1; } if n != 0 { M(n-1, b, d, e, d==e); // fine M(n-1, d==e, d, e, false); // error, cannot pass in d==e like we do } GM(d==e, d, e); // fine -- we're calling a ghost method var y0 := F(b, d==e); var y1 := F(d==e, false); // error } function method F(b: bool, ghost g: bool): int { 6 } ghost method GM(b: bool, d: D, e: D) // all equalities are fine in a ghost method ensures b ==> d == e; { ghost var g := 0; var h := 0; if d == e { g := g + 1; } else { assert !b; } if d == e { h := h + 1; } } } // ------ deeper nesting ------ module Deep { codatatype Co = Mo(Co) | NoMo class C { } method M(a: set>) { var s: set>; var t: set; // error: set element type must support equality var co: Co; var d := G(co, NoMo); // error: actual type parameter for Y (namely, Co) does // not support equality d := G(t, t) + G(s, s); // fine, because all sets support equality } function method G(y: Y, z: Y): int { if y == z then 5 else 7 } method P(b: set) { // error: set element type must be a type with equality } ghost method Q(b: set) { // fine, since this is a ghost method } method R(ghost b: set) { // fine, since this is a ghost parameter } datatype Dt = Bucket(T) datatype Left = Bucket(T) datatype Right = Bucket(set) // note, Dafny infers that U should be U(==) datatype RightExplicit = Bucket(set) type Syn = Left method W() { var a: set>; // error: Dt does not support equality var b: set>; var c: set>; var d: set>; // error: Left does not support equality var e: set>; // error: type parameter 1 to Right is required to support equality ghost var e': set>; // fine, since this is a ghost field var e'': set>; // error: cannot instantiate argument 1 with Co var f: set>; var g: set>; // error: Syn does not support equality ghost var h: set>; // in a ghost context, it's cool, though var i; // error: inferred type (set) uses invalid set-element type var j: set; // error: ditto ghost var k: set; // type allowed here, because it's a ghost assert i == k || j == k || true; // this infers the types of 'i' and 'j' } method StatementsWithVariables(a: set>) { var s: set>; var t: set; // error: bad type ghost var u: set; var c := new ABC; forall x | x in {t} { // error: bad type for x c.f := 0; } if t == u { forall x | x in {t} // fine, because this is a ghost statement ensures true; { } } } class ABC { var f: int; } method Expressions() { var t: set; // error: bad type var b := forall x | x in {t} :: x == x; // error: bad type var y := var k: set := t; k <= t; // error: bad type } ghost method GhostThings0(t: set) { assert forall x | x in {t} :: x == x; var y := var k: set := t; k <= t; assert y; } method GhostThings1(ghost t: set) { assert forall x | x in {t} :: x == x; ghost var y := var k: set := t; k <= t; assert y; } method InferEqualitySupportIsRequired(s: set) ghost method DontInferEqualitySupportIsRequired(s: set) method Explicit(s: set) method TakesABoolean(b: bool) method AClient(co: Co, ko: Co) { Explicit({5}); Explicit({co}); // error: bad type var b := ko in {co}; // error: bad type (argument for the set) ghost var bg := ko in {co}; // fine, it's a ghost InferEqualitySupportIsRequired({co}); // error: bad type DontInferEqualitySupportIsRequired({co}); TakesABoolean(ko in {co}); // error: bad type var x := multiset([co,ko,co,ko])[ko]; // error: bad type var m0 := map[5 := ko]; // no prob var m1 := map[ko := 5]; // error: bad type } }