|
1 | 1 | package liquidjava.rj_language.opt; |
2 | 2 |
|
| 3 | +import static liquidjava.rj_language.opt.VCSimplificationUtils.isTrue; |
| 4 | +import static liquidjava.rj_language.opt.VCSimplificationUtils.linkedConjuncts; |
| 5 | +import static liquidjava.rj_language.opt.VCSimplificationUtils.splitConjuncts; |
| 6 | +import static liquidjava.rj_language.opt.VCSimplificationUtils.termsOf; |
| 7 | +import static liquidjava.rj_language.opt.VCSimplificationUtils.valueVariablesOf; |
| 8 | + |
| 9 | +import java.util.ArrayList; |
3 | 10 | import java.util.HashSet; |
| 11 | +import java.util.List; |
4 | 12 | import java.util.Set; |
5 | 13 |
|
| 14 | +import liquidjava.processor.VCImplication; |
6 | 15 | import liquidjava.rj_language.Predicate; |
7 | | -import liquidjava.smt.Counterexample; |
8 | | -import liquidjava.utils.Pair; |
| 16 | +import liquidjava.rj_language.ast.Expression; |
9 | 17 |
|
10 | 18 | /** |
11 | | - * Variables that a simplified VC chain must keep a binder for even when the binder only says {@code true}: those of the |
12 | | - * expected refinement, and those that the counterexample gives a value |
| 19 | + * Decides which binders refined only by {@code true} a simplified VC chain keeps for an error. Such a binder states no |
| 20 | + * fact, so it is kept only when a fact linked to the expected refinement (sharing a term with it, directly or through |
| 21 | + * other facts) constrains its variable's value, or, when the error shows a counterexample, when expected itself |
| 22 | + * constrains its value, so that the counterexample can show it |
| 23 | + * |
| 24 | + * @param expectedTerms |
| 25 | + * variables and ghost applications of the expected refinement |
| 26 | + * @param expectedValues |
| 27 | + * variables whose value the expected refinement constrains |
| 28 | + * @param keepExpected |
| 29 | + * whether the binders of expectedValues are kept for that alone |
13 | 30 | */ |
14 | | -public record NeededVariables(Set<String> expected, Set<String> assigned) { |
| 31 | +public record NeededVariables(Set<String> expectedTerms, Set<String> expectedValues, boolean keepExpected) { |
15 | 32 |
|
16 | | - public static final NeededVariables NONE = new NeededVariables(Set.of(), Set.of()); |
| 33 | + public static final NeededVariables NONE = new NeededVariables(Set.of(), Set.of(), false); |
17 | 34 |
|
18 | 35 | public NeededVariables { |
19 | | - expected = Set.copyOf(expected); |
20 | | - assigned = Set.copyOf(assigned); |
| 36 | + expectedTerms = Set.copyOf(expectedTerms); |
| 37 | + expectedValues = Set.copyOf(expectedValues); |
| 38 | + } |
| 39 | + |
| 40 | + /** |
| 41 | + * For a refinement error, whose counterexample lists the values of the binders |
| 42 | + */ |
| 43 | + public static NeededVariables forRefinementError(Predicate expected) { |
| 44 | + return of(expected, true); |
21 | 45 | } |
22 | 46 |
|
23 | | - public static NeededVariables of(Predicate expected, Counterexample counterexample) { |
24 | | - Set<String> expectedNames = expected == null ? Set.of() : new HashSet<>(expected.getVariableNames()); |
25 | | - Set<String> assignedNames = new HashSet<>(); |
26 | | - if (counterexample != null) |
27 | | - counterexample.assignments().stream().map(Pair::first).forEach(assignedNames::add); |
28 | | - return new NeededVariables(expectedNames, assignedNames); |
| 47 | + /** |
| 48 | + * For a state refinement error, which has no counterexample |
| 49 | + */ |
| 50 | + public static NeededVariables forStateError(Predicate expected) { |
| 51 | + return of(expected, false); |
| 52 | + } |
| 53 | + |
| 54 | + private static NeededVariables of(Predicate expected, boolean keepExpected) { |
| 55 | + if (expected == null) |
| 56 | + return new NeededVariables(Set.of(), Set.of(), keepExpected); |
| 57 | + return new NeededVariables(new HashSet<>(termsOf(expected.getExpression())), |
| 58 | + new HashSet<>(valueVariablesOf(expected.getExpression())), keepExpected); |
29 | 59 | } |
30 | 60 |
|
31 | 61 | /** |
32 | | - * Whether a binder refined only by {@code true} must stay: the expected refinement is about its variable, or a |
33 | | - * later implication uses it and the counterexample has a value for it |
| 62 | + * Variables whose binder refined only by true the chain keeps: those whose own value a fact linked to expected |
| 63 | + * constrains. A variable named only as the object of a ghost or state application ({@code x} in |
| 64 | + * {@code b == size(x)}) has no value of its own there, so its row would say nothing |
34 | 65 | */ |
35 | | - public boolean needsTrueBinder(String name, boolean usedDownstream) { |
36 | | - return expected.contains(name) || usedDownstream && assigned.contains(name); |
| 66 | + public Set<String> trueBindersToKeep(VCImplication chain) { |
| 67 | + List<Expression> facts = new ArrayList<>(); |
| 68 | + for (VCImplication current = chain; current != null; current = current.getNext()) |
| 69 | + if (!isTrue(current.getRefinement().getExpression())) |
| 70 | + facts.addAll(splitConjuncts(current.getRefinement().getExpression())); |
| 71 | + |
| 72 | + Set<String> keep = new HashSet<>(keepExpected ? expectedValues : Set.of()); |
| 73 | + for (Expression fact : linkedConjuncts(facts, VCSimplificationUtils::termsOf, expectedTerms)) |
| 74 | + for (String name : valueVariablesOf(fact)) |
| 75 | + if (!expectedTerms.contains(name)) |
| 76 | + keep.add(name); |
| 77 | + return keep; |
37 | 78 | } |
38 | 79 | } |
0 commit comments