Skip to content

Commit 08c001b

Browse files
authored
Merge pull request #814 from viperproject/meilers_asserting
New "asserting" expression
2 parents 5611fcb + 5f5c022 commit 08c001b

14 files changed

Lines changed: 242 additions & 3 deletions

File tree

src/main/scala/viper/silver/ast/Expression.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,11 @@ case class Applying(wand: MagicWand, body: Exp)(val pos: Position = NoPosition,
499499
lazy val typ = body.typ
500500
}
501501

502+
case class Asserting(a: Exp, body: Exp)(val pos: Position = NoPosition, val info: Info = NoInfo, val errT: ErrorTrafo = NoTrafos) extends Exp {
503+
override lazy val check: Seq[ConsistencyError] = Consistency.checkPure(body)
504+
lazy val typ = body.typ
505+
}
506+
502507
// --- Old expressions
503508

504509
sealed trait OldExp extends UnExp {

src/main/scala/viper/silver/ast/pretty/PrettyPrinter.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,8 @@ object FastPrettyPrinter extends FastPrettyPrinterBase with BracketPrettyPrinter
771771
group(parens(text("unfolding") <+> nest(defaultIndent, show(acc)) <+> "in" <> nest(defaultIndent, line <> show(exp))))
772772
case Applying(wand, exp) =>
773773
parens(text("applying") <+> nest(defaultIndent, show(wand)) <+> "in" <> nest(defaultIndent, line <> show(exp)))
774+
case Asserting(ass, exp) =>
775+
parens(text("asserting") <+> nest(defaultIndent, parens(show(ass))) <+> "in" <> nest(defaultIndent, line <> show(exp)))
774776
case Old(exp) =>
775777
text("old") <> parens(show(exp))
776778
case LabelledOld(exp,label) =>

src/main/scala/viper/silver/ast/utility/Expressions.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ object Expressions {
2525
case CondExp(cnd, thn, els) => isPure(cnd) && isPure(thn) && isPure(els)
2626
case unf: Unfolding => isPure(unf.body)
2727
case app: Applying => isPure(app.body)
28+
case Asserting(a, e) => isPure(e)
2829
case QuantifiedExp(_, e0) => isPure(e0)
2930
case Let(_, _, body) => isPure(body)
3031
case e: ExtensionExp => e.extensionIsPure
@@ -96,9 +97,10 @@ object Expressions {
9697
def asBooleanExp(e: Exp): Exp = {
9798
e.transform({
9899
case _: AccessPredicate | _: MagicWand => TrueLit()()
99-
case fa@Forall(vs,ts,body) => Forall(vs,ts,asBooleanExp(body))(fa.pos,fa.info)
100+
case fa@Forall(vs,ts,body) => Forall(vs, ts, asBooleanExp(body))(fa.pos, fa.info, fa.errT)
100101
case Unfolding(_, exp) => asBooleanExp(exp)
101102
case Applying(_, exp) => asBooleanExp(exp)
103+
case ass@Asserting(a, exp) => Asserting(asBooleanExp(a), asBooleanExp(exp))(ass.pos, ass.info, ass.errT)
102104
})
103105
}
104106

@@ -199,6 +201,7 @@ object Expressions {
199201
case MapLookup(m, k) => List(MapContains(k, m)(p))
200202
case Unfolding(pred, _) => List(pred)
201203
case Applying(wand, _) => List(wand)
204+
case Asserting(a, _) => List(a)
202205
case _ => Nil
203206
}
204207
// Only use non-trivial conditions for the subnodes.

src/main/scala/viper/silver/ast/utility/Nodes.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ object Nodes {
8383
case PredicateAccessPredicate(pred_acc, perm) => Seq(pred_acc, perm)
8484
case Unfolding(acc, body) => Seq(acc, body)
8585
case Applying(wand, body) => Seq(wand, body)
86+
case Asserting(ass, body) => Seq(ass, body)
8687
case Old(exp) => Seq(exp)
8788
case CondExp(cond, thn, els) => Seq(cond, thn, els)
8889
case Let(v, exp, body) => Seq(v, exp, body)

src/main/scala/viper/silver/parser/FastParser.scala

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ object FastParserCompanion {
152152
// maps
153153
PKw.Map, PKwOp.Range, PKwOp.Domain,
154154
// prover hint expressions
155-
PKwOp.Unfolding, PKwOp.In, PKwOp.Applying,
155+
PKwOp.Unfolding, PKwOp.In, PKwOp.Applying, PKwOp.Asserting,
156156
// old expression
157157
PKwOp.Old, PKw.Lhs,
158158
// other expressions
@@ -365,7 +365,7 @@ class FastParser {
365365
def atomReservedKw[$: P]: P[PExp] = {
366366
reservedKwMany(
367367
StringIn("true", "false", "null", "old", "result", "acc", "none", "wildcard", "write", "epsilon", "perm", "let", "forall", "exists", "forperm",
368-
"unfolding", "applying", "Set", "Seq", "Multiset", "Map", "range", "domain", "new"),
368+
"unfolding", "applying", "asserting", "Set", "Seq", "Multiset", "Map", "range", "domain", "new"),
369369
str => pos => str match {
370370
case "true" => Pass.map(_ => PBoolLit(PReserved(PKw.True)(pos))(_))
371371
case "false" => Pass.map(_ => PBoolLit(PReserved(PKw.False)(pos))(_))
@@ -384,6 +384,7 @@ class FastParser {
384384
case "forperm" => forperm.map(_(PReserved(PKw.Forperm)(pos)))
385385
case "unfolding" => unfolding.map(_(PReserved(PKwOp.Unfolding)(pos)))
386386
case "applying" => applying.map(_(PReserved(PKwOp.Applying)(pos)))
387+
case "asserting" => asserting.map(_(PReserved(PKwOp.Asserting)(pos)))
387388
case "Set" => setConstructor.map(_(PReserved(PKwOp.Set)(pos)))
388389
case "Seq" => seqConstructor.map(_(PReserved(PKwOp.Seq)(pos)))
389390
case "Multiset" => multisetConstructor.map(_(PReserved(PKwOp.Multiset)(pos)))
@@ -652,6 +653,10 @@ class FastParser {
652653
PApplying(_, wand.inner, op, b)
653654
}
654655

656+
def asserting[$: P]: P[PKwOp.Asserting => Pos => PExp] = P(exp.parens ~ PKwOp.In ~ exp).map {
657+
case (a, in, b) => PAsserting(_, a.inner, in, b)
658+
}
659+
655660
def predicateAccessAssertion[$: P]: P[PAccAssertion] = P(accessPred | predAcc)
656661

657662
def setConstructor[$: P]: P[PKwOp.Set => Pos => PExp] =

src/main/scala/viper/silver/parser/ParseAst.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,6 +1080,12 @@ case class PApplying(applying: PKwOp.Applying, wand: PExp, in: PKwOp.In, exp: PE
10801080
List(Map(POpApp.pArgS(0) -> Wand, POpApp.pResS -> POpApp.pArg(1)))
10811081
}
10821082

1083+
case class PAsserting(asserting: PKwOp.Asserting, a: PExp, in: PKwOp.In, exp: PExp)(val pos: (Position, Position)) extends PHeapOpApp {
1084+
override val args = Seq(a, exp)
1085+
override val signatures: List[PTypeSubstitution] =
1086+
List(Map(POpApp.pArgS(0) -> Impure, POpApp.pResS -> POpApp.pArg(1)))
1087+
}
1088+
10831089
sealed trait PBinder extends PExp with PScope {
10841090
def boundVars: Seq[PLogicalVarDecl]
10851091

src/main/scala/viper/silver/parser/ParseAstKeyword.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,8 @@ object PKwOp {
494494
type Unfolding = PReserved[Unfolding.type]
495495
case object Applying extends PKwOp("applying") with PKeywordAtom with RightSpace
496496
type Applying = PReserved[Applying.type]
497+
case object Asserting extends PKwOp("asserting") with PKeywordAtom with RightSpace
498+
type Asserting = PReserved[Asserting.type]
497499
case object Let extends PKwOp("let") with PKeywordAtom with RightSpace
498500
type Let = PReserved[Let.type]
499501

src/main/scala/viper/silver/parser/Translator.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,8 @@ case class Translator(program: PProgram) {
513513
Unfolding(exp(loc).asInstanceOf[PredicateAccessPredicate], exp(e))(pos, info)
514514
case PApplying(_, wand, _, e) =>
515515
Applying(exp(wand).asInstanceOf[MagicWand], exp(e))(pos, info)
516+
case PAsserting(_, a, _, e) =>
517+
Asserting(exp(a), exp(e))(pos, info)
516518
case pl@PLet(_, _, _, exp1, _, PLetNestedScope(body)) =>
517519
Let(liftLogicalDecl(pl.decl), exp(exp1.inner), exp(body))(pos, info)
518520
case _: PLetNestedScope =>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Any copyright is dedicated to the Public Domain.
2+
// http://creativecommons.org/publicdomain/zero/1.0/
3+
4+
field f: Int
5+
6+
function fplusone(x: Ref, y: Ref): Int
7+
requires acc(x.f)
8+
{
9+
asserting (x != null) in (x.f + 1)
10+
}
11+
12+
//:: ExpectedOutput(function.not.wellformed:assertion.false)
13+
function fplusone2(x: Ref, y: Ref): Int
14+
requires acc(x.f)
15+
{
16+
asserting (x != y) in (x.f + 1)
17+
}
18+
19+
method main()
20+
{
21+
var x: Ref
22+
x := new(f)
23+
24+
var hmm: Int
25+
hmm := fplusone(x, x)
26+
hmm := asserting (hmm == x.f + 1) in hmm
27+
}
28+
29+
method main2()
30+
{
31+
var x: Ref
32+
x := new(f)
33+
34+
var hmm: Int
35+
hmm := fplusone(x, x)
36+
//:: ExpectedOutput(assignment.failed:assertion.false)
37+
hmm := asserting (hmm == x.f) in hmm
38+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Any copyright is dedicated to the Public Domain.
2+
// http://creativecommons.org/publicdomain/zero/1.0/
3+
4+
field x: Int
5+
6+
method test1() {
7+
//:: ExpectedOutput(assert.failed:division.by.zero)
8+
assert asserting (1 / 0 == 0) in true
9+
}
10+
11+
method test2() {
12+
//:: ExpectedOutput(assert.failed:division.by.zero)
13+
assert asserting (true) in (1 / 0 == 0)
14+
}
15+
16+
method test3(r: Ref) {
17+
//:: ExpectedOutput(assert.failed:insufficient.permission)
18+
assert asserting (true && acc(r.x)) in true
19+
}

0 commit comments

Comments
 (0)