Skip to content

Commit cbfc085

Browse files
committed
Filter & Sort Counterexamples by Binders
1 parent 850ffbf commit cbfc085

2 files changed

Lines changed: 27 additions & 23 deletions

File tree

liquidjava-verifier/src/main/java/liquidjava/diagnostics/errors/RefinementError.java

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import liquidjava.diagnostics.TranslationTable;
88
import liquidjava.processor.VCImplication;
99
import liquidjava.rj_language.Predicate;
10-
import liquidjava.rj_language.ast.Expression;
1110
import liquidjava.rj_language.ast.formatter.VariableFormatter;
1211
import liquidjava.rj_language.opt.VCSimplificationResult;
1312
import liquidjava.smt.Counterexample;
@@ -38,38 +37,30 @@ public RefinementError(SourcePosition position, Predicate expected, VCSimplifica
3837

3938
@Override
4039
public String getDetails() {
41-
String counterexampleString = getCounterExampleString();
42-
if (counterexampleString == null)
40+
Counterexample counterexamples = getCounterExamples();
41+
if (counterexamples == null)
4342
return "";
43+
44+
String counterexampleString = counterexamples.assignments().stream()
45+
.map(a -> VariableFormatter.format(a.first()) + " == " + a.second())
46+
.collect(Collectors.joining(" && "));
4447
return "Counterexample: " + counterexampleString;
4548
}
4649

47-
public String getCounterExampleString() {
50+
// Filters counterexample assignments only in found VC and sorts them in the order of its binders
51+
public Counterexample getCounterExamples() {
4852
if (counterexample == null || counterexample.assignments().isEmpty())
4953
return null;
5054

51-
List<String> foundVarNames = new ArrayList<>();
52-
Expression foundExpression = getFound().getImplication().toPredicate().getExpression();
53-
Expression expectedExpression = expected.getExpression();
54-
foundExpression.getVariableNames(foundVarNames);
55-
// also keep resolved static-final constants (e.g. Integer.MAX_VALUE) referenced by either side of the
56-
// subtyping check, so the counterexample maps the symbolic name back to its compile-time value
57-
foundExpression.getResolvedConstantNames(foundVarNames);
58-
expectedExpression.getResolvedConstantNames(foundVarNames);
59-
List<String> foundAssignments = foundExpression.getConjuncts().stream().map(Expression::toString).toList();
60-
String counterexampleString = counterexample.assignments().stream()
61-
// only include variables that appear in the found value and are not already fixed there
62-
.filter(a -> foundVarNames.contains(a.first())
63-
&& !foundAssignments.contains(a.first() + " == " + a.second()))
64-
// format as "var == value"
65-
.map(a -> VariableFormatter.format(a.first()) + " == " + a.second())
66-
// join with "&&"
67-
.collect(Collectors.joining(" && "));
55+
List<String> binderNames = getFound().getBinders();
56+
var assignments = counterexample.assignments().stream().filter(a -> binderNames.contains(a.first()))
57+
.sorted((a, b) -> Integer.compare(binderNames.indexOf(a.first()), binderNames.indexOf(b.first())))
58+
.toList();
6859

69-
if (counterexampleString.isEmpty())
60+
if (assignments.isEmpty())
7061
return null;
7162

72-
return counterexampleString;
63+
return new Counterexample(assignments);
7364
}
7465

7566
public Counterexample getCounterexample() {

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

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

3+
import java.util.ArrayList;
4+
import java.util.List;
35
import java.util.Objects;
46

57
import liquidjava.processor.VCImplication;
@@ -46,6 +48,17 @@ public String getSimplification() {
4648
return simplification;
4749
}
4850

51+
/**
52+
* Returns the list of binder names in the simplified VC chain in order of appearance
53+
*/
54+
public List<String> getBinders() {
55+
ArrayList<String> binderNames = new ArrayList<>();
56+
for (VCImplication current = getImplication(); current != null; current = current.getNext())
57+
if (current.hasBinder())
58+
binderNames.add(current.getName());
59+
return binderNames;
60+
}
61+
4962
@Override
5063
public String toString() {
5164
if (origin == null)

0 commit comments

Comments
 (0)