44import java .util .List ;
55import java .util .Optional ;
66
7+ import liquidjava .processor .SimplifiedVCImplication ;
78import liquidjava .processor .VCImplication ;
89import liquidjava .rj_language .Predicate ;
9- import liquidjava .rj_language .SimplifiedPredicate ;
10- import liquidjava .rj_language .SimplifiedPredicate .Binder ;
1110import liquidjava .rj_language .ast .BinaryExpression ;
1211import liquidjava .rj_language .ast .Expression ;
1312import liquidjava .rj_language .ast .Var ;
@@ -20,7 +19,7 @@ public class VCSubstitution {
2019 /**
2120 * A substitution discovered from an implication node
2221 */
23- private record Substitution (VCImplication source , Expression value ) {
22+ private record Substitution (VCImplication node , Expression replacement ) {
2423 }
2524
2625 /**
@@ -36,50 +35,47 @@ public static VCImplication applyOnce(VCImplication implication) {
3635 // apply only the first available substitution
3736 if (substitutionOpt .isPresent ()) {
3837 VCSubstitution .Substitution substitution = substitutionOpt .get ();
39- result = VCSubstitution .substitute (result , substitution .source (), substitution .value ());
38+ result = VCSubstitution .substitute (result , substitution .node (), substitution .replacement ());
4039 }
4140 return result ;
4241 }
4342
4443 /**
4544 * Rewrites one VC chain with a single substitution and removes its source node
4645 */
47- private static VCImplication substitute (VCImplication implication , VCImplication source , Expression value ) {
46+ private static VCImplication substitute (VCImplication implication , VCImplication node , Expression replacement ) {
4847 if (implication == null )
4948 return null ;
5049
5150 // skip the source node to remove it from the chain and start substitution from the next node
52- if (implication == source )
53- return substitute (implication .getNext (), source , value );
51+ if (implication == node )
52+ return substitute (implication .getNext (), node , replacement );
5453
55- Predicate refinement = substituteRefinement (implication .getRefinement (), source , value );
56- VCImplication result = new VCImplication (implication , refinement );
57- result .setNext (substitute (implication .getNext (), source , value ));
54+ VCImplication result = substituteNode (implication , node , replacement );
55+ result .setNext (substitute (implication .getNext (), node , replacement ));
5856 return result ;
5957 }
6058
6159 /**
62- * Substitutes a source binder inside one predicate while preserving simplification metadata
60+ * Substitutes a source binder inside one VC node while preserving simplification metadata
6361 */
64- private static Predicate substituteRefinement (Predicate refinement , VCImplication source , Expression value ) {
65- Expression exp = refinement .getExpression ().clone ();
66- Binder binder = new Binder (source .getName (), source .getType ());
67- Expression substituted = exp .substitute (new Var (binder .getName ()), value .clone ());
68-
69- return new SimplifiedPredicate (new Predicate (substituted ), refinement .getOrigin ().clone (),
70- bindersAfterSubstitution (refinement , exp , binder ));
62+ private static VCImplication substituteNode (VCImplication implication , VCImplication node , Expression replacement ) {
63+ Expression exp = implication .getRefinement ().getExpression ().clone ();
64+ if (!containsVar (exp , node .getName ()))
65+ return implication .copyWithRefinement (new Predicate (exp ));
66+
67+ Expression substituted = exp .substitute (new Var (node .getName ()), replacement .clone ());
68+ VCImplication origin = new VCImplication (node .getName (), node .getType (), origin (implication ));
69+ return new SimplifiedVCImplication (implication , new Predicate (substituted ), origin );
7170 }
7271
7372 /**
74- * Builds the binder metadata after one substitution
73+ * Uses the earliest original predicate available when simplifying an already-simplified node
7574 */
76- private static List <Binder > bindersAfterSubstitution (Predicate refinement , Expression exp ,
77- SimplifiedPredicate .Binder binder ) {
78- List <SimplifiedPredicate .Binder > binders = refinement instanceof SimplifiedPredicate previous
79- ? new ArrayList <>(previous .getBinders ()) : new ArrayList <>();
80- if (containsVariable (exp , binder .getName ()) && !binders .contains (binder ))
81- binders .add (binder );
82- return binders ;
75+ private static Predicate origin (VCImplication implication ) {
76+ if (implication instanceof SimplifiedVCImplication simplified )
77+ return simplified .getOrigin ().getRefinement ().clone ();
78+ return implication .getRefinement ().clone ();
8379 }
8480
8581 /**
@@ -111,9 +107,9 @@ private static Optional<Substitution> getSubstitution(VCImplication implication)
111107 Expression left = binary .getFirstOperand ();
112108 Expression right = binary .getSecondOperand ();
113109
114- if (isVar (left , name ) && !containsVariable (right , name ))
110+ if (isVar (left , name ) && !containsVar (right , name ))
115111 return Optional .of (new Substitution (implication , right .clone ()));
116- if (isVar (right , name ) && !containsVariable (left , name ))
112+ if (isVar (right , name ) && !containsVar (left , name ))
117113 return Optional .of (new Substitution (implication , left .clone ()));
118114
119115 return Optional .empty ();
@@ -129,7 +125,7 @@ public static boolean isVar(Expression expression, String name) {
129125 /**
130126 * Checks whether an expression contains a variable name
131127 */
132- public static boolean containsVariable (Expression expression , String name ) {
128+ public static boolean containsVar (Expression expression , String name ) {
133129 List <String > names = new ArrayList <>();
134130 expression .getVariableNames (names );
135131 return names .contains (name );
0 commit comments