Skip to content

Commit e4c42c1

Browse files
committed
Fix Usage Detection for Repeated Equalities
1 parent 6d1f086 commit e4c42c1

3 files changed

Lines changed: 25 additions & 4 deletions

File tree

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public static Map<String, Expression> resolve(Expression exp) {
2727
resolveRecursive(exp, map);
2828

2929
// remove variables that were not used in the expression
30-
map.entrySet().removeIf(entry -> !hasUsage(exp, entry.getKey(), entry.getValue()));
30+
map.entrySet().removeIf(entry -> !hasUsage(exp, entry.getKey(), entry.getValue(), true));
3131

3232
// transitively resolve variables
3333
return resolveTransitive(map);
@@ -136,12 +136,14 @@ private static Expression lookup(Expression exp, Map<String, Expression> map, Se
136136
*
137137
* @param exp
138138
* @param name
139+
* @param value
140+
* @param canExcludeDefinition
139141
*
140142
* @return true if used, false otherwise
141143
*/
142-
private static boolean hasUsage(Expression exp, String name, Expression value) {
144+
private static boolean hasUsage(Expression exp, String name, Expression value, boolean canExcludeDefinition) {
143145
// exclude own definitions
144-
if (exp instanceof BinaryExpression binary && "==".equals(binary.getOperator())) {
146+
if (canExcludeDefinition && exp instanceof BinaryExpression binary && "==".equals(binary.getOperator())) {
145147
Expression left = binary.getFirstOperand();
146148
Expression right = binary.getSecondOperand();
147149
if (left instanceof Var v && v.getName().equals(name) && right.equals(value)
@@ -167,8 +169,10 @@ && isConstant(left))
167169

168170
// recurse children
169171
if (exp.hasChildren()) {
172+
boolean childCanExcludeDefinition = exp instanceof BinaryExpression binary
173+
&& "&&".equals(binary.getOperator());
170174
for (Expression child : exp.getChildren())
171-
if (hasUsage(child, name, value))
175+
if (hasUsage(child, name, value, childCanExcludeDefinition))
172176
return true;
173177
}
174178

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,4 +658,12 @@ void testEnumConstantsPropagateIntoTernaryCondition() {
658658

659659
assertEquals("start(param)", result.getValue().toString());
660660
}
661+
662+
@Test
663+
void testRepeatedEqualDefinitionPropagatesIntoTernaryCondition() {
664+
Expression expression = parse("mode == 2 && (mode == 2 ? explicit(param) : start(param))");
665+
ValDerivationNode result = ExpressionSimplifier.simplify(expression);
666+
667+
assertEquals("explicit(param)", result.getValue().toString());
668+
}
661669
}

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,15 @@ void testDifferentEqualityInIteConditionCountsAsUsage() {
9999
assertEquals("1", result.get("mode").toString());
100100
}
101101

102+
@Test
103+
void testRepeatedEqualDefinitionCountsAsUsage() {
104+
Expression expression = parse("mode == 2 && (mode == 2 ? explicit(param) : start(param))");
105+
Map<String, Expression> result = VariableResolver.resolve(expression);
106+
107+
assertEquals(1, result.size(), "Repeated equalities should keep one definition and treat the other as usage");
108+
assertEquals("2", result.get("mode").toString());
109+
}
110+
102111
@Test
103112
void testReturnVariableIsNotSubstituted() {
104113
Expression expression = parse("x > 0 && #ret_1 == x");

0 commit comments

Comments
 (0)