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 ;
@@ -79,7 +78,6 @@ final class CelAstToZ3Translator {
7978 private static final String EMPTY_MSG_REF_PREFIX = "!empty_msg_ref_" ;
8079 private static final String EMPTY_LIST_PREFIX = "!empty_list" ;
8180 private static final String EMPTY_MAP_PREFIX = "!empty_map" ;
82- private static final String MAP_BIJECTION_PREFIX = "k_map_bijection" ;
8381 private final Context ctx ;
8482 private final CelZ3TypeSystem typeSystem ;
8583 private final CelZ3OperatorTranslator operatorTranslator ;
@@ -284,11 +282,24 @@ private TranslatedValue translateList(CelExpr celExpr, CelAbstractSyntaxTree ast
284282 // check to a trivial identity check (e.g., `list_ref_0 == list_ref_0`).
285283 if (listRef == null ) {
286284 SeqExpr seq = ctx .mkEmptySeq (ctx .mkSeqSort (typeSystem .celValueSort ()));
287- for (CelExpr element : createList .elements ()) {
285+ ImmutableList <Integer > optionalIndices = createList .optionalIndices ();
286+ ImmutableList <CelExpr > elements = createList .elements ();
287+ for (int i = 0 ; i < elements .size (); i ++) {
288+ CelExpr element = elements .get (i );
288289 TranslatedValue elem = translateExpr (element , ast );
289290 elementsTv .add (elem );
290291
291- seq = typeSystem .mkConcatSafe (seq , ctx .mkUnit (elem .z3Expr ()));
292+ if (optionalIndices .contains (i )) {
293+ Expr <?> optRef = typeSystem .getOptionalRef (elem .z3Expr ());
294+ seq =
295+ (SeqExpr )
296+ ctx .mkITE (
297+ typeSystem .optHasValue (optRef ),
298+ typeSystem .mkConcatSafe (seq , ctx .mkUnit (typeSystem .getOptionalValue (optRef ))),
299+ seq );
300+ } else {
301+ seq = typeSystem .mkConcatSafe (seq , ctx .mkUnit (elem .z3Expr ()));
302+ }
292303 }
293304 listRef = typeSystem .mkListRefConst (LIST_REF_PREFIX );
294305 typeConstraints .add (ctx .mkEq (typeSystem .getSeq (listRef ), seq ));
@@ -318,12 +329,24 @@ private TranslatedValue translateMap(CelExpr celExpr, CelAbstractSyntaxTree ast)
318329 Expr <?> value = valueTv .z3Expr ();
319330 elementsTv .add (valueTv );
320331
332+ Expr <?> finalValue = value ;
333+ BoolExpr finalPresence = ctx .mkTrue ();
334+ if (entryAst .optionalEntry ()) {
335+ Expr <?> optRef = typeSystem .getOptionalRef (value );
336+ finalPresence = typeSystem .optHasValue (optRef );
337+ finalValue = typeSystem .getOptionalValue (optRef );
338+ }
339+
321340 BoolExpr keyAlreadyPresent = (BoolExpr ) ctx .mkSelect (mapPresence , key );
341+ BoolExpr shouldInsertKey = ctx .mkAnd (ctx .mkNot (keyAlreadyPresent ), finalPresence );
322342 keysSeq =
323- ctx .mkITE (keyAlreadyPresent , keysSeq , typeSystem .mkConcatSafe (keysSeq , ctx .mkUnit (key )));
343+ ctx .mkITE (shouldInsertKey , typeSystem .mkConcatSafe (keysSeq , ctx .mkUnit (key )), keysSeq );
324344
325- mapValues = ctx .mkStore (mapValues , key , value );
326- mapPresence = ctx .mkStore (mapPresence , key , ctx .mkTrue ());
345+ mapValues =
346+ (ArrayExpr ) ctx .mkITE (finalPresence , ctx .mkStore (mapValues , key , finalValue ), mapValues );
347+ mapPresence =
348+ (ArrayExpr )
349+ ctx .mkITE (finalPresence , ctx .mkStore (mapPresence , key , ctx .mkTrue ()), mapPresence );
327350 }
328351
329352 typeConstraints .add (ctx .mkEq (typeSystem .getMapValues (mapRef ), mapValues ));
@@ -371,6 +394,14 @@ private TranslatedValue translateStruct(CelExpr celExpr, CelAbstractSyntaxTree a
371394 .orElseGet (() -> extractAstTypeOrDefault (ast , entryAst .value ().id ()));
372395 Expr <?> defaultVal = getDefaultValueForType (fieldType );
373396
397+ Expr <?> finalValue = value ;
398+ BoolExpr optionalHasValue = ctx .mkTrue ();
399+ if (entryAst .optionalEntry ()) {
400+ Expr <?> optRef = typeSystem .getOptionalRef (value );
401+ optionalHasValue = typeSystem .optHasValue (optRef );
402+ finalValue = typeSystem .getOptionalValue (optRef );
403+ }
404+
374405 // Canonicalization Trick:
375406 //
376407 // We avoid storing explicit default values (e.g. `single_int32: 0`)
@@ -379,11 +410,13 @@ private TranslatedValue translateStruct(CelExpr celExpr, CelAbstractSyntaxTree a
379410 // (`msg1 == msg2`) to work without using quantifiers (which avoids MBQI loops).
380411 // Because proto3 singular primitives do not have field presence, we also skip setting
381412 // `msgPresence`.
382- BoolExpr shouldBypass =
383- fieldType .kind ().isPrimitive () ? ctx .mkEq (value , defaultVal ) : ctx .mkFalse ();
413+ BoolExpr isDefaultPrimitive =
414+ fieldType .kind ().isPrimitive () ? ctx .mkEq (finalValue , defaultVal ) : ctx .mkFalse ();
415+
416+ BoolExpr shouldBypass = ctx .mkOr (ctx .mkNot (optionalHasValue ), isDefaultPrimitive );
384417
385418 msgValues =
386- (ArrayExpr ) ctx .mkITE (shouldBypass , msgValues , ctx .mkStore (msgValues , key , value ));
419+ (ArrayExpr ) ctx .mkITE (shouldBypass , msgValues , ctx .mkStore (msgValues , key , finalValue ));
387420
388421 msgPresence =
389422 (ArrayExpr )
@@ -655,7 +688,8 @@ private TranslatedValue translateComprehension(CelExpr celExpr, CelAbstractSynta
655688 List <Expr <?>> allRangeElems = new ArrayList <>();
656689
657690 // For statically known list/map literals, unroll them exactly.
658- if (iterRangeExpr .exprKind ().getKind () == ExprKind .Kind .LIST ) {
691+ if (iterRangeExpr .exprKind ().getKind () == ExprKind .Kind .LIST
692+ && iterRangeExpr .list ().optionalIndices ().isEmpty ()) {
659693 ImmutableList <CelExpr > elements = iterRangeExpr .list ().elements ();
660694 for (int i = 0 ; i < elements .size (); i ++) {
661695 TranslatedValue valueTv = translateExpr (elements .get (i ), ast );
@@ -664,7 +698,8 @@ private TranslatedValue translateComprehension(CelExpr celExpr, CelAbstractSynta
664698 iterationElements .add (new IterationElement (typeSystem .mkInt (i ), value ));
665699 allRangeElems .add (value );
666700 }
667- } else if (iterRangeExpr .exprKind ().getKind () == ExprKind .Kind .MAP ) {
701+ } else if (iterRangeExpr .exprKind ().getKind () == ExprKind .Kind .MAP
702+ && iterRangeExpr .map ().entries ().stream ().noneMatch (CelExpr .CelMap .Entry ::optionalEntry )) {
668703 for (CelExpr .CelMap .Entry entry : iterRangeExpr .map ().entries ()) {
669704 TranslatedValue keyTv = translateExpr (entry .key (), ast );
670705 Expr <?> key = keyTv .z3Expr ();
@@ -782,36 +817,18 @@ private void applyBoundedMapBijection(
782817 }
783818 }
784819
785- Expr <?> kVar = ctx .mkFreshConst (MAP_BIJECTION_PREFIX , typeSystem .celValueSort ());
786- BoolExpr isValidKey =
787- ctx .mkOr (
788- typeSystem .isInt (kVar ), typeSystem .isUint (kVar ),
789- typeSystem .isBool (kVar ), typeSystem .isString (kVar ));
790- BoolExpr inMap = (BoolExpr ) ctx .mkSelect (mapPresence , kVar );
820+ BoolExpr isNotTruncated = ctx .mkLe (lengthExpr , ctx .mkInt (comprehensionUnrollLimit ));
791821
792- List < BoolExpr > inSeqMatches = new ArrayList <>( );
822+ ArrayExpr seqMap = ctx . mkConstArray ( typeSystem . celValueSort (), ctx . mkFalse () );
793823 for (int i = 0 ; i < comprehensionUnrollLimit ; i ++) {
794- BoolExpr match =
795- ctx .mkAnd (
796- ctx .mkLt (ctx .mkInt (i ), lengthExpr ), ctx .mkEq (kVar , ctx .mkNth (seq , ctx .mkInt (i ))));
797- inSeqMatches .add (match );
824+ seqMap =
825+ (ArrayExpr )
826+ ctx .mkITE (
827+ ctx .mkLt (ctx .mkInt (i ), lengthExpr ),
828+ ctx .mkStore (seqMap , ctx .mkNth (seq , ctx .mkInt (i )), ctx .mkTrue ()),
829+ seqMap );
798830 }
799- BoolExpr inSeq = CelZ3TypeSystem .mkOrFlattened (ctx , inSeqMatches );
800-
801- BoolExpr isNotTruncated = ctx .mkLe (lengthExpr , ctx .mkInt (comprehensionUnrollLimit ));
802-
803- Pattern inMapPattern = ctx .mkPattern (inMap );
804-
805- BoolExpr completeness =
806- ctx .mkForall (
807- new Expr <?>[] {kVar },
808- ctx .mkImplies (ctx .mkAnd (isNotTruncated , isValidKey , inMap ), inSeq ),
809- 1 ,
810- new Pattern [] {inMapPattern },
811- null ,
812- null ,
813- null );
814- typeConstraints .add (completeness );
831+ typeConstraints .add (ctx .mkImplies (isNotTruncated , ctx .mkEq (mapPresence , seqMap )));
815832 }
816833
817834 private TranslatedValue [] evaluateLoopCondAndStep (
0 commit comments