@@ -284,11 +284,24 @@ private TranslatedValue translateList(CelExpr celExpr, CelAbstractSyntaxTree ast
284284 // check to a trivial identity check (e.g., `list_ref_0 == list_ref_0`).
285285 if (listRef == null ) {
286286 SeqExpr seq = ctx .mkEmptySeq (ctx .mkSeqSort (typeSystem .celValueSort ()));
287- for (CelExpr element : createList .elements ()) {
287+ ImmutableList <Integer > optionalIndices = createList .optionalIndices ();
288+ ImmutableList <CelExpr > elements = createList .elements ();
289+ for (int i = 0 ; i < elements .size (); i ++) {
290+ CelExpr element = elements .get (i );
288291 TranslatedValue elem = translateExpr (element , ast );
289292 elementsTv .add (elem );
290293
291- seq = typeSystem .mkConcatSafe (seq , ctx .mkUnit (elem .z3Expr ()));
294+ if (optionalIndices .contains (i )) {
295+ Expr <?> optRef = typeSystem .getOptionalRef (elem .z3Expr ());
296+ seq =
297+ (SeqExpr )
298+ ctx .mkITE (
299+ typeSystem .optHasValue (optRef ),
300+ typeSystem .mkConcatSafe (seq , ctx .mkUnit (typeSystem .getOptionalValue (optRef ))),
301+ seq );
302+ } else {
303+ seq = typeSystem .mkConcatSafe (seq , ctx .mkUnit (elem .z3Expr ()));
304+ }
292305 }
293306 listRef = typeSystem .mkListRefConst (LIST_REF_PREFIX );
294307 typeConstraints .add (ctx .mkEq (typeSystem .getSeq (listRef ), seq ));
@@ -318,12 +331,24 @@ private TranslatedValue translateMap(CelExpr celExpr, CelAbstractSyntaxTree ast)
318331 Expr <?> value = valueTv .z3Expr ();
319332 elementsTv .add (valueTv );
320333
334+ Expr <?> finalValue = value ;
335+ BoolExpr finalPresence = ctx .mkTrue ();
336+ if (entryAst .optionalEntry ()) {
337+ Expr <?> optRef = typeSystem .getOptionalRef (value );
338+ finalPresence = typeSystem .optHasValue (optRef );
339+ finalValue = typeSystem .getOptionalValue (optRef );
340+ }
341+
321342 BoolExpr keyAlreadyPresent = (BoolExpr ) ctx .mkSelect (mapPresence , key );
343+ BoolExpr shouldInsertKey = ctx .mkAnd (ctx .mkNot (keyAlreadyPresent ), finalPresence );
322344 keysSeq =
323- ctx .mkITE (keyAlreadyPresent , keysSeq , typeSystem .mkConcatSafe (keysSeq , ctx .mkUnit (key )));
345+ ctx .mkITE (shouldInsertKey , typeSystem .mkConcatSafe (keysSeq , ctx .mkUnit (key )), keysSeq );
324346
325- mapValues = ctx .mkStore (mapValues , key , value );
326- mapPresence = ctx .mkStore (mapPresence , key , ctx .mkTrue ());
347+ mapValues =
348+ (ArrayExpr ) ctx .mkITE (finalPresence , ctx .mkStore (mapValues , key , finalValue ), mapValues );
349+ mapPresence =
350+ (ArrayExpr )
351+ ctx .mkITE (finalPresence , ctx .mkStore (mapPresence , key , ctx .mkTrue ()), mapPresence );
327352 }
328353
329354 typeConstraints .add (ctx .mkEq (typeSystem .getMapValues (mapRef ), mapValues ));
@@ -371,6 +396,14 @@ private TranslatedValue translateStruct(CelExpr celExpr, CelAbstractSyntaxTree a
371396 .orElseGet (() -> extractAstTypeOrDefault (ast , entryAst .value ().id ()));
372397 Expr <?> defaultVal = getDefaultValueForType (fieldType );
373398
399+ Expr <?> finalValue = value ;
400+ BoolExpr optionalHasValue = ctx .mkTrue ();
401+ if (entryAst .optionalEntry ()) {
402+ Expr <?> optRef = typeSystem .getOptionalRef (value );
403+ optionalHasValue = typeSystem .optHasValue (optRef );
404+ finalValue = typeSystem .getOptionalValue (optRef );
405+ }
406+
374407 // Canonicalization Trick:
375408 //
376409 // We avoid storing explicit default values (e.g. `single_int32: 0`)
@@ -379,11 +412,13 @@ private TranslatedValue translateStruct(CelExpr celExpr, CelAbstractSyntaxTree a
379412 // (`msg1 == msg2`) to work without using quantifiers (which avoids MBQI loops).
380413 // Because proto3 singular primitives do not have field presence, we also skip setting
381414 // `msgPresence`.
382- BoolExpr shouldBypass =
383- fieldType .kind ().isPrimitive () ? ctx .mkEq (value , defaultVal ) : ctx .mkFalse ();
415+ BoolExpr isDefaultPrimitive =
416+ fieldType .kind ().isPrimitive () ? ctx .mkEq (finalValue , defaultVal ) : ctx .mkFalse ();
417+
418+ BoolExpr shouldBypass = ctx .mkOr (ctx .mkNot (optionalHasValue ), isDefaultPrimitive );
384419
385420 msgValues =
386- (ArrayExpr ) ctx .mkITE (shouldBypass , msgValues , ctx .mkStore (msgValues , key , value ));
421+ (ArrayExpr ) ctx .mkITE (shouldBypass , msgValues , ctx .mkStore (msgValues , key , finalValue ));
387422
388423 msgPresence =
389424 (ArrayExpr )
@@ -655,7 +690,8 @@ private TranslatedValue translateComprehension(CelExpr celExpr, CelAbstractSynta
655690 List <Expr <?>> allRangeElems = new ArrayList <>();
656691
657692 // For statically known list/map literals, unroll them exactly.
658- if (iterRangeExpr .exprKind ().getKind () == ExprKind .Kind .LIST ) {
693+ if (iterRangeExpr .exprKind ().getKind () == ExprKind .Kind .LIST
694+ && iterRangeExpr .list ().optionalIndices ().isEmpty ()) {
659695 ImmutableList <CelExpr > elements = iterRangeExpr .list ().elements ();
660696 for (int i = 0 ; i < elements .size (); i ++) {
661697 TranslatedValue valueTv = translateExpr (elements .get (i ), ast );
@@ -664,7 +700,8 @@ private TranslatedValue translateComprehension(CelExpr celExpr, CelAbstractSynta
664700 iterationElements .add (new IterationElement (typeSystem .mkInt (i ), value ));
665701 allRangeElems .add (value );
666702 }
667- } else if (iterRangeExpr .exprKind ().getKind () == ExprKind .Kind .MAP ) {
703+ } else if (iterRangeExpr .exprKind ().getKind () == ExprKind .Kind .MAP
704+ && iterRangeExpr .map ().entries ().stream ().noneMatch (CelExpr .CelMap .Entry ::optionalEntry )) {
668705 for (CelExpr .CelMap .Entry entry : iterRangeExpr .map ().entries ()) {
669706 TranslatedValue keyTv = translateExpr (entry .key (), ast );
670707 Expr <?> key = keyTv .z3Expr ();
0 commit comments