|
16 | 16 |
|
17 | 17 | import com.google.common.collect.ImmutableList; |
18 | 18 | import com.google.common.collect.ImmutableSet; |
| 19 | +import com.google.common.collect.ImmutableSortedSet; |
19 | 20 | import com.google.common.collect.Iterables; |
20 | 21 | import com.google.common.collect.Streams; |
21 | 22 | import com.microsoft.z3.ArithExpr; |
@@ -83,6 +84,7 @@ final class CelAstToZ3Translator { |
83 | 84 | private static final String EMPTY_MSG_REF_PREFIX = "!empty_msg_ref_"; |
84 | 85 | private static final String EMPTY_LIST_PREFIX = "!empty_list"; |
85 | 86 | private static final String EMPTY_MAP_PREFIX = "!empty_map"; |
| 87 | + private static final String FUNCTION_PREFIX = "!fn_"; |
86 | 88 | private static final String NULL_VALUE_FIELD = "null_value"; |
87 | 89 | private static final String SECONDS_FIELD = "seconds"; |
88 | 90 | private static final String NANOS_FIELD = "nanos"; |
@@ -927,21 +929,40 @@ private TranslatedValue translateCall(CelExpr expr, CelAbstractSyntaxTree ast) { |
927 | 929 | Sort[] argSorts = new Sort[args.size()]; |
928 | 930 | Arrays.fill(argSorts, 0, args.size(), typeSystem.celValueSort()); |
929 | 931 | FuncDecl<?> funcDecl = |
930 | | - typeSystem.internFuncDecl(functionName, argSorts, typeSystem.celValueSort()); |
| 932 | + typeSystem.internFuncDecl( |
| 933 | + uninterpretedFunctionSymbol(exprId, ast), |
| 934 | + argSorts, |
| 935 | + typeSystem.celValueSort()); |
931 | 936 |
|
932 | 937 | Expr<?>[] exprArgs = args.stream().map(TranslatedValue::z3Expr).toArray(Expr[]::new); |
933 | 938 | Expr<?> callRes = ctx.mkApp(funcDecl, exprArgs); |
934 | 939 | typeConstraints.add(createTypeConstraint(callRes, exprId, ast)); |
935 | 940 | typeConstraints.add(ctx.mkNot(typeSystem.isUnknown(callRes))); |
936 | 941 | typeConstraints.add(ctx.mkNot(typeSystem.isError(callRes))); |
937 | 942 |
|
938 | | - boolean isDynamic = ast.getTypeOrThrow(exprId).equals(SimpleType.DYN); |
939 | | - BoolExpr isApprox = ctx.mkBool(!isDynamic); |
| 943 | + // The solver picks the result freely, so a model depending on it is never exact. |
940 | 944 | return TranslatedValue.propagateStrict( |
941 | | - ctx, typeSystem, functionName, callRes, Optional.of(expr), isApprox, args); |
| 945 | + ctx, |
| 946 | + typeSystem, |
| 947 | + functionName, |
| 948 | + callRes, |
| 949 | + Optional.of(expr), |
| 950 | + /* baseTaint= */ ctx.mkTrue(), |
| 951 | + args); |
942 | 952 | }); |
943 | 953 | } |
944 | 954 |
|
| 955 | + /** |
| 956 | + * Returns the Z3 symbol for an uninterpreted call. Each set of candidate overloads gets its own |
| 957 | + * symbol, since distinct overloads may have different implementations even on equal values (e.g. |
| 958 | + * empty lists of different element types). The prefix keeps it apart from variables and internal |
| 959 | + * symbols. |
| 960 | + */ |
| 961 | + private static String uninterpretedFunctionSymbol(long exprId, CelAbstractSyntaxTree ast) { |
| 962 | + ImmutableList<String> overloadIds = ast.getReferenceOrThrow(exprId).overloadIds(); |
| 963 | + return FUNCTION_PREFIX + String.join("|", ImmutableSortedSet.copyOf(overloadIds)); |
| 964 | + } |
| 965 | + |
945 | 966 | /** |
946 | 967 | * Whether a call may construct a container that embeds its args (e.g. list concatenation, map |
947 | 968 | * insertion or optional.of). Indexing and conditionals return existing values instead, so |
|
0 commit comments