Skip to content

Commit 1ca6aa2

Browse files
authored
Check If Refinement Predicates Are Boolean Expressions (#85)
1 parent 57ccfcc commit 1ca6aa2

File tree

3 files changed

+49
-4
lines changed

3 files changed

+49
-4
lines changed

liquidjava-verifier/src/main/java/liquidjava/processor/refinement_checker/TypeChecker.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,15 @@ public Optional<Predicate> getRefinementFromAnnotation(CtElement element) throws
8888
}
8989
if (ref.isPresent()) {
9090
Predicate p = new Predicate(ref.get(), element, errorEmitter);
91+
92+
// check if refinement is valid
93+
if (!p.getExpression().isBooleanExpression()) {
94+
ErrorHandler.printCustomError(element, "Refinement predicate must be a boolean expression",
95+
errorEmitter);
96+
}
9197
if (errorEmitter.foundError())
9298
return Optional.empty();
99+
93100
constr = Optional.of(p);
94101
}
95102
return constr;
@@ -245,6 +252,12 @@ protected void handleAlias(String value, CtElement element) {
245252
}
246253
if (klass != null && path != null) {
247254
a.parse(path);
255+
// refinement alias must return a boolean expression
256+
if (a.getExpression() != null && !a.getExpression().isBooleanExpression()) {
257+
ErrorHandler.printCustomError(element, "Refinement alias must return a boolean expression",
258+
errorEmitter);
259+
return;
260+
}
248261
AliasWrapper aw = new AliasWrapper(a, factory, WILD_VAR, context, klass, path);
249262
context.addAlias(aw);
250263
}

liquidjava-verifier/src/main/java/liquidjava/processor/refinement_checker/object_checkers/AuxStateHandler.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,15 @@ private static void setConstructorStates(RefinedFunction f, List<CtAnnotation<?
6565
Map<String, CtExpression> m = an.getAllValues();
6666
String to = TypeCheckingUtils.getStringFromAnnotation(m.get("to"));
6767
ObjectState state = new ObjectState();
68-
if (to != null)
69-
state.setTo(new Predicate(to, element, tc.getErrorEmitter()));
68+
if (to != null) {
69+
Predicate p = new Predicate(to, element, tc.getErrorEmitter());
70+
if (!p.getExpression().isBooleanExpression()) {
71+
ErrorHandler.printCustomError(element, "State refinement transition must be a boolean expression",
72+
tc.getErrorEmitter());
73+
return;
74+
}
75+
state.setTo(p);
76+
}
7077
l.add(state);
7178
}
7279
f.setAllStates(l);
@@ -176,6 +183,11 @@ private static ObjectState getStates(CtAnnotation<? extends Annotation> ctAnnota
176183
private static Predicate createStatePredicate(String value, /* RefinedFunction f */ String targetClass,
177184
TypeChecker tc, CtElement e, boolean isTo, String prefix) throws ParsingException {
178185
Predicate p = new Predicate(value, e, tc.getErrorEmitter(), prefix);
186+
if (!p.getExpression().isBooleanExpression()) {
187+
ErrorHandler.printCustomError(e, "State refinement transition must be a boolean expression",
188+
tc.getErrorEmitter());
189+
return new Predicate();
190+
}
179191
String t = targetClass; // f.getTargetClass();
180192
CtTypeReference<?> r = tc.getFactory().Type().createReference(t);
181193

liquidjava-verifier/src/main/java/liquidjava/rj_language/ast/Expression.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
import java.util.List;
55
import java.util.Map;
66

7-
import com.microsoft.z3.Expr;
8-
97
import liquidjava.processor.context.Context;
108
import liquidjava.processor.facade.AliasDTO;
119
import liquidjava.rj_language.ast.typing.TypeInfer;
@@ -53,6 +51,28 @@ public boolean isLiteral() {
5351
return this instanceof LiteralInt || this instanceof LiteralReal || this instanceof LiteralBoolean;
5452
}
5553

54+
/**
55+
* Checks if this expression produces a boolean type based on its structure
56+
*
57+
* @return true if it is a boolean expression, false otherwise
58+
*/
59+
public boolean isBooleanExpression() {
60+
if (this instanceof LiteralBoolean || this instanceof Ite || this instanceof AliasInvocation
61+
|| this instanceof FunctionInvocation) {
62+
return true;
63+
}
64+
if (this instanceof GroupExpression ge) {
65+
return ge.getExpression().isBooleanExpression();
66+
}
67+
if (this instanceof BinaryExpression be) {
68+
return be.isBooleanOperation() || be.isLogicOperation();
69+
}
70+
if (this instanceof UnaryExpression ue) {
71+
return ue.getOp().equals("!");
72+
}
73+
return false;
74+
}
75+
5676
/**
5777
* Substitutes the expression first given expression by the second
5878
*

0 commit comments

Comments
 (0)