Skip to content

Commit fca40b1

Browse files
Keep linking facts through an enum constant a chain of comparisons relates to an object
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 0bb37b4 commit fca40b1

2 files changed

Lines changed: 28 additions & 9 deletions

File tree

‎liquidjava-verifier/src/main/java/liquidjava/rj_language/opt/VCRelevantFacts.java‎

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@
3030
* An object whose value a fact constrains, such as {@code x == y}, or that an alias or unknown function takes, is one
3131
* symbol with all its ghost functions, so its facts are never split. A constant, such as an enum constant read in code,
3232
* is a fixed value, so facts that only compare values with it share no symbol through it; it stays one when a function
33-
* or alias takes it or a value one takes is compared with it, as equal objects have equal ghost values. Nothing changes
34-
* when every fact or none is relevant
33+
* or alias takes it or a chain of comparisons relates it to a value one takes, as equal objects have equal ghost
34+
* values. Nothing changes when every fact or none is relevant
3535
*/
3636
public class VCRelevantFacts implements VCSimplificationPass {
3737

@@ -111,15 +111,17 @@ private VCImplication rebuild(VCImplication row, Iterator<List<Expression>> all,
111111
return result;
112112
}
113113

114-
// The constants no function or alias takes and that are compared with no value one takes
114+
// The constants no function or alias takes and that no chain of comparisons relates to a value one takes
115115
private Set<String> valueConstants(Expression expected, List<Expression> facts) {
116116
Set<String> objects = new HashSet<>();
117117
addArguments(expected, objects);
118118
facts.forEach(fact -> addArguments(fact, objects));
119+
List<Expression> all = new ArrayList<>(facts);
120+
all.add(expected);
121+
while (all.stream().anyMatch(expression -> addComparedWithObjects(expression, objects)))
122+
;
119123
Set<String> valueConstants = new HashSet<>(constants);
120124
valueConstants.removeAll(objects);
121-
removeComparedWithObjects(expected, objects, valueConstants);
122-
facts.forEach(fact -> removeComparedWithObjects(fact, objects, valueConstants));
123125
return valueConstants;
124126
}
125127

@@ -131,15 +133,18 @@ else if (expression instanceof AliasInvocation alias)
131133
expression.getChildren().forEach(child -> addArguments(child, objects));
132134
}
133135

134-
private static void removeComparedWithObjects(Expression expression, Set<String> objects,
135-
Set<String> valueConstants) {
136+
// Adds to objects the variables a comparison relates to one of them; true when it added any
137+
private static boolean addComparedWithObjects(Expression expression, Set<String> objects) {
138+
boolean added = false;
136139
if (expression instanceof BinaryExpression binary
137140
&& ("==".equals(binary.getOperator()) || "!=".equals(binary.getOperator()))) {
138141
List<String> compared = variablesOf(binary);
139142
if (compared.stream().anyMatch(objects::contains))
140-
valueConstants.removeAll(compared);
143+
added = objects.addAll(compared);
141144
}
142-
expression.getChildren().forEach(child -> removeComparedWithObjects(child, objects, valueConstants));
145+
for (Expression child : expression.getChildren())
146+
added |= addComparedWithObjects(child, objects);
147+
return added;
143148
}
144149

145150
// The symbols an expression constrains: f(x) for a ghost function over an object, or the object itself when values

‎liquidjava-verifier/src/test/java/liquidjava/rj_language/opt/VCSimplificationTest.java‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,20 @@ void relevantStepLinksFactsThroughAConstantAnObjectEquals() {
230230
assertSimplificationSteps(relevantTo("tilingSet(p)"), implication, step("p == Photo", "startTiling(Photo)"));
231231
}
232232

233+
@Test
234+
void relevantStepLinksFactsThroughAConstantAChainOfEqualitiesRelatesToAnObject() {
235+
// p == r == Photo == s == q, so the facts about q constrain tilingSet(p)
236+
Var photo = new Var("Mode.Photo");
237+
VCImplication implication = vc("∀p:Mode. true", "true");
238+
implication.setRefinement(new Predicate(new BinaryExpression(RefinementsParser.createAST("p == r", ""), "&&",
239+
new BinaryExpression(new Var("r"), "==", photo))));
240+
implication.getNext()
241+
.setRefinement(new Predicate(new BinaryExpression(new BinaryExpression(new Var("s"), "==", photo), "&&",
242+
RefinementsParser.createAST("s == q && startTiling(q)", ""))));
243+
assertSimplificationSteps(relevantTo("tilingSet(p)"), implication,
244+
step("p == r && r == Photo", "s == Photo && s == q && startTiling(q)"));
245+
}
246+
233247
@Test
234248
void relevantStepKeepsFactsAnUnknownFunctionTakesTheObjectOf() {
235249
assertSimplificationSteps(relevantTo("tilingSet(p)"), vc("compressionSet(p) && ready(p)", "startTiling(p)"),

0 commit comments

Comments
 (0)