1515
1616import liquidjava .processor .VCImplication ;
1717import liquidjava .rj_language .Predicate ;
18+ import liquidjava .rj_language .ast .AliasInvocation ;
1819import liquidjava .rj_language .ast .BinaryExpression ;
1920import liquidjava .rj_language .ast .Expression ;
2021import liquidjava .rj_language .ast .FunctionInvocation ;
2728 * value it constrains. Different ghost functions, or the same one over different objects, are different solver terms,
2829 * so facts that share no symbol with expected, directly or through other facts, are independent of it and are left out.
2930 * An object whose value a fact constrains, such as {@code x == y}, or that an alias or unknown function takes, is one
30- * symbol with all its ghost functions, so its facts are never split. Nothing changes when every fact or none is
31- * relevant
31+ * symbol with all its ghost functions, so its facts are never split. A constant, such as an enum constant read in code,
32+ * 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
3235 */
3336public class VCRelevantFacts implements VCSimplificationPass {
3437
3538 private final Expression expected ;
3639 private final Function <String , Set <String >> ghostFunctionsOf ;
40+ private final Set <String > constants ;
3741
3842 /**
3943 * @param ghostFunctionsOf
4044 * the ghost functions an invocation name stands for: a state's state set function, or the ghost itself;
4145 * none for any other name
46+ * @param constants
47+ * the variable names that denote constants, such as enum constants
4248 */
43- public VCRelevantFacts (Expression expected , Function <String , Set <String >> ghostFunctionsOf ) {
49+ public VCRelevantFacts (Expression expected , Function <String , Set <String >> ghostFunctionsOf , Set < String > constants ) {
4450 this .expected = expected ;
4551 this .ghostFunctionsOf = ghostFunctionsOf ;
52+ this .constants = constants ;
4653 }
4754
4855 @ Override
@@ -60,8 +67,10 @@ public VCImplication apply(VCImplication implication) {
6067 addSymbols (expected , new HashMap <>(), values );
6168 allFacts .forEach (fact -> addSymbols (fact , new HashMap <>(), values ));
6269
63- Set <String > linked = symbolsOf (expected , values );
64- List <Set <String >> unlinked = new ArrayList <>(allFacts .stream ().map (fact -> symbolsOf (fact , values )).toList ());
70+ Set <String > valueConstants = valueConstants (expected , allFacts );
71+ Set <String > linked = symbolsOf (expected , values , valueConstants );
72+ List <Set <String >> unlinked = new ArrayList <>(
73+ allFacts .stream ().map (fact -> symbolsOf (fact , values , valueConstants )).toList ());
6574 boolean changed = true ;
6675 while (changed ) {
6776 changed = false ;
@@ -75,8 +84,11 @@ public VCImplication apply(VCImplication implication) {
7584 }
7685 }
7786
78- List <List <Expression >> kept = rowFacts .stream ().map (facts -> facts .stream ()
79- .filter (fact -> symbolsOf (fact , values ).stream ().anyMatch (linked ::contains )).toList ()).toList ();
87+ List <List <Expression >> kept = rowFacts .stream ()
88+ .map (facts -> facts .stream ()
89+ .filter (fact -> symbolsOf (fact , values , valueConstants ).stream ().anyMatch (linked ::contains ))
90+ .toList ())
91+ .toList ();
8092 int relevant = kept .stream ().mapToInt (List ::size ).sum ();
8193 if (relevant == 0 || relevant == allFacts .size ())
8294 return implication ;
@@ -99,13 +111,45 @@ private VCImplication rebuild(VCImplication row, Iterator<List<Expression>> all,
99111 return result ;
100112 }
101113
114+ // The constants no function or alias takes and that are compared with no value one takes
115+ private Set <String > valueConstants (Expression expected , List <Expression > facts ) {
116+ Set <String > objects = new HashSet <>();
117+ addArguments (expected , objects );
118+ facts .forEach (fact -> addArguments (fact , objects ));
119+ Set <String > valueConstants = new HashSet <>(constants );
120+ valueConstants .removeAll (objects );
121+ removeComparedWithObjects (expected , objects , valueConstants );
122+ facts .forEach (fact -> removeComparedWithObjects (fact , objects , valueConstants ));
123+ return valueConstants ;
124+ }
125+
126+ private static void addArguments (Expression expression , Set <String > objects ) {
127+ if (expression instanceof FunctionInvocation invocation )
128+ invocation .getArgs ().forEach (argument -> objects .addAll (variablesOf (argument )));
129+ else if (expression instanceof AliasInvocation alias )
130+ alias .getArgs ().forEach (argument -> objects .addAll (variablesOf (argument )));
131+ expression .getChildren ().forEach (child -> addArguments (child , objects ));
132+ }
133+
134+ private static void removeComparedWithObjects (Expression expression , Set <String > objects ,
135+ Set <String > valueConstants ) {
136+ if (expression instanceof BinaryExpression binary
137+ && ("==" .equals (binary .getOperator ()) || "!=" .equals (binary .getOperator ()))) {
138+ List <String > compared = variablesOf (binary );
139+ if (compared .stream ().anyMatch (objects ::contains ))
140+ valueConstants .removeAll (compared );
141+ }
142+ expression .getChildren ().forEach (child -> removeComparedWithObjects (child , objects , valueConstants ));
143+ }
144+
102145 // The symbols an expression constrains: f(x) for a ghost function over an object, or the object itself when values
103- // has it, and the variables whose value it constrains
104- private Set <String > symbolsOf (Expression expression , Set <String > values ) {
146+ // has it, and the variables whose value it constrains, except the value constants
147+ private Set <String > symbolsOf (Expression expression , Set <String > values , Set < String > valueConstants ) {
105148 Map <String , String > applications = new HashMap <>();
106149 Set <String > symbols = new HashSet <>();
107150 addSymbols (expression , applications , symbols );
108151 applications .forEach ((application , object ) -> symbols .add (values .contains (object ) ? object : application ));
152+ symbols .removeAll (valueConstants );
109153 return symbols ;
110154 }
111155
0 commit comments