diff --git a/liquidjava-verifier/src/main/java/liquidjava/processor/refinement_checker/VCChecker.java b/liquidjava-verifier/src/main/java/liquidjava/processor/refinement_checker/VCChecker.java index d01b03e5..39a155d3 100644 --- a/liquidjava-verifier/src/main/java/liquidjava/processor/refinement_checker/VCChecker.java +++ b/liquidjava-verifier/src/main/java/liquidjava/processor/refinement_checker/VCChecker.java @@ -374,23 +374,45 @@ private boolean hasVariable(Expression exp, String var) { // Errors--------------------------------------------------------------------------------------------------- + /** + * Builds the {@link VCImplication} premise chain that backs an error message. Every refined variable named in + * {@code predicates} — and, transitively, the path variables those drag in — is gathered, and their refinements are + * joined into a chain. + * + *

+ * Callers pass every predicate that should contribute variables, not just one: a bare predicate such as + * {@code true} carries no variable names and would gather nothing on its own, leaving the chain (and the displayed + * premises) empty. Passing both the {@code found} and {@code expected} refinements ensures the variable that is + * only named on one side still seeds the chain. + * + * @param map + * translation table populated, as a side effect, with the gathered variables' code placements + * @param predicates + * predicates whose variables seed the chain; {@code predicates[0]} is also passed to + * {@code joinPredicates} + * + * @return the joined premise chain + */ + private VCImplication buildPremiseChain(TranslationTable map, Predicate... predicates) { + List lrv = new ArrayList<>(), mainVars = new ArrayList<>(); + for (Predicate p : predicates) { + gatherVariables(p, lrv, mainVars); + } + return joinPredicates(predicates[0], mainVars, lrv, map); + } + protected void throwRefinementError(SourcePosition position, Predicate expected, Predicate found, Counterexample counterexample, String customMessage) throws RefinementError { - List lrv = new ArrayList<>(), mainVars = new ArrayList<>(); - gatherVariables(expected, lrv, mainVars); - gatherVariables(found, lrv, mainVars); TranslationTable map = new TranslationTable(); - Predicate premises = joinPredicates(expected, mainVars, lrv, map).toConjunctions(); + Predicate premises = buildPremiseChain(map, expected, found).toConjunctions(); throw new RefinementError(position, expected.simplify(context), premises.simplify(context), map, counterexample, customMessage); } protected void throwStateRefinementError(SourcePosition position, Predicate found, Predicate expected, String customMessage) throws StateRefinementError { - List lrv = new ArrayList<>(), mainVars = new ArrayList<>(); - gatherVariables(found, lrv, mainVars); TranslationTable map = new TranslationTable(); - VCImplication foundState = joinPredicates(found, mainVars, lrv, map); + VCImplication foundState = buildPremiseChain(map, expected, found); throw new StateRefinementError(position, expected.simplify(context), foundState.toConjunctions().simplify(context), map, customMessage); } @@ -401,10 +423,8 @@ protected void throwStateConflictError(SourcePosition position, Predicate expect } private TranslationTable createMap(Predicate expectedType) { - List lrv = new ArrayList<>(), mainVars = new ArrayList<>(); - gatherVariables(expectedType, lrv, mainVars); TranslationTable map = new TranslationTable(); - joinPredicates(expectedType, mainVars, lrv, map); + buildPremiseChain(map, expectedType); return map; }