@@ -284,11 +284,26 @@ 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+ ImmutableSet <Integer > optionalIndices = ImmutableSet .copyOf (createList .optionalIndices ());
288+ for (int i = 0 ; i < createList .elements ().size (); i ++) {
289+ CelExpr element = createList .elements ().get (i );
288290 TranslatedValue elem = translateExpr (element , ast );
289291 elementsTv .add (elem );
290292
291- seq = typeSystem .mkConcatSafe (seq , ctx .mkUnit (elem .z3Expr ()));
293+ if (optionalIndices .contains (i )) {
294+ Expr <?> optRef = typeSystem .getOptionalRef (elem .z3Expr ());
295+ BoolExpr hasVal = typeSystem .optHasValue (optRef );
296+ Expr <?> val = typeSystem .getOptionalValue (optRef );
297+ SeqExpr optSeq =
298+ (SeqExpr )
299+ ctx .mkITE (
300+ hasVal ,
301+ ctx .mkUnit (val ),
302+ ctx .mkEmptySeq (ctx .mkSeqSort (typeSystem .celValueSort ())));
303+ seq = typeSystem .mkConcatSafe (seq , optSeq );
304+ } else {
305+ seq = typeSystem .mkConcatSafe (seq , ctx .mkUnit (elem .z3Expr ()));
306+ }
292307 }
293308 listRef = typeSystem .mkListRefConst (LIST_REF_PREFIX );
294309 typeConstraints .add (ctx .mkEq (typeSystem .getSeq (listRef ), seq ));
@@ -297,7 +312,9 @@ private TranslatedValue translateList(CelExpr celExpr, CelAbstractSyntaxTree ast
297312 }
298313
299314 Expr <?> result = typeSystem .wrapList (listRef );
300- return TranslatedValue .propagateStrict (ctx , typeSystem , result , celExpr , elementsTv );
315+ BoolExpr baseTaint = ctx .mkFalse ();
316+ return TranslatedValue .propagateStrict (
317+ ctx , typeSystem , result , Optional .of (celExpr ), baseTaint , elementsTv );
301318 }
302319
303320 private TranslatedValue translateMap (CelExpr celExpr , CelAbstractSyntaxTree ast ) {
@@ -318,20 +335,43 @@ private TranslatedValue translateMap(CelExpr celExpr, CelAbstractSyntaxTree ast)
318335 Expr <?> value = valueTv .z3Expr ();
319336 elementsTv .add (valueTv );
320337
321- BoolExpr keyAlreadyPresent = (BoolExpr ) ctx .mkSelect (mapPresence , key );
322- keysSeq =
323- ctx .mkITE (keyAlreadyPresent , keysSeq , typeSystem .mkConcatSafe (keysSeq , ctx .mkUnit (key )));
338+ Expr <?> effectiveValue ;
339+ BoolExpr isPresent ;
340+ if (entryAst .optionalEntry ()) {
341+ Expr <?> optRef = typeSystem .getOptionalRef (value );
342+ isPresent = typeSystem .optHasValue (optRef );
343+ effectiveValue = typeSystem .getOptionalValue (optRef );
344+ } else {
345+ isPresent = ctx .mkTrue ();
346+ effectiveValue = value ;
347+ }
324348
325- mapValues = ctx .mkStore (mapValues , key , value );
326- mapPresence = ctx .mkStore (mapPresence , key , ctx .mkTrue ());
349+ BoolExpr keyAlreadyPresent = (BoolExpr ) ctx .mkSelect (mapPresence , key );
350+ BoolExpr shouldAddKey = ctx .mkAnd (isPresent , ctx .mkNot (keyAlreadyPresent ));
351+
352+ SeqExpr keyOptSeq =
353+ (SeqExpr )
354+ ctx .mkITE (
355+ shouldAddKey ,
356+ ctx .mkUnit (key ),
357+ ctx .mkEmptySeq (ctx .mkSeqSort (typeSystem .celValueSort ())));
358+
359+ keysSeq = typeSystem .mkConcatSafe (keysSeq , keyOptSeq );
360+ mapValues =
361+ (ArrayExpr ) ctx .mkITE (isPresent , ctx .mkStore (mapValues , key , effectiveValue ), mapValues );
362+ mapPresence =
363+ (ArrayExpr )
364+ ctx .mkITE (isPresent , ctx .mkStore (mapPresence , key , ctx .mkTrue ()), mapPresence );
327365 }
328366
329367 typeConstraints .add (ctx .mkEq (typeSystem .getMapValues (mapRef ), mapValues ));
330368 typeConstraints .add (ctx .mkEq (typeSystem .getMapPresence (mapRef ), mapPresence ));
331369 typeConstraints .add (ctx .mkEq (typeSystem .getMapKeys (mapRef ), keysSeq ));
332370
333371 Expr <?> result = typeSystem .wrapMap (mapRef );
334- return TranslatedValue .propagateStrict (ctx , typeSystem , result , celExpr , elementsTv );
372+ BoolExpr baseTaint = ctx .mkFalse ();
373+ return TranslatedValue .propagateStrict (
374+ ctx , typeSystem , result , Optional .of (celExpr ), baseTaint , elementsTv );
335375 }
336376
337377 private TranslatedValue translateStruct (CelExpr celExpr , CelAbstractSyntaxTree ast ) {
@@ -379,15 +419,29 @@ private TranslatedValue translateStruct(CelExpr celExpr, CelAbstractSyntaxTree a
379419 // (`msg1 == msg2`) to work without using quantifiers (which avoids MBQI loops).
380420 // Because proto3 singular primitives do not have field presence, we also skip setting
381421 // `msgPresence`.
422+ Expr <?> effectiveValue ;
423+ BoolExpr isPresent ;
424+ if (entryAst .optionalEntry ()) {
425+ Expr <?> optRef = typeSystem .getOptionalRef (value );
426+ isPresent = typeSystem .optHasValue (optRef );
427+ effectiveValue = typeSystem .getOptionalValue (optRef );
428+ } else {
429+ isPresent = ctx .mkTrue ();
430+ effectiveValue = value ;
431+ }
432+
382433 BoolExpr shouldBypass =
383- fieldType .kind ().isPrimitive () ? ctx .mkEq (value , defaultVal ) : ctx .mkFalse ();
434+ fieldType .kind ().isPrimitive () ? ctx .mkEq (effectiveValue , defaultVal ) : ctx .mkFalse ();
435+
436+ BoolExpr shouldStore = ctx .mkAnd (isPresent , ctx .mkNot (shouldBypass ));
384437
385438 msgValues =
386- (ArrayExpr ) ctx .mkITE (shouldBypass , msgValues , ctx .mkStore (msgValues , key , value ));
439+ (ArrayExpr )
440+ ctx .mkITE (shouldStore , ctx .mkStore (msgValues , key , effectiveValue ), msgValues );
387441
388442 msgPresence =
389443 (ArrayExpr )
390- ctx .mkITE (shouldBypass , msgPresence , ctx .mkStore (msgPresence , key , ctx .mkTrue ()));
444+ ctx .mkITE (shouldStore , ctx .mkStore (msgPresence , key , ctx .mkTrue ()), msgPresence );
391445 }
392446
393447 typeConstraints .add (
@@ -396,7 +450,9 @@ private TranslatedValue translateStruct(CelExpr celExpr, CelAbstractSyntaxTree a
396450 typeConstraints .add (ctx .mkEq (typeSystem .getMsgPresence (msgRef ), msgPresence ));
397451
398452 Expr <?> result = typeSystem .wrapMessage (msgRef );
399- return TranslatedValue .propagateStrict (ctx , typeSystem , result , celExpr , elementsTv );
453+ BoolExpr baseTaint = ctx .mkFalse ();
454+ return TranslatedValue .propagateStrict (
455+ ctx , typeSystem , result , Optional .of (celExpr ), baseTaint , elementsTv );
400456 }
401457
402458 private Expr <?> getDefaultValueForType (CelType type ) {
@@ -657,12 +713,26 @@ private TranslatedValue translateComprehension(CelExpr celExpr, CelAbstractSynta
657713 // For statically known list/map literals, unroll them exactly.
658714 if (iterRangeExpr .exprKind ().getKind () == ExprKind .Kind .LIST ) {
659715 ImmutableList <CelExpr > elements = iterRangeExpr .list ().elements ();
716+ ImmutableList <Integer > optionalIndices = iterRangeExpr .list ().optionalIndices ();
660717 for (int i = 0 ; i < elements .size (); i ++) {
661718 TranslatedValue valueTv = translateExpr (elements .get (i ), ast );
662719 Expr <?> value = valueTv .z3Expr ();
663- taints .add (valueTv .isApproximate ());
664- iterationElements .add (new IterationElement (typeSystem .mkInt (i ), value ));
665- allRangeElems .add (value );
720+ if (optionalIndices .contains (i )) {
721+ Expr <?> optRef = typeSystem .getOptionalRef (value );
722+ BoolExpr hasVal = typeSystem .optHasValue (optRef );
723+ if (ctx .mkFalse ().equals (hasVal )) {
724+ continue ;
725+ }
726+ Expr <?> optVal = typeSystem .getOptionalValue (optRef );
727+ taints .add (CelZ3TypeSystem .mkAndFlattened (ctx , hasVal , valueTv .isApproximate ()));
728+ iterationElements .add (
729+ new IterationElement (typeSystem .mkInt (i ), optVal , Optional .of (hasVal )));
730+ allRangeElems .add (ctx .mkITE (hasVal , optVal , typeSystem .mkInt (0 )));
731+ } else {
732+ taints .add (valueTv .isApproximate ());
733+ iterationElements .add (new IterationElement (typeSystem .mkInt (i ), value ));
734+ allRangeElems .add (value );
735+ }
666736 }
667737 } else if (iterRangeExpr .exprKind ().getKind () == ExprKind .Kind .MAP ) {
668738 for (CelExpr .CelMap .Entry entry : iterRangeExpr .map ().entries ()) {
@@ -671,10 +741,23 @@ private TranslatedValue translateComprehension(CelExpr celExpr, CelAbstractSynta
671741 taints .add (keyTv .isApproximate ());
672742 TranslatedValue valueTv = translateExpr (entry .value (), ast );
673743 Expr <?> value = valueTv .z3Expr ();
674- taints .add (valueTv .isApproximate ());
675- iterationElements .add (new IterationElement (key , value ));
676- allRangeElems .add (key );
677- allRangeElems .add (value );
744+ if (entry .optionalEntry ()) {
745+ Expr <?> optRef = typeSystem .getOptionalRef (value );
746+ BoolExpr hasVal = typeSystem .optHasValue (optRef );
747+ if (ctx .mkFalse ().equals (hasVal )) {
748+ continue ;
749+ }
750+ Expr <?> optVal = typeSystem .getOptionalValue (optRef );
751+ taints .add (CelZ3TypeSystem .mkAndFlattened (ctx , hasVal , valueTv .isApproximate ()));
752+ iterationElements .add (new IterationElement (key , optVal , Optional .of (hasVal )));
753+ allRangeElems .add (key );
754+ allRangeElems .add (ctx .mkITE (hasVal , optVal , typeSystem .mkInt (0 )));
755+ } else {
756+ taints .add (valueTv .isApproximate ());
757+ iterationElements .add (new IterationElement (key , value ));
758+ allRangeElems .add (key );
759+ allRangeElems .add (value );
760+ }
678761 }
679762 } else {
680763 return translateDynamicComprehension (celExpr , ast );
@@ -693,13 +776,23 @@ private TranslatedValue translateComprehension(CelExpr celExpr, CelAbstractSynta
693776 comp , ast , iterElem .keyOrIndex , iterElem .value , currentAccu , isMap , isTwoVar );
694777 Expr <?> condition = condAndStep [0 ].z3Expr ();
695778 Expr <?> step = condAndStep [1 ].z3Expr ();
696- taints .add (condAndStep [1 ].isApproximate ());
779+ if (iterElem .hasValue .isPresent ()) {
780+ taints .add (
781+ CelZ3TypeSystem .mkAndFlattened (
782+ ctx , iterElem .hasValue .get (), condAndStep [1 ].isApproximate ()));
783+ } else {
784+ taints .add (condAndStep [1 ].isApproximate ());
785+ }
697786
698787 Expr <?> stepVal = ctx .mkITE ((BoolExpr ) typeSystem .unwrapBool (condition ), step , currentAccu );
699788 Expr <?> typeErrorOrStep =
700789 typeSystem .withRuntimeError (stepVal , ctx .mkNot (typeSystem .isBool (condition )));
701790
702- accu = typeSystem .propagateErrorAndUnknown (typeErrorOrStep , condition );
791+ Expr <?> updatedAccu = typeSystem .propagateErrorAndUnknown (typeErrorOrStep , condition );
792+ accu =
793+ iterElem .hasValue .isPresent ()
794+ ? ctx .mkITE (iterElem .hasValue .get (), updatedAccu , currentAccu )
795+ : updatedAccu ;
703796 }
704797
705798 TranslatedValue resultTv =
@@ -1229,10 +1322,16 @@ private BoolExpr createTypeConstraintForType(Expr<?> val, CelType type) {
12291322 private static class IterationElement {
12301323 final Expr <?> keyOrIndex ;
12311324 final Expr <?> value ;
1325+ final Optional <BoolExpr > hasValue ;
12321326
12331327 IterationElement (Expr <?> keyOrIndex , Expr <?> value ) {
1328+ this (keyOrIndex , value , Optional .empty ());
1329+ }
1330+
1331+ IterationElement (Expr <?> keyOrIndex , Expr <?> value , Optional <BoolExpr > hasValue ) {
12341332 this .keyOrIndex = keyOrIndex ;
12351333 this .value = value ;
1334+ this .hasValue = hasValue ;
12361335 }
12371336 }
12381337
@@ -1249,6 +1348,7 @@ private Optional<Object> toCacheKey(CelExpr expr) {
12491348 }
12501349 builder .add (elemKey .get ());
12511350 }
1351+ builder .add (expr .list ().optionalIndices ());
12521352 return Optional .of (builder .build ());
12531353 default :
12541354 return Optional .empty ();
0 commit comments