2323import com .microsoft .z3 .Expr ;
2424import com .microsoft .z3 .FuncDecl ;
2525import com .microsoft .z3 .IntExpr ;
26- import com .microsoft .z3 .Pattern ;
2726import com .microsoft .z3 .Quantifier ;
2827import com .microsoft .z3 .SeqExpr ;
2928import com .microsoft .z3 .Sort ;
4140import dev .cel .common .types .ListType ;
4241import dev .cel .common .types .MapType ;
4342import dev .cel .common .types .NullableType ;
43+ import dev .cel .common .types .OptionalType ;
4444import dev .cel .common .types .SimpleType ;
4545import dev .cel .common .types .StructType ;
4646import dev .cel .common .types .StructTypeReference ;
@@ -79,7 +79,6 @@ final class CelAstToZ3Translator {
7979 private static final String EMPTY_MSG_REF_PREFIX = "!empty_msg_ref_" ;
8080 private static final String EMPTY_LIST_PREFIX = "!empty_list" ;
8181 private static final String EMPTY_MAP_PREFIX = "!empty_map" ;
82- private static final String MAP_BIJECTION_PREFIX = "k_map_bijection" ;
8382 private final Context ctx ;
8483 private final CelZ3TypeSystem typeSystem ;
8584 private final CelZ3OperatorTranslator operatorTranslator ;
@@ -289,9 +288,13 @@ private TranslatedValue translateList(CelExpr celExpr, CelAbstractSyntaxTree ast
289288 for (int i = 0 ; i < elements .size (); i ++) {
290289 CelExpr element = elements .get (i );
291290 TranslatedValue elem = translateExpr (element , ast );
292- elementsTv .add (elem );
293291
294292 if (optionalIndices .contains (i )) {
293+ Expr <?> checkedValue =
294+ typeSystem .withRuntimeError (
295+ elem .z3Expr (), ctx .mkNot (typeSystem .isOptional (elem .z3Expr ())));
296+ elem = TranslatedValue .create (checkedValue , element , typeSystem , elem .isApproximate ());
297+
295298 Expr <?> optRef = typeSystem .getOptionalRef (elem .z3Expr ());
296299 seq =
297300 (SeqExpr )
@@ -302,6 +305,7 @@ private TranslatedValue translateList(CelExpr celExpr, CelAbstractSyntaxTree ast
302305 } else {
303306 seq = typeSystem .mkConcatSafe (seq , ctx .mkUnit (elem .z3Expr ()));
304307 }
308+ elementsTv .add (elem );
305309 }
306310 listRef = typeSystem .mkListRefConst (LIST_REF_PREFIX );
307311 typeConstraints .add (ctx .mkEq (typeSystem .getSeq (listRef ), seq ));
@@ -329,15 +333,22 @@ private TranslatedValue translateMap(CelExpr celExpr, CelAbstractSyntaxTree ast)
329333 elementsTv .add (keyTv );
330334 TranslatedValue valueTv = translateExpr (entryAst .value (), ast );
331335 Expr <?> value = valueTv .z3Expr ();
332- elementsTv .add (valueTv );
333336
334337 Expr <?> finalValue = value ;
335338 BoolExpr finalPresence = ctx .mkTrue ();
336339 if (entryAst .optionalEntry ()) {
340+ Expr <?> checkedValue =
341+ typeSystem .withRuntimeError (value , ctx .mkNot (typeSystem .isOptional (value )));
342+ valueTv =
343+ TranslatedValue .create (
344+ checkedValue , entryAst .value (), typeSystem , valueTv .isApproximate ());
345+ value = checkedValue ;
346+
337347 Expr <?> optRef = typeSystem .getOptionalRef (value );
338348 finalPresence = typeSystem .optHasValue (optRef );
339349 finalValue = typeSystem .getOptionalValue (optRef );
340350 }
351+ elementsTv .add (valueTv );
341352
342353 BoolExpr keyAlreadyPresent = (BoolExpr ) ctx .mkSelect (mapPresence , key );
343354 BoolExpr shouldInsertKey = ctx .mkAnd (ctx .mkNot (keyAlreadyPresent ), finalPresence );
@@ -384,7 +395,6 @@ private TranslatedValue translateStruct(CelExpr celExpr, CelAbstractSyntaxTree a
384395 Expr <?> key = ctx .mkString (entryAst .fieldKey ());
385396 TranslatedValue valueTv = translateExpr (entryAst .value (), ast );
386397 Expr <?> value = valueTv .z3Expr ();
387- elementsTv .add (valueTv );
388398
389399 CelType fieldType =
390400 typeProvider
@@ -399,10 +409,18 @@ private TranslatedValue translateStruct(CelExpr celExpr, CelAbstractSyntaxTree a
399409 Expr <?> finalValue = value ;
400410 BoolExpr optionalHasValue = ctx .mkTrue ();
401411 if (entryAst .optionalEntry ()) {
412+ Expr <?> checkedValue =
413+ typeSystem .withRuntimeError (value , ctx .mkNot (typeSystem .isOptional (value )));
414+ valueTv =
415+ TranslatedValue .create (
416+ checkedValue , entryAst .value (), typeSystem , valueTv .isApproximate ());
417+ value = checkedValue ;
418+
402419 Expr <?> optRef = typeSystem .getOptionalRef (value );
403420 optionalHasValue = typeSystem .optHasValue (optRef );
404421 finalValue = typeSystem .getOptionalValue (optRef );
405422 }
423+ elementsTv .add (valueTv );
406424
407425 // Canonicalization Trick:
408426 //
@@ -438,6 +456,9 @@ private Expr<?> getDefaultValueForType(CelType type) {
438456 if (type instanceof NullableType ) {
439457 return typeSystem .mkNull ();
440458 }
459+ if (type instanceof OptionalType ) {
460+ return typeSystem .mkOptionalNone ();
461+ }
441462 if (type .equals (SimpleType .INT )) {
442463 return typeSystem .mkInt (0 );
443464 }
@@ -819,36 +840,18 @@ private void applyBoundedMapBijection(
819840 }
820841 }
821842
822- Expr <?> kVar = ctx .mkFreshConst (MAP_BIJECTION_PREFIX , typeSystem .celValueSort ());
823- BoolExpr isValidKey =
824- ctx .mkOr (
825- typeSystem .isInt (kVar ), typeSystem .isUint (kVar ),
826- typeSystem .isBool (kVar ), typeSystem .isString (kVar ));
827- BoolExpr inMap = (BoolExpr ) ctx .mkSelect (mapPresence , kVar );
843+ BoolExpr isNotTruncated = ctx .mkLe (lengthExpr , ctx .mkInt (comprehensionUnrollLimit ));
828844
829- List < BoolExpr > inSeqMatches = new ArrayList <>( );
845+ ArrayExpr seqMap = ctx . mkConstArray ( typeSystem . celValueSort (), ctx . mkFalse () );
830846 for (int i = 0 ; i < comprehensionUnrollLimit ; i ++) {
831- BoolExpr match =
832- ctx .mkAnd (
833- ctx .mkLt (ctx .mkInt (i ), lengthExpr ), ctx .mkEq (kVar , ctx .mkNth (seq , ctx .mkInt (i ))));
834- inSeqMatches .add (match );
847+ seqMap =
848+ (ArrayExpr )
849+ ctx .mkITE (
850+ ctx .mkLt (ctx .mkInt (i ), lengthExpr ),
851+ ctx .mkStore (seqMap , ctx .mkNth (seq , ctx .mkInt (i )), ctx .mkTrue ()),
852+ seqMap );
835853 }
836- BoolExpr inSeq = CelZ3TypeSystem .mkOrFlattened (ctx , inSeqMatches );
837-
838- BoolExpr isNotTruncated = ctx .mkLe (lengthExpr , ctx .mkInt (comprehensionUnrollLimit ));
839-
840- Pattern inMapPattern = ctx .mkPattern (inMap );
841-
842- BoolExpr completeness =
843- ctx .mkForall (
844- new Expr <?>[] {kVar },
845- ctx .mkImplies (ctx .mkAnd (isNotTruncated , isValidKey , inMap ), inSeq ),
846- 1 ,
847- new Pattern [] {inMapPattern },
848- null ,
849- null ,
850- null );
851- typeConstraints .add (completeness );
854+ typeConstraints .add (ctx .mkImplies (isNotTruncated , ctx .mkEq (mapPresence , seqMap )));
852855 }
853856
854857 private TranslatedValue [] evaluateLoopCondAndStep (
@@ -1167,6 +1170,24 @@ private BoolExpr createTypeConstraint(Expr<?> val, long exprId, CelAbstractSynta
11671170 }
11681171
11691172 private BoolExpr createTypeConstraintForType (Expr <?> val , CelType type ) {
1173+ if (type instanceof NullableType ) {
1174+ NullableType nullableType = (NullableType ) type ;
1175+ return ctx .mkOr (
1176+ typeSystem .isNull (val ),
1177+ createTypeConstraintForType (val , nullableType .targetType ()));
1178+ }
1179+ if (type instanceof OptionalType ) {
1180+ BoolExpr isOpt = typeSystem .isOptional (val );
1181+ CelType paramType = type .parameters ().get (0 );
1182+ if (paramType .kind ().isDyn () || paramType .kind ().isTypeParam ()) {
1183+ return isOpt ;
1184+ }
1185+ Expr <?> optRef = typeSystem .getOptionalRef (val );
1186+ BoolExpr hasValue = typeSystem .optHasValue (optRef );
1187+ BoolExpr valConstraint =
1188+ createTypeConstraintForType (typeSystem .getOptionalValue (optRef ), paramType );
1189+ return ctx .mkAnd (isOpt , ctx .mkImplies (hasValue , valConstraint ));
1190+ }
11701191 if (type .equals (SimpleType .BOOL )) {
11711192 return (BoolExpr ) ctx .mkApp (typeSystem .boolCons ().getTesterDecl (), val );
11721193 }
0 commit comments