Skip to content

Commit 96f5af0

Browse files
committed
Fix Single Equality Expression Simplification
1 parent 11a9263 commit 96f5af0

File tree

3 files changed

+144
-0
lines changed

3 files changed

+144
-0
lines changed

liquidjava-verifier/src/main/java/liquidjava/rj_language/opt/VariableResolver.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@ public class VariableResolver {
1515
* Extracts variables with constant values from an expression Returns a map from variable names to their values
1616
*/
1717
public static Map<String, Expression> resolve(Expression exp) {
18+
// if the expression is just a single equality (not a conjunction) don't extract it
19+
// this avoids creating tautologies like "1 == 1" after substitution, which are then simplified to "true"
20+
if (exp instanceof BinaryExpression) {
21+
BinaryExpression be = (BinaryExpression) exp;
22+
if ("==".equals(be.getOperator())) {
23+
return new HashMap<>();
24+
}
25+
}
26+
1827
Map<String, Expression> map = new HashMap<>();
1928
resolveRecursive(exp, map);
2029
return resolveTransitive(map);

liquidjava-verifier/src/test/java/liquidjava/rj_language/opt/ExpressionSimplifierTest.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,31 @@ void testComplexArithmeticWithMultipleOperations() {
304304
assertDerivationEquals(expected, result, "");
305305
}
306306

307+
@Test
308+
void testSingleEqualityNotSimplifiedToTrue() {
309+
// Given: x == 1
310+
// Expected: x == 1 (should not be simplified to "true")
311+
312+
Expression varX = new Var("x");
313+
Expression one = new LiteralInt(1);
314+
Expression xEquals1 = new BinaryExpression(varX, "==", one);
315+
316+
// When
317+
ValDerivationNode result = ExpressionSimplifier.simplify(xEquals1);
318+
319+
// Then
320+
assertNotNull(result, "Result should not be null");
321+
assertEquals("x == 1", result.getValue().toString(),
322+
"Single equality should not be simplified to a boolean literal");
323+
324+
// The result should be the original expression unchanged
325+
assertTrue(result.getValue() instanceof BinaryExpression, "Result should still be a binary expression");
326+
BinaryExpression resultExpr = (BinaryExpression) result.getValue();
327+
assertEquals("==", resultExpr.getOperator(), "Operator should still be ==");
328+
assertEquals("x", resultExpr.getFirstOperand().toString(), "Left operand should be x");
329+
assertEquals("1", resultExpr.getSecondOperand().toString(), "Right operand should be 1");
330+
}
331+
307332
/**
308333
* Helper method to compare two derivation nodes recursively
309334
*/
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package liquidjava.rj_language.opt;
2+
3+
import static org.junit.jupiter.api.Assertions.*;
4+
5+
import java.util.Map;
6+
7+
import org.junit.jupiter.api.Test;
8+
9+
import liquidjava.rj_language.ast.BinaryExpression;
10+
import liquidjava.rj_language.ast.Expression;
11+
import liquidjava.rj_language.ast.GroupExpression;
12+
import liquidjava.rj_language.ast.LiteralInt;
13+
import liquidjava.rj_language.ast.UnaryExpression;
14+
import liquidjava.rj_language.ast.Var;
15+
16+
class VariableResolverTest {
17+
18+
@Test
19+
void testSingleEqualityNotExtracted() {
20+
// x == 1 should not extract because it's a single equality
21+
Expression varX = new Var("x");
22+
Expression one = new LiteralInt(1);
23+
Expression xEquals1 = new BinaryExpression(varX, "==", one);
24+
Map<String, Expression> result = VariableResolver.resolve(xEquals1);
25+
assertTrue(result.isEmpty(), "Single equality should not extract variable mapping");
26+
}
27+
28+
@Test
29+
void testConjunctionExtractsVariables() {
30+
// x + y && x == 1 && y == 2 should extract x -> 1, y -> 2
31+
Expression varX = new Var("x");
32+
Expression varY = new Var("y");
33+
Expression one = new LiteralInt(1);
34+
Expression two = new LiteralInt(2);
35+
36+
Expression xPlusY = new BinaryExpression(varX, "+", varY);
37+
Expression xEquals1 = new BinaryExpression(varX, "==", one);
38+
Expression yEquals2 = new BinaryExpression(varY, "==", two);
39+
40+
Expression conditions = new BinaryExpression(xEquals1, "&&", yEquals2);
41+
Expression fullExpr = new BinaryExpression(xPlusY, "&&", conditions);
42+
43+
Map<String, Expression> result = VariableResolver.resolve(fullExpr);
44+
assertEquals(2, result.size(), "Should extract both variables");
45+
assertEquals("1", result.get("x").toString());
46+
assertEquals("2", result.get("y").toString());
47+
}
48+
49+
@Test
50+
void testSingleComparisonNotExtracted() {
51+
// x > 0 should not extract anything
52+
Expression varX = new Var("x");
53+
Expression zero = new LiteralInt(0);
54+
Expression xGreaterZero = new BinaryExpression(varX, ">", zero);
55+
56+
Map<String, Expression> result = VariableResolver.resolve(xGreaterZero);
57+
assertTrue(result.isEmpty(), "Single comparison should not extract variable mapping");
58+
}
59+
60+
@Test
61+
void testSingleArithmeticExpression() {
62+
// x + 1 should not extract anything
63+
Expression varX = new Var("x");
64+
Expression one = new LiteralInt(1);
65+
Expression xPlusOne = new BinaryExpression(varX, "+", one);
66+
67+
Map<String, Expression> result = VariableResolver.resolve(xPlusOne);
68+
assertTrue(result.isEmpty(), "Single arithmetic expression should not extract variable mapping");
69+
}
70+
71+
@Test
72+
void testDisjunctionWithEqualities() {
73+
// x == 1 || y == 2 should not extract anything
74+
Expression varX = new Var("x");
75+
Expression varY = new Var("y");
76+
Expression one = new LiteralInt(1);
77+
Expression two = new LiteralInt(2);
78+
79+
Expression xEquals1 = new BinaryExpression(varX, "==", one);
80+
Expression yEquals2 = new BinaryExpression(varY, "==", two);
81+
Expression disjunction = new BinaryExpression(xEquals1, "||", yEquals2);
82+
83+
Map<String, Expression> result = VariableResolver.resolve(disjunction);
84+
assertTrue(result.isEmpty(), "Disjunction should not extract variable mappings");
85+
}
86+
87+
@Test
88+
void testNegatedEquality() {
89+
// !(x == 1) should not extract because it's a single equality
90+
Expression varX = new Var("x");
91+
Expression one = new LiteralInt(1);
92+
Expression xEquals1 = new BinaryExpression(varX, "==", one);
93+
Expression notXEquals1 = new UnaryExpression("!", xEquals1);
94+
95+
Map<String, Expression> result = VariableResolver.resolve(notXEquals1);
96+
assertTrue(result.isEmpty(), "Negated equality should not extract variable mapping");
97+
}
98+
99+
@Test
100+
void testGroupedEquality() {
101+
// (x == 1) should not extract because it's a single equality
102+
Expression varX = new Var("x");
103+
Expression one = new LiteralInt(1);
104+
Expression xEquals1 = new BinaryExpression(varX, "==", one);
105+
Expression grouped = new GroupExpression(xEquals1);
106+
107+
Map<String, Expression> result = VariableResolver.resolve(grouped);
108+
assertTrue(result.isEmpty(), "Grouped single equality should not extract variable mapping");
109+
}
110+
}

0 commit comments

Comments
 (0)