88import liquidjava .processor .VCImplication ;
99import liquidjava .rj_language .Predicate ;
1010import liquidjava .rj_language .ast .LiteralBoolean ;
11+ import liquidjava .rj_language .ast .Var ;
1112
1213/**
1314 * Simplifies VCImplication chains by removing vacuous binder implications
1415 */
1516public 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 */
0 commit comments