@@ -19,13 +19,17 @@ import viper.silver.verifier.ConsistencyError
1919trait ExpTransformer extends ProgramManager with ErrorReporter {
2020
2121 /**
22- * Transforms an expression into a statement.
22+ * Transforms an expression into a statement that checks the termination conditions for that expression.
23+ * If inhaleExp is true, the expression is inhaled during the check.
2324 *
2425 * @return a statement representing the expression.
2526 */
26- def transformExp (e : Exp , c : ExpressionContext ): Stmt = e match {
27- case And (fst, snd) =>
28- val fstStmt = transformExp(fst, c)
27+ def transformExp (e : Exp , c : ExpressionContext , inhaleExp : Boolean ): Stmt = e match {
28+ case And (fst, snd) if inhaleExp =>
29+ // Special case conjunctions s.t. we properly inhale the first expression before checking the second.
30+ // This is necessary if fst contains e.g. a quantified permission, and snd is well-defined only if that quantified
31+ // permission is available.
32+ val fstStmt = transformExp(fst, c, inhaleExp)
2933 val nonDetVarDecl = LocalVarDecl (uniqueName(" b" ), Bool )(e.pos, e.info, e.errT)
3034 val assumeFalse = Inhale (FalseLit ()())()
3135 val inhaleFst = Inhale (fst)()
@@ -39,20 +43,20 @@ trait ExpTransformer extends ProgramManager with ErrorReporter {
3943 }
4044 val fstIf = If (nonDetVarDecl.localVar, Seqn (Seq (fstStmt, assumeFalse), Nil )(), Seqn (Seq (inhaleFstStmt), Nil )())(e.pos, e.info, e.errT)
4145 val fstBlock = Seqn (Seq (fstIf), Seq (nonDetVarDecl))()
42- val sndStmt = transformExp(snd, c)
46+ val sndStmt = transformExp(snd, c, inhaleExp )
4347 Seqn (Seq (fstBlock, sndStmt), Nil )()
4448 case CondExp (cond, thn, els) =>
45- val condStmt = transformExp(cond, c)
46- val thnStmt = transformExp(thn, c)
47- val elsStmt = transformExp(els, c)
49+ val condStmt = transformExp(cond, c, false )
50+ val thnStmt = transformExp(thn, c, inhaleExp )
51+ val elsStmt = transformExp(els, c, inhaleExp )
4852
4953 val ifStmt = If (cond, Seqn (Seq (thnStmt), Nil )(), Seqn (Seq (elsStmt), Nil )())()
5054
5155 val stmts = Seq (condStmt, ifStmt)
5256 Seqn (stmts, Nil )()
5357 case Unfolding (acc, unfBody) =>
54- val permCheck = transformExp(acc.perm, c)
55- val unfoldBody = transformExp(unfBody, c)
58+ val permCheck = transformExp(acc.perm, c, false )
59+ val unfoldBody = transformExp(unfBody, c, inhaleExp )
5660 // only unfold and fold if body contains something
5761 val (unfold, fold) = (Unfold (acc)(), Fold (acc)())
5862
@@ -61,32 +65,32 @@ trait ExpTransformer extends ProgramManager with ErrorReporter {
6165 case Applying (wand, body) =>
6266 // note that this case is untested -- it's not possible to write a function with an `applying` expression
6367 val nonDetVarDecl = LocalVarDecl (uniqueName(" b" ), Bool )(e.pos, e.info, e.errT)
64- val bodyStmt = transformExp(body, c)
68+ val bodyStmt = transformExp(body, c, inhaleExp )
6569 val killBranchStmt = Inhale (FalseLit ()(e.pos, e.info, e.errT))(e.pos, e.info, e.errT)
6670 val thnStmt = Seqn (Seq (Apply (wand)(e.pos, e.info, e.errT), bodyStmt, killBranchStmt), Nil )()
6771 val ifStmt = If (nonDetVarDecl.localVar, thnStmt, EmptyStmt )(e.pos, e.info, e.errT)
6872 Seqn (Seq (ifStmt), Seq (nonDetVarDecl))(e.pos, e.info, e.errT)
6973 case inex : InhaleExhaleExp =>
70- val inhaleStmt = transformExp(inex.in, c)
71- val exhaleStmt = transformExp(inex.ex, c)
74+ val inhaleStmt = transformExp(inex.in, c, inhaleExp )
75+ val exhaleStmt = transformExp(inex.ex, c, inhaleExp )
7276
7377 c.conditionInEx match {
7478 case Some (conditionVar) => If (conditionVar.localVar, Seqn (Seq (inhaleStmt), Nil )(), Seqn (Seq (exhaleStmt), Nil )())()
7579 case None => Seqn (Seq (inhaleStmt, exhaleStmt), Nil )()
7680 }
7781 case letExp : Let =>
78- val expressionStmt = transformExp(letExp.exp, c)
82+ val expressionStmt = transformExp(letExp.exp, c, false )
7983 val localVarDecl = letExp.variable
8084
8185 val inhaleEq = Inhale (EqCmp (localVarDecl.localVar, letExp.exp)())()
8286
83- val bodyStmt = transformExp(letExp.body, c)
87+ val bodyStmt = transformExp(letExp.body, c, inhaleExp )
8488
8589 Seqn (Seq (expressionStmt, inhaleEq, bodyStmt), Seq (localVarDecl))()
8690
8791 case b : BinExp =>
88- val left = transformExp(b.left, c)
89- val right = transformExp(b.right, c)
92+ val left = transformExp(b.left, c, inhaleExp )
93+ val right = transformExp(b.right, c, inhaleExp )
9094
9195 // Short circuit evaluation
9296 val pureLeft : Exp = toPureBooleanExp(c).execute(b.left)
@@ -111,21 +115,21 @@ trait ExpTransformer extends ProgramManager with ErrorReporter {
111115 case _ : LocationAccess => EmptyStmt
112116
113117 case ap : AccessPredicate =>
114- val check = transformExp(ap.perm, c)
118+ val check = transformExp(ap.perm, c, false )
115119 val inhale = Inhale (ap)(ap.pos)
116120 Seqn (Seq (check, inhale), Nil )()
117121 case fa : Forall =>
118122 // we turn the quantified variables into local variables with arbitrary value and show that the expression holds
119123 // for arbitrary values, which is similar to a forall introduction
120124 val (localDeclMapping, transformedExp) = substituteWithFreshVars(fa.variables, fa.exp)
121- val expressionStmt = transformExp(transformedExp, c)
125+ val expressionStmt = transformExp(transformedExp, c, inhaleExp )
122126 Seqn (Seq (expressionStmt), localDeclMapping.map(_._2))(fa.pos, fa.info, fa.errT)
123127 case fp : ForPerm =>
124128 // let's pick arbitrary values for the quantified variables and check the body given that the current heap has
125129 // sufficient permissions
126130 val (localDeclMapping, transformedExp) = substituteWithFreshVars(fp.variables, fp.exp)
127131 val transformedRes = applySubstitution(localDeclMapping, fp.resource)
128- val expressionStmt = transformExp(transformedExp, c)
132+ val expressionStmt = transformExp(transformedExp, c, inhaleExp )
129133 val killBranchStmt = Inhale (FalseLit ()(e.pos, e.info, e.errT))(e.pos, e.info, e.errT)
130134 val thnStmt = Seqn (Seq (expressionStmt, killBranchStmt), Nil )(e.pos, e.info, e.errT)
131135 val ifCond = GtCmp (CurrentPerm (transformedRes)(e.pos, e.info, e.errT), NoPerm ()(e.pos, e.info, e.errT))(e.pos, e.info, e.errT)
@@ -137,15 +141,15 @@ trait ExpTransformer extends ProgramManager with ErrorReporter {
137141 // we can't use an assume statement at this point because the `assume`s have already been rewritten
138142 // furthermore, Viper only allows pure existentially quantified expressions
139143 val inhaleWitnesses = Inhale (transformedExp)(ex.pos, ex.info, ex.errT)
140- val expressionStmt = transformExp(transformedExp, c)
144+ val expressionStmt = transformExp(transformedExp, c, inhaleExp )
141145 Seqn (Seq (inhaleWitnesses, expressionStmt), localDeclMapping.map(_._2))(ex.pos, ex.info, ex.errT)
142146 case fa : FuncLikeApp =>
143- val argStmts = fa.args.map(transformExp(_, c))
147+ val argStmts = fa.args.map(transformExp(_, c, false ))
144148 Seqn (argStmts, Nil )()
145149 case e : ExtensionExp => reportUnsupportedExp(e)
146150
147151 case _ =>
148- val sub = e.subExps.map(transformExp(_, c))
152+ val sub = e.subExps.map(transformExp(_, c, false ))
149153 Seqn (sub, Nil )()
150154 }
151155
0 commit comments