@@ -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 + " — "
0 commit comments