// RUN: %dafny /compile:0 /print:"%t.print" /dprint:"%t.dprint" "%s" > "%t" // RUN: %diff "%s.expect" "%t" class MyClass { var x: int; var y: int; ghost var g: int; method M(S: set, mc: MyClass) requires this == mc; modifies this, S; { if mc == this { modify mc, this; } modify {this}, this, {this}, S; modify this; modify {:myAttribute} {:another true} {this}, this, S; modify {} ; } method N() modifies this; { x := 18; modify this; assert x == 18; // error: cannot conclude this here } method P(other: MyClass) modifies this; { x := 18; var previous := if other == null then 0 else other.x; modify this; assert other != null && other != this ==> other.x == previous; } method FieldSpecific0() modifies `x; { modify this; // error: this is a larger frame than what FieldSpecific0 is allowed to modify } method FieldSpecific1() modifies `x, `y; { modify this; // error: this is a larger frame than what FieldSpecific0 is allowed to modify } method FieldSpecific2() modifies this; { modify `x; } method FieldSpecific3() modifies `x; { modify this`x; modify `y; // error: this is a larger frame than what FieldSpecific3 is allowed to modify } method FieldSpecific4() modifies `x; { var xx, yy := x, y; modify this`x; assert y == yy; // fine assert x == xx; // error: x just changed } method GhostFrame4() modifies this; { var xx := x; ghost var gg := g; if g < 100 { // we're now in a ghost context var n := 0; while n < y modifies this; { g := g + 1; n := n + 1; } } assert x == xx; // fine, since only ghost state is allowed to be modified inside the ghost if assert g == gg; // error } ghost method Ghost0() modifies this; { var xx := x; var gg := g; modify this; // since we're in the context of a ghost method, this will only modify ghost fields assert x == xx; // fine assert g == gg; // error } ghost method Ghost1() modifies this; { var xx := x; var gg := g; modify `g; // since we're in the context of a ghost method, this will only modify // ghost fields, despite the specific mention of non-ghost fields assert x == xx; // fine assert g == gg; // error } method Ghost2() modifies this; { var xx := x; ghost var gg := g; if g < 100 { // the if guard mentions a ghost field, so we're now in a ghost context modify this; assert x == xx; // fine, since the 'modify' statement only modified ghost fields assert g == gg; // error: the 'modify' statement can affect the ghost field 'g' } } } class ModifyBody { var x: int; var y: int; method M0() modifies this; { modify {} { x := 3; // error: violates modifies clause of the modify statement } } method M1() modifies this; { modify {} { var o := new ModifyBody; o.x := 3; // fine } } method M2() modifies this; { modify this { x := 3; } } method M3(o: ModifyBody, p: ModifyBody) modifies this, o, p; { modify {this, o, p} { modify this, o; modify o, this { modify o { modify o; modify {} { modify {}; } } } } } method P0() modifies this; { var xx := x; modify this; assert xx == x; // error } method P1() modifies this; { var xx := x; modify this { y := 3; } assert xx == x; // fine, because the modify body trumps the modify frame } }