Skip to content

Commit a3988dc

Browse files
committed
Fix VCFunctionSubstitution
1 parent 6512612 commit a3988dc

3 files changed

Lines changed: 29 additions & 28 deletions

File tree

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

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package liquidjava.rj_language.opt;
22

3+
import static liquidjava.rj_language.opt.VCSimplificationUtils.copyWithRefinement;
4+
35
import java.util.Optional;
46

5-
import liquidjava.processor.SimplifiedVCImplication;
67
import liquidjava.processor.VCImplication;
78
import liquidjava.rj_language.Predicate;
89
import liquidjava.rj_language.ast.BinaryExpression;
@@ -46,41 +47,41 @@ private VCImplication substitute(VCImplication implication, VCImplication node,
4647

4748
// skip the source node to remove it from the chain and start substitution from the next node
4849
if (implication == node) {
49-
VCImplication result = implication.copyWithRefinement(implication.getRefinement().clone());
50-
result.setNext(substituteSuffix(implication.getNext(), node, invocation, replacement));
50+
VCImplication result = copyWithRefinement(implication, implication.getRefinement().clone());
51+
result.setNext(substituteSuffix(implication.getNext(), invocation, replacement));
5152
return result;
5253
}
5354

5455
// preserve the current node and continue rewriting the suffix
55-
VCImplication result = implication.copyWithRefinement(implication.getRefinement().clone());
56+
VCImplication result = copyWithRefinement(implication, implication.getRefinement().clone());
5657
result.setNext(substitute(implication.getNext(), node, invocation, replacement));
5758
return result;
5859
}
5960

6061
/**
6162
* Rewrites every node after the source equality with one function substitution
6263
*/
63-
private VCImplication substituteSuffix(VCImplication implication, VCImplication source,
64-
FunctionInvocation invocation, Expression replacement) {
64+
private VCImplication substituteSuffix(VCImplication implication, FunctionInvocation invocation,
65+
Expression replacement) {
6566
if (implication == null)
6667
return null;
6768

68-
VCImplication result = substituteNode(implication, source, invocation, replacement);
69-
result.setNext(substituteSuffix(implication.getNext(), source, invocation, replacement));
69+
VCImplication result = substituteNode(implication, invocation, replacement);
70+
result.setNext(substituteSuffix(implication.getNext(), invocation, replacement));
7071
return result;
7172
}
7273

7374
/**
74-
* Substitutes one exact function invocation inside one VC node while preserving simplification metadata
75+
* Substitutes one exact function invocation inside one VC node
7576
*/
76-
private VCImplication substituteNode(VCImplication implication, VCImplication source, FunctionInvocation invocation,
77+
private VCImplication substituteNode(VCImplication implication, FunctionInvocation invocation,
7778
Expression replacement) {
7879
Expression expression = implication.getRefinement().getExpression().clone();
7980
if (!containsExpression(expression, invocation))
80-
return implication.copyWithRefinement(new Predicate(expression));
81+
return copyWithRefinement(implication, new Predicate(expression));
8182

8283
Expression substituted = expression.substitute(invocation, replacement.clone());
83-
return new SimplifiedVCImplication(implication, new Predicate(substituted), source);
84+
return copyWithRefinement(implication, new Predicate(substituted));
8485
}
8586

8687
/**

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

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,63 +13,56 @@ class VCFunctionSubstitutionTest {
1313
void substitutesExactFunctionInvocationIntoSuffix() {
1414
VCImplication implication = vc("f(x) == 0", "f(y) == f(x) + 1");
1515

16-
assertSimplificationSteps(substitution::apply, implication,
17-
chain(expect("f(x) == 0"), expect("f(y) == 0 + 1", "f(x) == 0")));
16+
assertSimplificationSteps(substitution::apply, implication, step("f(x) == 0", "f(y) == 0 + 1"));
1817
}
1918

2019
@Test
2120
void substitutesReverseFunctionEquality() {
2221
VCImplication implication = vc("0 == f(x)", "f(y) == f(x) + 1");
2322

24-
assertSimplificationSteps(substitution::apply, implication,
25-
chain(expect("0 == f(x)"), expect("f(y) == 0 + 1", "0 == f(x)")));
23+
assertSimplificationSteps(substitution::apply, implication, step("0 == f(x)", "f(y) == 0 + 1"));
2624
}
2725

2826
@Test
2927
void preservesSourceNode() {
3028
VCImplication implication = vc("f(x) == 0", "f(x) > -1");
3129

32-
assertSimplificationSteps(substitution::apply, implication,
33-
chain(expect("f(x) == 0"), expect("0 > -1", "f(x) == 0")));
30+
assertSimplificationSteps(substitution::apply, implication, step("f(x) == 0", "0 > -1"));
3431
}
3532

3633
@Test
3734
void doesNotRewriteEarlierNodesFromLaterEquality() {
3835
VCImplication implication = vc("f(x) > 0", "f(x) == 1");
3936

40-
assertSimplificationSteps(substitution::apply, implication, chain(expect("f(x) > 0"), expect("f(x) == 1")));
37+
assertSimplificationSteps(substitution::apply, implication, step("f(x) > 0", "f(x) == 1"));
4138
}
4239

4340
@Test
4441
void skipsUsedUpEqualityAndUsesNextAvailableEquality() {
4542
VCImplication implication = vc("f(x) == 0", "f(y) == f(x) + 1", "f(y) == 1");
4643

47-
assertSimplificationSteps(substitution::apply, implication,
48-
chain(expect("f(x) == 0"), expect("f(y) == 0 + 1", "f(x) == 0"), expect("f(y) == 1")),
49-
chain(expect("f(x) == 0"), expect("f(y) == 0 + 1", "f(x) == 0"),
50-
expect("0 + 1 == 1", "f(y) == 0 + 1")));
44+
assertSimplificationSteps(substitution::apply, implication, step("f(x) == 0", "f(y) == 0 + 1", "f(y) == 1"),
45+
step("f(x) == 0", "f(y) == 0 + 1", "0 + 1 == 1"));
5146
}
5247

5348
@Test
5449
void doesNotGeneralizeAcrossDifferentArguments() {
5550
VCImplication implication = vc("f(x) == 0", "f(y) == 0");
5651

57-
assertSimplificationSteps(substitution::apply, implication, chain(expect("f(x) == 0"), expect("f(y) == 0")));
52+
assertSimplificationSteps(substitution::apply, implication, step("f(x) == 0", "f(y) == 0"));
5853
}
5954

6055
@Test
6156
void ignoresRecursiveFunctionEquality() {
6257
VCImplication implication = vc("f(x) == f(x) + 1", "f(x) > 0");
6358

64-
assertSimplificationSteps(substitution::apply, implication,
65-
chain(expect("f(x) == f(x) + 1"), expect("f(x) > 0")));
59+
assertSimplificationSteps(substitution::apply, implication, step("f(x) == f(x) + 1", "f(x) > 0"));
6660
}
6761

6862
@Test
6963
void extractsEqualityFromTopLevelConjunction() {
7064
VCImplication implication = vc("ok && f(x) == 0", "f(y) == f(x) + 1");
7165

72-
assertSimplificationSteps(substitution::apply, implication,
73-
chain(expect("ok && f(x) == 0"), expect("f(y) == 0 + 1", "ok && f(x) == 0")));
66+
assertSimplificationSteps(substitution::apply, implication, step("ok && f(x) == 0", "f(y) == 0 + 1"));
7467
}
7568
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import com.pholser.junit.quickcheck.runner.JUnitQuickcheck;
1212
import liquidjava.processor.VCImplication;
1313
import liquidjava.processor.context.Context;
14+
import liquidjava.processor.context.GhostFunction;
1415
import liquidjava.rj_language.Predicate;
1516
import liquidjava.rj_language.ast.BinaryExpression;
1617
import liquidjava.rj_language.ast.Expression;
@@ -19,12 +20,15 @@
1920
import liquidjava.smt.SMTResult;
2021
import liquidjava.utils.TestUtils;
2122
import org.junit.runner.RunWith;
23+
import spoon.Launcher;
24+
import spoon.reflect.factory.Factory;
2225

2326
@RunWith(JUnitQuickcheck.class)
2427
public class VCSimplificationPropertyBasedTest {
2528

2629
private static final int TRIALS = 50; // number of random VCs to test
2730
private static final int MAX_STEPS = 20; // to prevent infinite loops in case of non-termination
31+
private static final Factory FACTORY = new Launcher().getFactory();
2832

2933
@Property(trials = TRIALS)
3034
public void eachSimplificationStepPreservesVcSemantics(@From(VCImplicationGenerator.class) VCImplication vc) {
@@ -50,6 +54,9 @@ private static void setUpContext() {
5054
TestUtils.addIntVariableToContext(variable);
5155
for (String variable : VCImplicationGenerator.FREE_VARS)
5256
TestUtils.addIntVariableToContext(variable);
57+
for (String function : VCImplicationGenerator.FUNCTIONS)
58+
Context.getInstance().addGhostFunction(
59+
new GhostFunction(function, List.of("int"), FACTORY.Type().INTEGER_PRIMITIVE, FACTORY, ""));
5360
}
5461

5562
private static void assertEquivalent(VCImplication unsimplified, VCImplication simplified, int step) {

0 commit comments

Comments
 (0)