Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package liquidjava.diagnostics.errors;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import liquidjava.diagnostics.TranslationTable;
import liquidjava.processor.VCImplication;
import liquidjava.rj_language.Predicate;
import liquidjava.rj_language.ast.Expression;
import liquidjava.rj_language.ast.formatter.VariableFormatter;
Expand Down Expand Up @@ -38,38 +37,33 @@ public RefinementError(SourcePosition position, Predicate expected, VCSimplifica

@Override
public String getDetails() {
String counterexampleString = getCounterExampleString();
if (counterexampleString == null)
Counterexample counterexamples = getCounterExamples();
if (counterexamples == null)
return "";

String counterexampleString = counterexamples.assignments().stream()
.map(a -> VariableFormatter.format(a.first()) + " == " + a.second())
.collect(Collectors.joining(" && "));
return "Counterexample: " + counterexampleString;
}

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

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

if (counterexampleString.isEmpty())
if (assignments.isEmpty())
return null;

return counterexampleString;
return new Counterexample(assignments);
}

public Counterexample getCounterexample() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package liquidjava.rj_language.opt;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import liquidjava.processor.VCImplication;
Expand Down Expand Up @@ -35,6 +37,17 @@ public VCSimplificationResult getOrigin() {
return origin;
}

/**
* Returns the list of binder names in the simplified VC chain in order of appearance
*/
public List<String> getBinders() {
ArrayList<String> binderNames = new ArrayList<>();
for (VCImplication current = getImplication(); current != null; current = current.getNext())
if (current.hasBinder())
binderNames.add(current.getName());
return binderNames;
}

@Override
public String toString() {
if (origin == null)
Expand Down
Loading