domain Option__Node { unique function Option__Node__Some(): Option__Node unique function Option__Node__None(): Option__Node function variantOfOptionNode(self: Ref): Option__Node function isOptionNode(self: Ref): Bool axiom ax_variantOfOptionNodeChoices { forall x: Ref :: { variantOfOptionNode(x) } (variantOfOptionNode(x) == Option__Node__Some() || variantOfOptionNode(x) == Option__Node__None()) } axiom ax_isCounterState { forall x: Ref :: { variantOfOptionNode(x) } isOptionNode(x) == (variantOfOptionNode(x) == Option__Node__Some() || variantOfOptionNode(x) == Option__Node__None()) } } predicate validOption(this: Ref) { isOptionNode(this) && variantOfOptionNode(this) == Option__Node__Some() ==> ( acc(this.Option__Node__Some__1, write) && acc(validNode(this.Option__Node__Some__1)) ) } field Option__Node__Some__1: Ref field Node__v: Int field Node__next: Ref predicate validNode(this: Ref) { acc(this.Node__v) && acc(this.Node__next) && acc(validOption(this.Node__next)) } function length(this: Ref): Int requires acc(validNode(this), write) ensures result >= 1 { (unfolding acc(validNode(this), write) in unfolding acc(validOption(this.Node__next)) in (variantOfOptionNode(this.Node__next) == Option__Node__None()) ? 1 : 1 + length(this.Node__next.Option__Node__Some__1) ) } function itemAt(this: Ref, i: Int): Int requires acc(validNode(this), write) requires 0 <= i && i < length(this) { unfolding acc(validNode(this), write) in unfolding acc(validOption(this.Node__next)) in ( (i == 0) ? this.Node__v: (variantOfOptionNode(this.Node__next) == Option__Node__Some()) ? itemAt(this.Node__next.Option__Node__Some__1, i-1) : this.Node__v ) } function sum(this$1: Ref): Int requires acc(validNode(this$1), write) { (unfolding acc(validNode(this$1), write) in unfolding acc(validOption(this$1.Node__next)) in (variantOfOptionNode(this$1.Node__next) == Option__Node__None()) ? this$1.Node__v : this$1.Node__v + sum(this$1.Node__next.Option__Node__Some__1)) } method append(this: Ref, val: Int) requires acc(validNode(this), write) ensures acc(validNode(this), write) /* POST1 */ ensures length(this) == (old(length(this)) + 1) /* POST2 */ ensures (forall i: Int :: (0 <= i && i < old(length(this))) ==> (itemAt(this, i) == old(itemAt(this, i)))) /* POST3 */ ensures itemAt(this, length(this) - 1) == val /* POST4 */ ensures true ==> true { var tmp_node: Ref var tmp_option: Ref unfold acc(validNode(this), write) unfold acc(validOption(this.Node__next), write) if (variantOfOptionNode(this.Node__next) == Option__Node__None()) { tmp_node := new(Node__next, Node__v) tmp_node.Node__next := null tmp_node.Node__v := val assume variantOfOptionNode(tmp_node.Node__next) == Option__Node__None() fold acc(validOption(tmp_node.Node__next)) fold acc(validNode(tmp_node), write) tmp_option := new(Option__Node__Some__1) tmp_option.Option__Node__Some__1 := tmp_node assume variantOfOptionNode(tmp_option) == Option__Node__Some() fold acc(validOption(tmp_option)) this.Node__next := tmp_option unfold validOption(tmp_option) assert length(tmp_node) == 1 /* TODO: Required by Silicon, POST2 fails otherwise */ assert itemAt(tmp_node, 0) == val /* TODO: Required by Silicon, POST4 fails otherwise */ fold validOption(tmp_option) } else { append(this.Node__next.Option__Node__Some__1, val) fold acc(validOption(this.Node__next), write) } fold acc(validNode(this), write) } method prepend(tail: Ref, val: Int) returns (res: Ref) requires acc(validNode(tail)) ensures acc(validNode(res)) //ensures acc(validNode(tail)) ensures length(res) == old(length(tail)) + 1 ensures (forall i: Int :: (1 <= i && i < length(res)) ==> (itemAt(res, i) == old(itemAt(tail, i-1)))) /* POST3 */ ensures itemAt(res, 0) == val { var tmp_option: Ref res := new(Node__v, Node__next) res.Node__v := val tmp_option := new(Option__Node__Some__1) tmp_option.Option__Node__Some__1 := tail assume variantOfOptionNode(tmp_option) == Option__Node__Some() res.Node__next := tmp_option assert acc(validNode(tail)) fold acc(validOption(res.Node__next)) fold acc(validNode(res)) } method length_iter(list: Ref) returns (len: Int) requires acc(validNode(list), write) ensures old(length(list)) == len // TODO we have to preserve this property // ensures acc(validNode(list)) { var curr: Ref := list var tmp: Ref := list len := 1 unfold acc(validNode(curr)) unfold acc(validOption(curr.Node__next)) while(variantOfOptionNode(curr.Node__next) == Option__Node__Some()) invariant acc(curr.Node__v) invariant acc(curr.Node__next) invariant (variantOfOptionNode(curr.Node__next) == Option__Node__Some() ==> ( acc(curr.Node__next.Option__Node__Some__1, write) && acc(validNode(curr.Node__next.Option__Node__Some__1)) )) invariant (variantOfOptionNode(curr.Node__next) == Option__Node__Some() ==> len + length(curr.Node__next.Option__Node__Some__1) == old(length(list))) invariant (variantOfOptionNode(curr.Node__next) == Option__Node__None() ==> len == old(length(list))) { assert acc(validNode(curr.Node__next.Option__Node__Some__1)) len := len + 1 tmp := curr curr := curr.Node__next.Option__Node__Some__1 unfold acc(validNode(curr)) unfold acc(validOption(curr.Node__next)) } } method t1() { var l: Ref l := new(Node__v, Node__next) l.Node__next := null l.Node__v := 1 assume variantOfOptionNode(l.Node__next) == Option__Node__None() fold validOption(l.Node__next) fold validNode(l) assert length(l) == 1 assert itemAt(l, 0) == 1 append(l, 7) assert itemAt(l, 1) == 7 assert itemAt(l, 0) == 1 assert length(l) == 2 l := prepend(l, 10) assert itemAt(l, 2) == 7 assert itemAt(l, 1) == 1 assert itemAt(l, 0) == 10 assert length(l) == 3 //assert sum(l) == 18 } method t2(l: Ref) returns (res: Ref) requires acc(validNode(l), write) ensures acc(validNode(res), write) ensures length(res) > old(length(l)) { res := prepend(l, 10) }