Skip to content

Commit a2ad360

Browse files
l46kokcopybara-github
authored andcommitted
Add variable bounds for optionals in verifier
PiperOrigin-RevId: 952363986
1 parent 46e1933 commit a2ad360

2 files changed

Lines changed: 149 additions & 61 deletions

File tree

verifier/src/main/java/dev/cel/verifier/CelAstToZ3Translator.java

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import dev.cel.common.types.ListType;
4141
import dev.cel.common.types.MapType;
4242
import dev.cel.common.types.NullableType;
43+
import dev.cel.common.types.OptionalType;
4344
import dev.cel.common.types.SimpleType;
4445
import dev.cel.common.types.StructType;
4546
import dev.cel.common.types.StructTypeReference;
@@ -287,9 +288,13 @@ private TranslatedValue translateList(CelExpr celExpr, CelAbstractSyntaxTree ast
287288
for (int i = 0; i < elements.size(); i++) {
288289
CelExpr element = elements.get(i);
289290
TranslatedValue elem = translateExpr(element, ast);
290-
elementsTv.add(elem);
291291

292292
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+
293298
Expr<?> optRef = typeSystem.getOptionalRef(elem.z3Expr());
294299
seq =
295300
(SeqExpr)
@@ -300,6 +305,7 @@ private TranslatedValue translateList(CelExpr celExpr, CelAbstractSyntaxTree ast
300305
} else {
301306
seq = typeSystem.mkConcatSafe(seq, ctx.mkUnit(elem.z3Expr()));
302307
}
308+
elementsTv.add(elem);
303309
}
304310
listRef = typeSystem.mkListRefConst(LIST_REF_PREFIX);
305311
typeConstraints.add(ctx.mkEq(typeSystem.getSeq(listRef), seq));
@@ -327,15 +333,20 @@ private TranslatedValue translateMap(CelExpr celExpr, CelAbstractSyntaxTree ast)
327333
elementsTv.add(keyTv);
328334
TranslatedValue valueTv = translateExpr(entryAst.value(), ast);
329335
Expr<?> value = valueTv.z3Expr();
330-
elementsTv.add(valueTv);
331336

332337
Expr<?> finalValue = value;
333338
BoolExpr finalPresence = ctx.mkTrue();
334339
if (entryAst.optionalEntry()) {
335-
Expr<?> optRef = typeSystem.getOptionalRef(value);
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+
Expr<?> optRef = typeSystem.getOptionalRef(checkedValue);
336346
finalPresence = typeSystem.optHasValue(optRef);
337347
finalValue = typeSystem.getOptionalValue(optRef);
338348
}
349+
elementsTv.add(valueTv);
339350

340351
BoolExpr keyAlreadyPresent = (BoolExpr) ctx.mkSelect(mapPresence, key);
341352
BoolExpr shouldInsertKey = ctx.mkAnd(ctx.mkNot(keyAlreadyPresent), finalPresence);
@@ -382,7 +393,6 @@ private TranslatedValue translateStruct(CelExpr celExpr, CelAbstractSyntaxTree a
382393
Expr<?> key = ctx.mkString(entryAst.fieldKey());
383394
TranslatedValue valueTv = translateExpr(entryAst.value(), ast);
384395
Expr<?> value = valueTv.z3Expr();
385-
elementsTv.add(valueTv);
386396

387397
CelType fieldType =
388398
typeProvider
@@ -397,10 +407,16 @@ private TranslatedValue translateStruct(CelExpr celExpr, CelAbstractSyntaxTree a
397407
Expr<?> finalValue = value;
398408
BoolExpr optionalHasValue = ctx.mkTrue();
399409
if (entryAst.optionalEntry()) {
400-
Expr<?> optRef = typeSystem.getOptionalRef(value);
410+
Expr<?> checkedValue =
411+
typeSystem.withRuntimeError(value, ctx.mkNot(typeSystem.isOptional(value)));
412+
valueTv =
413+
TranslatedValue.create(
414+
checkedValue, entryAst.value(), typeSystem, valueTv.isApproximate());
415+
Expr<?> optRef = typeSystem.getOptionalRef(checkedValue);
401416
optionalHasValue = typeSystem.optHasValue(optRef);
402417
finalValue = typeSystem.getOptionalValue(optRef);
403418
}
419+
elementsTv.add(valueTv);
404420

405421
// Canonicalization Trick:
406422
//
@@ -436,6 +452,9 @@ private Expr<?> getDefaultValueForType(CelType type) {
436452
if (type instanceof NullableType) {
437453
return typeSystem.mkNull();
438454
}
455+
if (type instanceof OptionalType) {
456+
return typeSystem.mkOptionalNone();
457+
}
439458
if (type.equals(SimpleType.INT)) {
440459
return typeSystem.mkInt(0);
441460
}
@@ -1147,6 +1166,23 @@ private BoolExpr createTypeConstraint(Expr<?> val, long exprId, CelAbstractSynta
11471166
}
11481167

11491168
private BoolExpr createTypeConstraintForType(Expr<?> val, CelType type) {
1169+
if (type instanceof NullableType) {
1170+
NullableType nullableType = (NullableType) type;
1171+
return ctx.mkOr(
1172+
typeSystem.isNull(val), createTypeConstraintForType(val, nullableType.targetType()));
1173+
}
1174+
if (type instanceof OptionalType) {
1175+
BoolExpr isOpt = typeSystem.isOptional(val);
1176+
CelType paramType = type.parameters().get(0);
1177+
if (paramType.kind().isDyn() || paramType.kind().isTypeParam()) {
1178+
return isOpt;
1179+
}
1180+
Expr<?> optRef = typeSystem.getOptionalRef(val);
1181+
BoolExpr hasValue = typeSystem.optHasValue(optRef);
1182+
BoolExpr valConstraint =
1183+
createTypeConstraintForType(typeSystem.getOptionalValue(optRef), paramType);
1184+
return ctx.mkAnd(isOpt, ctx.mkImplies(hasValue, valConstraint));
1185+
}
11501186
if (type.equals(SimpleType.BOOL)) {
11511187
return (BoolExpr) ctx.mkApp(typeSystem.boolCons().getTesterDecl(), val);
11521188
}

0 commit comments

Comments
 (0)