@@ -20,7 +20,7 @@ import scala.collection.mutable
20
20
*
21
21
*/
22
22
class 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 ]({
24
24
// Does NOT rewrite ternary expressions; those have to be transformed to implications in advance
25
25
// using the ternaryRewriter below.
26
26
//
@@ -32,8 +32,8 @@ class ConditionalPermissionRewriter {
32
32
// Transformation causes issues if the permission involve a wildcard, so we avoid that case.
33
33
// Also, we cannot push perm and forperm expressions further in, since their value may be different at different
34
34
// 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)
37
37
else
38
38
(Implies (And (cc.c.exp, cond)(), acc)(i.pos, i.info, i.errT), cc)
39
39
alreadySeen.add(res._1)
@@ -61,8 +61,8 @@ class ConditionalPermissionRewriter {
61
61
case (acc : AccessPredicate , cc) if cc.c.optExp.nonEmpty =>
62
62
// Found an accessibility predicate nested under some conditionals
63
63
// 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
66
66
else
67
67
(Implies (cc.c.exp, acc)(acc.pos, acc.info, acc.errT), cc)
68
68
alreadySeen.add(res._1)
@@ -103,7 +103,11 @@ class ConditionalPermissionRewriter {
103
103
*/
104
104
def rewrite (root : Program ): Program = {
105
105
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)
107
111
res
108
112
}
109
113
@@ -114,26 +118,27 @@ class ConditionalPermissionRewriter {
114
118
115
119
/** Makes `acc`'s permissions conditional w.r.t. `cond`.
116
120
*/
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 = {
118
122
// We have to be careful not to introduce well-definedness issues when conditionalizing.
119
123
// For example, if we transform
120
124
// i >= 0 && i < |s| ==> acc(s[i].f)
121
125
// to
122
126
// acc(s[i].f, i >= 0 && i < |s| ? write : none)
123
127
// then backends may complain that s[i].f is not well-defined. Thus, we only perform the
124
128
// transformation if receiver/argument expressions are always well-defined.
129
+ val defaultPerm = if (isFunction) WildcardPerm ()() else FullPerm ()()
125
130
acc match {
126
131
case FieldAccessPredicate (loc, perm) =>
127
132
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)
129
134
} else {
130
135
// Hack: use a conditional null as the receiver, that's always well-defined.
131
136
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)
133
138
}
134
139
case PredicateAccessPredicate (loc, perm) =>
135
140
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)
137
142
else
138
143
Implies (cond.exp, acc)(acc.pos, acc.info, acc.errT)
139
144
case wand : MagicWand =>
0 commit comments