1919import com .google .common .collect .ImmutableList ;
2020import com .microsoft .z3 .BoolExpr ;
2121import com .microsoft .z3 .Expr ;
22+ import com .microsoft .z3 .FPExpr ;
2223import com .microsoft .z3 .FuncDecl ;
2324import com .microsoft .z3 .IntExpr ;
2425import com .microsoft .z3 .Sort ;
2526import dev .cel .checker .CelStandardDeclarations .StandardFunction ;
2627import dev .cel .checker .CelStandardDeclarations .StandardFunction .Overload .Conversions ;
28+ import dev .cel .common .types .SimpleType ;
2729import java .util .Optional ;
2830
2931/** Axiomatization for CEL's type conversion functions. */
@@ -42,14 +44,12 @@ final class TypeConversionAxioms {
4244 return Optional .of (
4345 typeSystem .withRuntimeError (typeSystem .wrapInt (uintVal ), outOfBounds ));
4446 })
45- .addUnaryOverloadTranslator (
47+ .addOverloadTranslator (
4648 Conversions .DOUBLE_TO_INT64 .celOverloadDecl (),
47- createUninterpretedConversion (Conversions .DOUBLE_TO_INT64 ),
48- /* isApproximated= */ true )
49- .addUnaryOverloadTranslator (
49+ createUninterpretedConversion (Conversions .DOUBLE_TO_INT64 ))
50+ .addOverloadTranslator (
5051 Conversions .STRING_TO_INT64 .celOverloadDecl (),
51- createUninterpretedConversion (Conversions .STRING_TO_INT64 ),
52- /* isApproximated= */ true )
52+ createUninterpretedConversion (Conversions .STRING_TO_INT64 ))
5353 .addUnaryOverloadTranslator (
5454 Conversions .TIMESTAMP_TO_INT64 .celOverloadDecl (),
5555 (ctx , typeSystem , sink , arg ) ->
@@ -69,79 +69,66 @@ final class TypeConversionAxioms {
6969 return Optional .of (
7070 typeSystem .withRuntimeError (typeSystem .wrapUint (intVal ), outOfBounds ));
7171 })
72- .addUnaryOverloadTranslator (
72+ .addOverloadTranslator (
7373 Conversions .DOUBLE_TO_UINT64 .celOverloadDecl (),
74- createUninterpretedConversion (Conversions .DOUBLE_TO_UINT64 ),
75- /* isApproximated= */ true )
76- .addUnaryOverloadTranslator (
74+ createUninterpretedConversion (Conversions .DOUBLE_TO_UINT64 ))
75+ .addOverloadTranslator (
7776 Conversions .STRING_TO_UINT64 .celOverloadDecl (),
78- createUninterpretedConversion (Conversions .STRING_TO_UINT64 ),
79- /* isApproximated= */ true )
77+ createUninterpretedConversion (Conversions .STRING_TO_UINT64 ))
8078 .build ();
8179
8280 private static final CelZ3FunctionAxiom DOUBLE_AXIOM =
8381 CelZ3FunctionAxiom .newBuilder (StandardFunction .DOUBLE .functionDecl ())
8482 .addUnaryOverloadTranslator (
8583 Conversions .DOUBLE_TO_DOUBLE .celOverloadDecl (),
8684 (ctx , typeSystem , sink , arg ) -> Optional .of (arg ))
87- .addUnaryOverloadTranslator (
85+ .addOverloadTranslator (
8886 Conversions .INT64_TO_DOUBLE .celOverloadDecl (),
89- createUninterpretedConversion (Conversions .INT64_TO_DOUBLE ),
90- /* isApproximated= */ true )
91- .addUnaryOverloadTranslator (
87+ createUninterpretedConversion (Conversions .INT64_TO_DOUBLE ))
88+ .addOverloadTranslator (
9289 Conversions .UINT64_TO_DOUBLE .celOverloadDecl (),
93- createUninterpretedConversion (Conversions .UINT64_TO_DOUBLE ),
94- /* isApproximated= */ true )
95- .addUnaryOverloadTranslator (
90+ createUninterpretedConversion (Conversions .UINT64_TO_DOUBLE ))
91+ .addOverloadTranslator (
9692 Conversions .STRING_TO_DOUBLE .celOverloadDecl (),
97- createUninterpretedConversion (Conversions .STRING_TO_DOUBLE ),
98- /* isApproximated= */ true )
93+ createUninterpretedConversion (Conversions .STRING_TO_DOUBLE ))
9994 .build ();
10095
10196 private static final CelZ3FunctionAxiom STRING_AXIOM =
10297 CelZ3FunctionAxiom .newBuilder (StandardFunction .STRING .functionDecl ())
10398 .addUnaryOverloadTranslator (
10499 Conversions .STRING_TO_STRING .celOverloadDecl (),
105100 (ctx , typeSystem , sink , arg ) -> Optional .of (arg ))
106- .addUnaryOverloadTranslator (
101+ .addOverloadTranslator (
107102 Conversions .INT64_TO_STRING .celOverloadDecl (),
108- createUninterpretedConversion (Conversions .INT64_TO_STRING ),
109- /* isApproximated= */ true )
110- .addUnaryOverloadTranslator (
103+ createUninterpretedConversion (Conversions .INT64_TO_STRING ))
104+ .addOverloadTranslator (
111105 Conversions .UINT64_TO_STRING .celOverloadDecl (),
112- createUninterpretedConversion (Conversions .UINT64_TO_STRING ),
113- /* isApproximated= */ true )
114- .addUnaryOverloadTranslator (
106+ createUninterpretedConversion (Conversions .UINT64_TO_STRING ))
107+ .addOverloadTranslator (
115108 Conversions .DOUBLE_TO_STRING .celOverloadDecl (),
116- createUninterpretedConversion (Conversions .DOUBLE_TO_STRING ),
117- /* isApproximated= */ true )
118- .addUnaryOverloadTranslator (
109+ createUninterpretedConversion (Conversions .DOUBLE_TO_STRING ))
110+ .addOverloadTranslator (
119111 Conversions .BOOL_TO_STRING .celOverloadDecl (),
120- createUninterpretedConversion (Conversions .BOOL_TO_STRING ),
121- /* isApproximated= */ true )
122- .addUnaryOverloadTranslator (
112+ createUninterpretedConversion (Conversions .BOOL_TO_STRING ))
113+ .addOverloadTranslator (
123114 Conversions .BYTES_TO_STRING .celOverloadDecl (),
124- createUninterpretedConversion (Conversions .BYTES_TO_STRING ),
125- /* isApproximated= */ true )
126- .addUnaryOverloadTranslator (
115+ createUninterpretedConversion (Conversions .BYTES_TO_STRING ))
116+ .addOverloadTranslator (
127117 Conversions .TIMESTAMP_TO_STRING .celOverloadDecl (),
128- createUninterpretedConversion (Conversions .TIMESTAMP_TO_STRING ),
129- /* isApproximated= */ true )
130- .addUnaryOverloadTranslator (
118+ createUninterpretedConversion (Conversions .TIMESTAMP_TO_STRING ))
119+ .addOverloadTranslator (
131120 Conversions .DURATION_TO_STRING .celOverloadDecl (),
132- createUninterpretedConversion (Conversions .DURATION_TO_STRING ),
133- /* isApproximated= */ true )
121+ createUninterpretedConversion (Conversions .DURATION_TO_STRING ))
134122 .build ();
135123
136124 private static final CelZ3FunctionAxiom BYTES_AXIOM =
137125 CelZ3FunctionAxiom .newBuilder (StandardFunction .BYTES .functionDecl ())
138126 .addUnaryOverloadTranslator (
139127 Conversions .BYTES_TO_BYTES .celOverloadDecl (),
140128 (ctx , typeSystem , sink , arg ) -> Optional .of (arg ))
141- .addUnaryOverloadTranslator (
129+ .addOverloadTranslator (
142130 Conversions .STRING_TO_BYTES .celOverloadDecl (),
143- createUninterpretedConversion (Conversions .STRING_TO_BYTES ),
144- /* isApproximated= */ true )
131+ createUninterpretedConversion (Conversions .STRING_TO_BYTES ))
145132 .build ();
146133
147134 private static final CelZ3FunctionAxiom DYN_AXIOM =
@@ -156,21 +143,19 @@ final class TypeConversionAxioms {
156143 .addUnaryOverloadTranslator (
157144 Conversions .DURATION_TO_DURATION .celOverloadDecl (),
158145 (ctx , typeSystem , sink , arg ) -> Optional .of (arg ))
159- .addUnaryOverloadTranslator (
146+ .addOverloadTranslator (
160147 Conversions .STRING_TO_DURATION .celOverloadDecl (),
161- createUninterpretedConversion (Conversions .STRING_TO_DURATION ),
162- /* isApproximated= */ true )
148+ createUninterpretedConversion (Conversions .STRING_TO_DURATION ))
163149 .build ();
164150
165151 private static final CelZ3FunctionAxiom TIMESTAMP_AXIOM =
166152 CelZ3FunctionAxiom .newBuilder (StandardFunction .TIMESTAMP .functionDecl ())
167153 .addUnaryOverloadTranslator (
168154 Conversions .TIMESTAMP_TO_TIMESTAMP .celOverloadDecl (),
169155 (ctx , typeSystem , sink , arg ) -> Optional .of (arg ))
170- .addUnaryOverloadTranslator (
156+ .addOverloadTranslator (
171157 Conversions .STRING_TO_TIMESTAMP .celOverloadDecl (),
172- createUninterpretedConversion (Conversions .STRING_TO_TIMESTAMP ),
173- /* isApproximated= */ true )
158+ createUninterpretedConversion (Conversions .STRING_TO_TIMESTAMP ))
174159 .addUnaryOverloadTranslator (
175160 Conversions .INT64_TO_TIMESTAMP .celOverloadDecl (),
176161 (ctx , typeSystem , sink , arg ) -> {
@@ -186,10 +171,9 @@ final class TypeConversionAxioms {
186171 .addUnaryOverloadTranslator (
187172 Conversions .BOOL_TO_BOOL .celOverloadDecl (),
188173 (ctx , typeSystem , sink , arg ) -> Optional .of (arg ))
189- .addUnaryOverloadTranslator (
174+ .addOverloadTranslator (
190175 Conversions .STRING_TO_BOOL .celOverloadDecl (),
191- createUninterpretedConversion (Conversions .STRING_TO_BOOL ),
192- /* isApproximated= */ true )
176+ createUninterpretedConversion (Conversions .STRING_TO_BOOL ))
193177 .build ();
194178
195179 static final ImmutableList <CelZ3FunctionAxiom > ALL_AXIOMS =
@@ -204,64 +188,77 @@ final class TypeConversionAxioms {
204188 TIMESTAMP_AXIOM ,
205189 BOOL_AXIOM );
206190
207- private static CelZ3FunctionAxiom .UnaryTranslator createUninterpretedConversion (
208- Conversions conversion ) {
209- return (ctx , typeSystem , sink , arg ) -> {
191+ private static CelZ3OverloadTranslator createUninterpretedConversion (Conversions conversion ) {
192+ return (ctx , typeSystem , sink , unwrappedArgs , argApproximations ) -> {
193+ Expr <?> arg = unwrappedArgs .get (0 );
194+ BoolExpr baseApprox = argApproximations .get (0 );
195+
210196 FuncDecl <?> funcDecl =
211197 typeSystem .internFuncDecl (
212198 conversion .celOverloadDecl ().overloadId (),
213199 new Sort [] {typeSystem .celValueSort ()},
214200 typeSystem .celValueSort ());
215201 Expr <?> res = ctx .mkApp (funcDecl , arg );
216202
217- BoolExpr isValid ;
218203 switch (conversion .celOverloadDecl ().resultType ().kind ()) {
219204 case INT :
220- isValid =
221- ctx .mkAnd (
205+ sink .accept (ctx .mkOr (typeSystem .isInt (res ), typeSystem .isError (res )));
206+ sink .accept (
207+ ctx .mkImplies (
222208 typeSystem .isInt (res ),
223- ctx .mkNot (typeSystem .checkIntOverflow (typeSystem .getInt (res ))));
209+ ctx .mkNot (typeSystem .checkIntOverflow (typeSystem .getInt (res ))))) ;
224210 break ;
225211 case TIMESTAMP :
226- isValid =
227- ctx .mkAnd (
212+ sink .accept (ctx .mkOr (typeSystem .isTimestamp (res ), typeSystem .isError (res )));
213+ sink .accept (
214+ ctx .mkImplies (
228215 typeSystem .isTimestamp (res ),
229- ctx .mkNot (typeSystem .checkTimestampOverflow (typeSystem .getTimestamp (res ))));
216+ ctx .mkNot (typeSystem .checkTimestampOverflow (typeSystem .getTimestamp (res ))))) ;
230217 break ;
231218 case DURATION :
232- isValid =
233- ctx .mkAnd (
219+ sink .accept (ctx .mkOr (typeSystem .isDuration (res ), typeSystem .isError (res )));
220+ sink .accept (
221+ ctx .mkImplies (
234222 typeSystem .isDuration (res ),
235- ctx .mkNot (typeSystem .checkDurationOverflow (typeSystem .getDuration (res ))));
223+ ctx .mkNot (typeSystem .checkDurationOverflow (typeSystem .getDuration (res ))))) ;
236224 break ;
237225 case UINT :
238- isValid =
239- ctx .mkAnd (
226+ sink .accept (ctx .mkOr (typeSystem .isUint (res ), typeSystem .isError (res )));
227+ sink .accept (
228+ ctx .mkImplies (
240229 typeSystem .isUint (res ),
241- ctx .mkNot (typeSystem .checkUintOverflow (typeSystem .getUint (res ))));
230+ ctx .mkNot (typeSystem .checkUintOverflow (typeSystem .getUint (res ))))) ;
242231 break ;
243232 case DOUBLE :
244- isValid =
245- ctx .mkAnd (
246- typeSystem .isDouble (res ), ctx .mkNot (ctx .mkFPIsNaN (typeSystem .getDouble (res ))));
233+ sink .accept (ctx .mkOr (typeSystem .isDouble (res ), typeSystem .isError (res )));
234+ sink .accept (
235+ ctx .mkImplies (
236+ typeSystem .isDouble (res ),
237+ ctx .mkNot (ctx .mkFPIsNaN ((FPExpr ) typeSystem .getDouble (res )))));
247238 break ;
248239 case STRING :
249- isValid = typeSystem .isString (res );
240+ sink . accept ( ctx . mkOr ( typeSystem .isString (res ), typeSystem . isError ( res )) );
250241 break ;
251242 case BYTES :
252- isValid = typeSystem .isBytes (res );
243+ sink . accept ( ctx . mkOr ( typeSystem .isBytes (res ), typeSystem . isError ( res )) );
253244 break ;
254245 case BOOL :
255- isValid = typeSystem .isBool (res );
246+ sink . accept ( ctx . mkOr ( typeSystem .isBool (res ), typeSystem . isError ( res )) );
256247 break ;
257248 default :
258249 throw new IllegalArgumentException (
259250 "Unsupported uninterpreted conversion result type: "
260251 + conversion .celOverloadDecl ().resultType ());
261252 }
262253
263- sink .accept (ctx .mkOr (isValid , typeSystem .isError (res )));
264- return Optional .of (res );
254+ boolean isArgConstant = typeSystem .isPrimitiveConstant (arg );
255+ boolean isStringParseConversion =
256+ conversion .celOverloadDecl ().parameterTypes ().get (0 ).equals (SimpleType .STRING );
257+
258+ BoolExpr finalApprox =
259+ (!isArgConstant && isStringParseConversion ) ? baseApprox : ctx .mkTrue ();
260+
261+ return Optional .of (CelZ3OverloadResult .create (res , finalApprox ));
265262 };
266263 }
267264
0 commit comments