@@ -20,7 +20,7 @@ import scala.collection.mutable
2020 *
2121 */
2222class ConditionalPermissionRewriter {
23- private def rewriter (implicit p : Program , alreadySeen : mutable.HashSet [Exp ]) = ViperStrategy .Context [Condition ]({
23+ private def rewriter (implicit p : Program , isFunction : Boolean , alreadySeen : mutable.HashSet [Exp ]) = ViperStrategy .Context [Condition ]({
2424 // Does NOT rewrite ternary expressions; those have to be transformed to implications in advance
2525 // using the ternaryRewriter below.
2626 //
@@ -32,8 +32,8 @@ class ConditionalPermissionRewriter {
3232 // Transformation causes issues if the permission involve a wildcard, so we avoid that case.
3333 // Also, we cannot push perm and forperm expressions further in, since their value may be different at different
3434 // places in the same assertion.
35- val res = if (! acc.perm.contains[WildcardPerm ] && ! Expressions .containsPermissionIntrospection(cond))
36- (conditionalize(acc, cc.c &*& cond), cc) // Won't recurse into acc's children (see recurseFunc below)
35+ val res = if ((isFunction || ! acc.perm.contains[WildcardPerm ]) && ! Expressions .containsPermissionIntrospection(cond))
36+ (conditionalize(acc, cc.c &*& cond, isFunction ), cc) // Won't recurse into acc's children (see recurseFunc below)
3737 else
3838 (Implies (And (cc.c.exp, cond)(), acc)(i.pos, i.info, i.errT), cc)
3939 alreadySeen.add(res._1)
@@ -61,8 +61,8 @@ class ConditionalPermissionRewriter {
6161 case (acc : AccessPredicate , cc) if cc.c.optExp.nonEmpty =>
6262 // Found an accessibility predicate nested under some conditionals
6363 // Wildcards may cause issues, see above.
64- val res = if (! acc.perm.contains[WildcardPerm ])
65- (conditionalize(acc, cc.c), cc) // Won't recurse into acc's children
64+ val res = if (isFunction || ! acc.perm.contains[WildcardPerm ])
65+ (conditionalize(acc, cc.c, isFunction ), cc) // Won't recurse into acc's children
6666 else
6767 (Implies (cc.c.exp, acc)(acc.pos, acc.info, acc.errT), cc)
6868 alreadySeen.add(res._1)
@@ -103,7 +103,11 @@ class ConditionalPermissionRewriter {
103103 */
104104 def rewrite (root : Program ): Program = {
105105 val noTernaryProgram : Program = ternaryRewriter.execute(root)
106- val res : Program = rewriter(root, new mutable.HashSet [Exp ]()).execute(noTernaryProgram)
106+ val functionRewriter = rewriter(root, true , new mutable.HashSet [Exp ]())
107+ val nonFunctionRewriter = rewriter(root, false , new mutable.HashSet [Exp ]())
108+ val res = noTernaryProgram.copy(functions = noTernaryProgram.functions.map(functionRewriter.execute[Function ](_)),
109+ predicates = noTernaryProgram.predicates.map(nonFunctionRewriter.execute[Predicate ](_)),
110+ methods = noTernaryProgram.methods.map(nonFunctionRewriter.execute[Method ](_)))(noTernaryProgram.pos, noTernaryProgram.info, noTernaryProgram.errT)
107111 res
108112 }
109113
@@ -114,26 +118,27 @@ class ConditionalPermissionRewriter {
114118
115119 /** Makes `acc`'s permissions conditional w.r.t. `cond`.
116120 */
117- private def conditionalize (acc : AccessPredicate , cond : Condition )(implicit p : Program ): Exp = {
121+ private def conditionalize (acc : AccessPredicate , cond : Condition , isFunction : Boolean )(implicit p : Program ): Exp = {
118122 // We have to be careful not to introduce well-definedness issues when conditionalizing.
119123 // For example, if we transform
120124 // i >= 0 && i < |s| ==> acc(s[i].f)
121125 // to
122126 // acc(s[i].f, i >= 0 && i < |s| ? write : none)
123127 // then backends may complain that s[i].f is not well-defined. Thus, we only perform the
124128 // transformation if receiver/argument expressions are always well-defined.
129+ val defaultPerm = if (isFunction) WildcardPerm ()() else FullPerm ()()
125130 acc match {
126131 case FieldAccessPredicate (loc, perm) =>
127132 if (Expressions .proofObligations(loc.rcv)(p).isEmpty) {
128- FieldAccessPredicate (loc, makeCondExp(cond.exp, perm))(acc.pos, acc.info, acc.errT)
133+ FieldAccessPredicate (loc, Some ( makeCondExp(cond.exp, perm.getOrElse(defaultPerm)) ))(acc.pos, acc.info, acc.errT)
129134 } else {
130135 // Hack: use a conditional null as the receiver, that's always well-defined.
131136 val fieldAccess = loc.copy(rcv = makeCondExp(cond.exp, loc.rcv, NullLit ()()))(loc.pos, loc.info, loc.errT)
132- FieldAccessPredicate (fieldAccess, makeCondExp(cond.exp, perm))(acc.pos, acc.info, acc.errT)
137+ FieldAccessPredicate (fieldAccess, Some ( makeCondExp(cond.exp, perm.getOrElse(defaultPerm)) ))(acc.pos, acc.info, acc.errT)
133138 }
134139 case PredicateAccessPredicate (loc, perm) =>
135140 if (! loc.args.exists(a => Expressions .proofObligations(a)(p).nonEmpty))
136- PredicateAccessPredicate (loc, makeCondExp(cond.exp, perm))(acc.pos, acc.info, acc.errT)
141+ PredicateAccessPredicate (loc, Some ( makeCondExp(cond.exp, perm.getOrElse(defaultPerm)) ))(acc.pos, acc.info, acc.errT)
137142 else
138143 Implies (cond.exp, acc)(acc.pos, acc.info, acc.errT)
139144 case wand : MagicWand =>
0 commit comments