1515import com .microsoft .z3 .Model ;
1616
1717import java .util .ArrayList ;
18+ import java .util .Arrays ;
1819import java .util .HashMap ;
1920import java .util .List ;
2021import java .util .Map ;
22+ import java .util .stream .Collectors ;
2123
2224import liquidjava .diagnostics .Counterexample ;
2325import liquidjava .diagnostics .errors .LJError ;
@@ -35,6 +37,8 @@ public class TranslatorToZ3 implements AutoCloseable {
3537 private final Map <String , List <Expr <?>>> varSuperTypes = new HashMap <>();
3638 private final Map <String , AliasWrapper > aliasTranslation = new HashMap <>(); // this is not being used
3739 private final Map <String , FuncDecl <?>> funcTranslation = new HashMap <>();
40+ private final Map <String , Expr <?>> funcAppTranslation = new HashMap <>();
41+ private final Map <Expr <?>, String > exprToNameTranslation = new HashMap <>();
3842
3943 public TranslatorToZ3 (liquidjava .processor .context .Context c ) {
4044 TranslatorContextToZ3 .translateVariables (z3 , c .getContext (), varTranslation );
@@ -56,14 +60,22 @@ public Solver makeSolverForExpression(Expr<?> e) {
5660 */
5761 public Counterexample getCounterexample (Model model ) {
5862 List <String > assignments = new ArrayList <>();
63+ // Extract constant variable assignments
5964 for (FuncDecl <?> decl : model .getDecls ()) {
60- // extract variable assignments with constants
6165 if (decl .getArity () == 0 ) {
6266 String name = decl .getName ().toString ();
6367 String value = model .getConstInterp (decl ).toString ();
64- assignments .add (name + " == " + value );
68+ // Skip opaque Z3 object values
69+ if (!value .contains ("!val!" ))
70+ assignments .add (name + " == " + value );
6571 }
66- // TODO: extract function assignments (arity > 0)?
72+ }
73+ // Extract function application values
74+ for (Map .Entry <String , Expr <?>> entry : funcAppTranslation .entrySet ()) {
75+ String label = entry .getKey ();
76+ Expr <?> application = entry .getValue ();
77+ Expr <?> value = model .eval (application , true );
78+ assignments .add (label + " = " + value );
6779 }
6880 return new Counterexample (assignments );
6981 }
@@ -101,7 +113,9 @@ private Expr<?> getVariableTranslation(String name) throws LJError {
101113 }
102114
103115 public Expr <?> makeVariable (String name ) throws LJError {
104- return getVariableTranslation (name ); // int[] not in varTranslation
116+ Expr <?> expr = getVariableTranslation (name ); // int[] not in varTranslation
117+ exprToNameTranslation .put (expr , name ); // Track for readable labels
118+ return expr ;
105119 }
106120
107121 public Expr <?> makeFunctionInvocation (String name , Expr <?>[] params ) throws LJError {
@@ -111,7 +125,7 @@ public Expr<?> makeFunctionInvocation(String name, Expr<?>[] params) throws LJEr
111125 return makeSelect (params );
112126 FuncDecl <?> fd = funcTranslation .get (name );
113127 if (fd == null )
114- fd = resolveFunctionDeclFallback (name , params );
128+ fd = resolveFunctionDecl (name , params );
115129
116130 Sort [] s = fd .getDomain ();
117131 for (int i = 0 ; i < s .length ; i ++) {
@@ -125,15 +139,18 @@ public Expr<?> makeFunctionInvocation(String name, Expr<?>[] params) throws LJEr
125139 params [i ] = e ;
126140 }
127141 }
128- return z3 .mkApp (fd , params );
142+ String label = buildFunctionLabel (name , params );
143+ Expr <?> app = z3 .mkApp (fd , params );
144+ funcAppTranslation .put (label , app );
145+ return app ;
129146 }
130147
131148 /**
132- * Fallback resolver for function declarations when an exact qualified name lookup fails. Tries to match by simple
149+ * Gets function declarations when an exact qualified name lookup fails. Tries to match by simple
133150 * name and number of parameters, preferring an exact qualified-name match if found among candidates; otherwise
134151 * returns the first compatible candidate and relies on later coercion via var supertypes.
135152 */
136- private FuncDecl <?> resolveFunctionDeclFallback (String name , Expr <?>[] params ) throws LJError {
153+ private FuncDecl <?> resolveFunctionDecl (String name , Expr <?>[] params ) throws LJError {
137154 String simple = Utils .getSimpleName (name );
138155 FuncDecl <?> candidate = null ;
139156 for (Map .Entry <String , FuncDecl <?>> entry : funcTranslation .entrySet ()) {
@@ -330,6 +347,13 @@ public Expr<?> makeIte(Expr<?> c, Expr<?> t, Expr<?> e) {
330347 throw new RuntimeException ("Condition is not a boolean expression" );
331348 }
332349
350+ private String buildFunctionLabel (String functionName , Expr <?>[] params ) {
351+ String simpleName = Utils .getSimpleName (functionName );
352+ String argsString = Arrays .stream (params ).map (p -> exprToNameTranslation .getOrDefault (p , p .toString ()))
353+ .collect (Collectors .joining (", " ));
354+ return simpleName + "(" + argsString + ")" ;
355+ }
356+
333357 @ Override
334358 public void close () throws Exception {
335359 z3 .close ();
0 commit comments