Skip to content

Commit 0ded161

Browse files
authored
Remove Unused Fresh Path Binders In Simplification (#278)
1 parent f6ea882 commit 0ded161

3 files changed

Lines changed: 50 additions & 7 deletions

File tree

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

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,15 @@
88
import liquidjava.processor.VCImplication;
99
import liquidjava.rj_language.Predicate;
1010
import liquidjava.rj_language.ast.LiteralBoolean;
11+
import liquidjava.rj_language.ast.Var;
1112

1213
/**
1314
* Simplifies VCImplication chains by removing vacuous binder implications
1415
*/
1516
public class VCBinderSimplification implements VCSimplificationPass {
1617

18+
private static final String FRESH_PREFIX = "#fresh_";
19+
1720
/**
1821
* Applies one binder simplification in a VC chain
1922
*/
@@ -34,8 +37,8 @@ private VCImplication simplify(VCImplication implication) {
3437
if (isFalseBinder(implication))
3538
return collapseFalseBinder(implication);
3639

37-
if (isTrueBinder(implication) && !containsVar(implication.getNext(), implication.getName()))
38-
return removeTrueBinder(implication);
40+
if (isRemovableUnusedBinder(implication))
41+
return removeBinder(implication);
3942

4043
VCImplication next = simplify(implication.getNext());
4144
if (next == null)
@@ -47,12 +50,12 @@ private VCImplication simplify(VCImplication implication) {
4750
}
4851

4952
/**
50-
* Removes a true binder whose name is not used in the suffix
53+
* Removes a binder that can be omitted from the suffix
5154
*/
52-
private VCImplication removeTrueBinder(VCImplication implication) {
55+
private VCImplication removeBinder(VCImplication implication) {
5356
VCImplication next = implication.getNext();
5457

55-
// ∀x. true => P -> P
58+
// ∀x. true => P -> P, and unused generated path conditions can be omitted from diagnostics
5659
if (next != null)
5760
return next.clone();
5861

@@ -61,6 +64,28 @@ private VCImplication removeTrueBinder(VCImplication implication) {
6164
return new VCImplication(truePredicate);
6265
}
6366

67+
/**
68+
* Checks whether a binder is unused and can be removed without changing the VC conclusion
69+
*/
70+
private boolean isRemovableUnusedBinder(VCImplication implication) {
71+
if (!implication.hasBinder() || containsVar(implication.getNext(), implication.getName()))
72+
return false;
73+
74+
return isTrueBinder(implication) || isUnusedFreshPathBinder(implication);
75+
}
76+
77+
/**
78+
* Checks for a generated boolean path binder refined exactly by itself
79+
*/
80+
private boolean isUnusedFreshPathBinder(VCImplication implication) {
81+
if (!implication.hasNext() || !implication.getName().startsWith(FRESH_PREFIX)
82+
|| !"boolean".equals(implication.getType().getQualifiedName()))
83+
return false;
84+
85+
return implication.getRefinement().getExpression()instanceof Var var
86+
&& implication.getName().equals(var.getName());
87+
}
88+
6489
/**
6590
* Replaces a false binder implication with true
6691
*/

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,21 @@ void removesTrueBinderWhenVariableIsUnusedDownstream() {
1212
assertSimplificationSteps(binderSimplification, vc("∀x:int. true", "y > 0"), step("y > 0"));
1313
}
1414

15+
@Test
16+
void removesFreshPathBinderWhenVariableIsUnusedDownstream() {
17+
assertSimplificationSteps(binderSimplification, vc("∀#fresh_1:boolean. #fresh_1", "y > 0"), step("y > 0"));
18+
}
19+
20+
@Test
21+
void keepsNonTrueBinderWhenVariableIsUnusedDownstream() {
22+
assertSimplificationSteps(binderSimplification, vc("∀x:int. x > 0", "y > 0"), step("x > 0", "y > 0"));
23+
}
24+
25+
@Test
26+
void keepsNonTrueTerminalBinderAsConclusion() {
27+
assertSimplificationSteps(binderSimplification, vc("∀x:int. x > 0"), step("x > 0"));
28+
}
29+
1530
@Test
1631
void keepsTrueBinderWhenVariableIsUsedDownstream() {
1732
assertSimplificationSteps(binderSimplification, vc("∀x:int. true", "x > 0"), step("true", "x > 0"));

liquidjava-verifier/src/test/java/liquidjava/utils/VCTestUtils.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@
1313
import liquidjava.rj_language.opt.VCSimplificationResult;
1414
import liquidjava.rj_language.parsing.RefinementsParser;
1515
import spoon.Launcher;
16+
import spoon.reflect.factory.TypeFactory;
1617
import spoon.reflect.reference.CtTypeReference;
1718

1819
public class VCTestUtils {
1920

20-
private static final CtTypeReference<?> INT = new Launcher().getFactory().Type().INTEGER_PRIMITIVE;
21+
private static final TypeFactory TYPE_FACTORY = new Launcher().getFactory().Type();
2122

2223
public static VCImplication vc(String... implications) {
2324
VCImplication first = null;
@@ -97,7 +98,9 @@ private static VCImplication parseImplication(String implication) {
9798

9899
private static CtTypeReference<?> type(String name) {
99100
if ("int".equals(name))
100-
return INT;
101+
return TYPE_FACTORY.INTEGER_PRIMITIVE;
102+
if ("boolean".equals(name))
103+
return TYPE_FACTORY.BOOLEAN_PRIMITIVE;
101104
throw new IllegalArgumentException("Unsupported test type: " + name);
102105
}
103106

0 commit comments

Comments
 (0)