Skip to content

Commit f7adec3

Browse files
Add -a/--all flag to show all SMT verification conditions
1 parent 3ac0f36 commit f7adec3

4 files changed

Lines changed: 62 additions & 10 deletions

File tree

liquidjava-verifier/src/main/java/liquidjava/api/CommandLineArgs.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ public class CommandLineArgs {
2222
@Option(names = { "-d", "--debug" }, description = "Enable debug mode for more detailed output")
2323
public boolean debugMode;
2424

25+
@Option(names = { "-a", "--all" }, description = "Show every verification condition sent to the SMT solver")
26+
public boolean showAllVCs;
27+
2528
@Option(names = { "-lsp", "--language-server" }, description = "Enable language server mode for editor support")
2629
public boolean lspMode;
2730

liquidjava-verifier/src/main/java/liquidjava/diagnostics/DebugLog.java

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,56 @@ public static boolean enabled() {
3737
return CommandLineLauncher.cmdArgs.debugMode;
3838
}
3939

40+
/**
41+
* Gate for the SMT-query trace (verification conditions fed to Z3 and their outcomes). Enabled by either
42+
* {@code --debug} / {@code -d} or the lighter {@code --all} / {@code -a}, which shows every query without the rest
43+
* of the debug output (e.g. simplification passes).
44+
*/
45+
public static boolean smtEnabled() {
46+
return CommandLineLauncher.cmdArgs.debugMode || CommandLineLauncher.cmdArgs.showAllVCs;
47+
}
48+
49+
/**
50+
* Set by {@link #smtStart} (the structured / flat VC printers) and consumed by {@link #smtRawQuery}. Lets the
51+
* low-level Z3 boundary trace skip a query that a higher layer already printed in full, so {@code -a} shows every
52+
* query exactly once. Single-threaded: each {@code smtStart} is immediately followed by one {@code solver.check()}.
53+
*/
54+
private static boolean structuredQueryPending = false;
55+
56+
/**
57+
* Catch-all trace emitted at the actual {@code solver.check()} boundary so {@code -a} / {@code -d} show EVERY query
58+
* sent to Z3 — including those that bypass the structured {@link #smtStart} path (the simplifier's implication
59+
* checks, refinement satisfiability checks, speculative typestate checks). Suppressed for queries a structured
60+
* print already covered, to avoid duplication.
61+
*
62+
* @param sent
63+
* the predicate actually handed to Z3
64+
* @param result
65+
* the raw Z3 {@code Status}
66+
*/
67+
public static void smtRawQuery(Predicate sent, String result) {
68+
if (!smtEnabled()) {
69+
return;
70+
}
71+
if (structuredQueryPending) {
72+
structuredQueryPending = false; // already shown by the structured print that preceded this check
73+
return;
74+
}
75+
List<Expression> conjuncts = new ArrayList<>();
76+
flattenConjunction(sent.getExpression(), conjuncts);
77+
System.out.println(SMT_TAG + " " + Colors.GREY + "query → Z3" + Colors.RESET);
78+
for (Expression c : conjuncts) {
79+
System.out.println(SMT_TAG + " " + c);
80+
}
81+
System.out.println(SMT_TAG + " Result: " + Colors.CYAN + result + Colors.RESET);
82+
}
83+
4084
/**
4185
* One-line header for a verification check: emits the absolute file path + line so terminals (iTerm2, VS Code,
4286
* WezTerm, …) make it ⌘/Ctrl-clickable. Replaces the older two-line {@code info()} prints.
4387
*/
4488
public static void smtVerifying(SourcePosition position) {
45-
if (!enabled() || position == null) {
89+
if (!smtEnabled() || position == null) {
4690
return;
4791
}
4892
String where = position.getFile().getAbsolutePath() + ":" + position.getLine();
@@ -59,9 +103,10 @@ public static void smtVerifying(SourcePosition position) {
59103
* points that don't carry the structured per-variable {@link VCImplication} chain (e.g. ExpressionSimplifier).
60104
*/
61105
public static void smtStart(Predicate premises, Predicate conclusion) {
62-
if (!enabled()) {
106+
if (!smtEnabled()) {
63107
return;
64108
}
109+
structuredQueryPending = true;
65110
List<Expression> conjuncts = new ArrayList<>();
66111
flattenConjunction(premises.getExpression(), conjuncts);
67112
System.out.println(SMT_TAG);
@@ -85,9 +130,10 @@ public static void smtStart(VCImplication chain, Predicate conclusion) {
85130
* {@code verifySMTSubtypeStates}).
86131
*/
87132
public static void smtStart(VCImplication chain, Predicate extraPremise, Predicate conclusion) {
88-
if (!enabled()) {
133+
if (!smtEnabled()) {
89134
return;
90135
}
136+
structuredQueryPending = true;
91137
// Pre-compute label widths for column alignment across all printed rows.
92138
int labelWidth = 0;
93139
for (VCImplication node = chain; node != null; node = node.getNext()) {
@@ -362,14 +408,14 @@ private static void flattenConjunction(Expression e, List<Expression> out) {
362408
}
363409

364410
public static void smtUnsat() {
365-
if (!enabled()) {
411+
if (!smtEnabled()) {
366412
return;
367413
}
368414
System.out.println(SMT_TAG + " Result: " + Colors.GREEN + "UNSAT (subtype holds)" + Colors.RESET);
369415
}
370416

371417
public static void smtSat(Object counterexample) {
372-
if (!enabled()) {
418+
if (!smtEnabled()) {
373419
return;
374420
}
375421
String header = SMT_TAG + " Result: " + Colors.RED + "SAT (subtype fails)" + Colors.RESET;
@@ -413,7 +459,7 @@ private static String formatCounterexample(Object counterexample) {
413459
}
414460

415461
public static void smtUnknown() {
416-
if (!enabled()) {
462+
if (!smtEnabled()) {
417463
return;
418464
}
419465
System.out.println(SMT_TAG + " Result: " + Colors.YELLOW + "UNKNOWN (treated as OK)" + Colors.RESET);
@@ -424,7 +470,7 @@ public static void smtUnknown() {
424470
* print). {@link liquidjava.smt.SMTResult} doesn't preserve UNKNOWN, so this maps OK → UNSAT and ERROR → SAT.
425471
*/
426472
public static void smtResult(liquidjava.smt.SMTResult result) {
427-
if (!enabled()) {
473+
if (!smtEnabled()) {
428474
return;
429475
}
430476
if (result.isError()) {
@@ -439,7 +485,7 @@ public static void smtResult(liquidjava.smt.SMTResult result) {
439485
* still responsible for surfacing the user-facing error.
440486
*/
441487
public static void smtError(String message) {
442-
if (!enabled()) {
488+
if (!smtEnabled()) {
443489
return;
444490
}
445491
System.out.println(SMT_TAG + " Result: " + Colors.RED + "ERROR" + Colors.RESET + " — "

liquidjava-verifier/src/main/java/liquidjava/processor/refinement_checker/VCChecker.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ private List<GhostState> filterGhostStatesForVariables(List<GhostState> list, Li
233233
* chain in place; safe because {@code joinPredicates} returns a clone.
234234
*/
235235
private void transformChainForDebug(VCImplication chain, List<GhostState> filtered, String[] s, Factory f) {
236-
if (!DebugLog.enabled())
236+
if (!DebugLog.smtEnabled())
237237
return;
238238
for (VCImplication n = chain; n != null; n = n.getNext()) {
239239
if (n.getRefinement() == null)

liquidjava-verifier/src/main/java/liquidjava/smt/SMTEvaluator.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public SMTResult verifySubtype(Predicate subRef, Predicate supRef, Context conte
4141
Expr<?> e = exp.accept(visitor);
4242
Solver solver = tz3.makeSolverForExpression(e);
4343
Status result = solver.check();
44+
DebugLog.smtRawQuery(toVerify, result.toString());
4445

4546
// subRef is not a subtype of supRef
4647
if (result.equals(Status.SATISFIABLE)) {
@@ -75,7 +76,9 @@ public boolean isUnsatisfiable(Predicate predicate, Context context) throws Exce
7576
ExpressionToZ3Visitor visitor = new ExpressionToZ3Visitor(tz3);
7677
Expr<?> e = exp.accept(visitor);
7778
Solver solver = tz3.makeSolverForExpression(e);
78-
return solver.check().equals(Status.UNSATISFIABLE);
79+
Status result = solver.check();
80+
DebugLog.smtRawQuery(predicate, result.toString());
81+
return result.equals(Status.UNSATISFIABLE);
7982
}
8083
} catch (Z3Exception e) {
8184
throw new Z3Exception(e.getLocalizedMessage());

0 commit comments

Comments
 (0)