Skip to content

Commit acebb01

Browse files
committed
Remove Unused Fresh Path Binders In Simplification
1 parent 8cdac31 commit acebb01

4 files changed

Lines changed: 36 additions & 12 deletions

File tree

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

Lines changed: 19 additions & 4 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
*/
@@ -47,12 +50,12 @@ private VCImplication simplify(VCImplication implication) {
4750
}
4851

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

55-
// ∀x. R => P -> P when x is not used in 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

@@ -62,13 +65,25 @@ private VCImplication removeBinder(VCImplication implication) {
6265
}
6366

6467
/**
65-
* Checks whether a binder is unused and can be removed
68+
* Checks whether a binder is unused and can be removed without changing the VC conclusion
6669
*/
6770
private boolean isRemovableUnusedBinder(VCImplication implication) {
6871
if (!implication.hasBinder() || containsVar(implication.getNext(), implication.getName()))
6972
return false;
7073

71-
return implication.hasNext() || isTrueBinder(implication);
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());
7287
}
7388

7489
/**

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,13 @@ void removesTrueBinderWhenVariableIsUnusedDownstream() {
1313
}
1414

1515
@Test
16-
void removesNonTrueBinderWhenVariableIsUnusedDownstream() {
17-
assertSimplificationSteps(binderSimplification, vc("∀x:int. x > 0", "y > 0"), step("y > 0"));
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"));
1823
}
1924

2025
@Test

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,13 +108,14 @@ void simplifyUsesLogicalSimplificationToEnableSubstitutionOnNextStep() {
108108
}
109109

110110
@Test
111-
void simplifyRemovesUnusedBinderBeforeFolding() {
112-
assertSimplificationSteps(vc("∀x:int. 1 > 2", "y > 0"), step("y > 0"));
111+
void simplifyUsesFoldingToEnableBinderSimplificationOnNextStep() {
112+
assertSimplificationSteps(vc("∀x:int. 1 > 2", "y > 0"), step("false", "y > 0"), step("true"));
113113
}
114114

115115
@Test
116-
void simplifyRemovesUnusedBinderBeforeArithmeticAndLogicalSimplification() {
117-
assertSimplificationSteps(vc("∀x:int. x + 0 == x", "y > 0"), step("y > 0"));
116+
void simplifyUsesArithmeticAndLogicalSimplificationToEnableBinderRemoval() {
117+
assertSimplificationSteps(vc("∀x:int. x + 0 == x", "y > 0"), step("x == x", "y > 0"), step("true", "y > 0"),
118+
step("y > 0"));
118119
}
119120

120121
@Test

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)