Skip to content

Commit 5ef40b9

Browse files
stanleyycheungcopybara-github
authored andcommitted
Handle AccumulatedUnknowns in execution plan.
PiperOrigin-RevId: 955923584
1 parent 310d96f commit 5ef40b9

6 files changed

Lines changed: 132 additions & 4 deletions

File tree

runtime/src/main/java/dev/cel/runtime/planner/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,7 @@ java_library(
446446
":planned_interpretable",
447447
"//common/ast",
448448
"//common/values",
449+
"//runtime:accumulated_unknowns",
449450
"//runtime:evaluation_exception",
450451
"//runtime:interpretable",
451452
"//runtime:resolved_overload",
@@ -957,6 +958,7 @@ cel_android_library(
957958
"//runtime:evaluation_exception",
958959
"//runtime:interpretable_android",
959960
"//runtime:resolved_overload_android",
961+
"//runtime/src/main/java/dev/cel/runtime:accumulated_unknowns_android",
960962
],
961963
)
962964

runtime/src/main/java/dev/cel/runtime/planner/EvalBinary.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ Object evalInternal(GlobalResolver resolver, ExecutionFrame frame) throws CelEva
4646
AccumulatedUnknowns unknowns = AccumulatedUnknowns.maybeMerge(null, argVal1);
4747
unknowns = AccumulatedUnknowns.maybeMerge(unknowns, argVal2);
4848

49-
if (unknowns != null) {
49+
if (unknowns != null && resolvedOverload.isStrict()) {
5050
return unknowns;
5151
}
5252

runtime/src/main/java/dev/cel/runtime/planner/EvalFold.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,15 @@ private Object evalMap(Map<?, ?> iterRange, Folder folder, ExecutionFrame frame)
105105
folder.iterVar2Val = entry.getValue();
106106
}
107107

108-
boolean cond = (boolean) condition.eval(folder, frame);
108+
Object condResult = condition.eval(folder, frame);
109+
if (condResult instanceof AccumulatedUnknowns) {
110+
return condResult;
111+
}
112+
if (!(condResult instanceof Boolean)) {
113+
throw new IllegalArgumentException(
114+
String.format("Expected boolean value, found :%s", condResult));
115+
}
116+
boolean cond = (boolean) condResult;
109117
if (!cond) {
110118
folder.computeResult = true;
111119
return result.eval(folder, frame);
@@ -131,7 +139,15 @@ private Object evalList(Collection<?> iterRange, Folder folder, ExecutionFrame f
131139
folder.iterVar2Val = item;
132140
}
133141

134-
boolean cond = (boolean) condition.eval(folder, frame);
142+
Object condResult = condition.eval(folder, frame);
143+
if (condResult instanceof AccumulatedUnknowns) {
144+
return condResult;
145+
}
146+
if (!(condResult instanceof Boolean)) {
147+
throw new IllegalArgumentException(
148+
String.format("Expected boolean value, found :%s", condResult));
149+
}
150+
boolean cond = (boolean) condResult;
135151
if (!cond) {
136152
folder.computeResult = true;
137153
return maybeUnwrapAccumulator(result.eval(folder, frame));

runtime/src/main/java/dev/cel/runtime/planner/EvalUnary.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import dev.cel.common.ast.CelExpr;
2121
import dev.cel.common.values.CelValueConverter;
22+
import dev.cel.runtime.AccumulatedUnknowns;
2223
import dev.cel.runtime.CelEvaluationException;
2324
import dev.cel.runtime.CelResolvedOverload;
2425
import dev.cel.runtime.GlobalResolver;
@@ -36,6 +37,12 @@ Object evalInternal(GlobalResolver resolver, ExecutionFrame frame) throws CelEva
3637
resolvedOverload.isStrict()
3738
? evalStrictly(arg, resolver, frame)
3839
: evalNonstrictly(arg, resolver, frame);
40+
41+
AccumulatedUnknowns unknowns = AccumulatedUnknowns.maybeMerge(null, argVal);
42+
if (unknowns != null && resolvedOverload.isStrict()) {
43+
return unknowns;
44+
}
45+
3946
return EvalHelpers.dispatch(functionName, resolvedOverload, celValueConverter, argVal);
4047
}
4148

runtime/src/main/java/dev/cel/runtime/planner/EvalVarArgsCall.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ Object evalInternal(GlobalResolver resolver, ExecutionFrame frame) throws CelEva
4848
unknowns = AccumulatedUnknowns.maybeMerge(unknowns, argVals[i]);
4949
}
5050

51-
if (unknowns != null) {
51+
if (unknowns != null && resolvedOverload.isStrict()) {
5252
return unknowns;
5353
}
5454

runtime/src/test/java/dev/cel/runtime/planner/ProgramPlannerTest.java

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,20 @@ private static DefaultDispatcher newDispatcher() {
210210
CelFunctionBinding.from("neg_int", Long.class, arg -> -arg),
211211
CelFunctionBinding.from("neg_double", Double.class, arg -> -arg)));
212212

213+
addBindingsToDispatcher(
214+
builder,
215+
CelFunctionBinding.fromOverloads(
216+
"add", CelFunctionBinding.from("add_int", Long.class, Long.class, (a, b) -> a + b)));
217+
218+
addBindingsToDispatcher(
219+
builder,
220+
CelFunctionBinding.fromOverloads(
221+
"func",
222+
CelFunctionBinding.from(
223+
"func_int",
224+
ImmutableList.of(Long.class, Long.class, Long.class),
225+
(args) -> (long) args.length)));
226+
213227
addBindingsToDispatcher(
214228
builder,
215229
CelFunctionBinding.fromOverloads(
@@ -977,6 +991,95 @@ public void plan_partialEval_withWildcardQualification() throws Exception {
977991
ImmutableSet.of(2L, 5L, 7L)));
978992
}
979993

994+
@Test
995+
public void plan_unaryFunction_withUnknownArg() throws Exception {
996+
CelCompiler compiler =
997+
CelCompilerFactory.standardCelCompilerBuilder()
998+
.addVar("unk", SimpleType.INT)
999+
.addFunctionDeclarations(
1000+
newFunctionDeclaration(
1001+
"neg", newGlobalOverload("neg_int", SimpleType.INT, SimpleType.INT)))
1002+
.build();
1003+
CelAbstractSyntaxTree ast = compile(compiler, "neg(unk)");
1004+
1005+
Program program = PLANNER.plan(ast);
1006+
1007+
CelUnknownSet result =
1008+
(CelUnknownSet) program.eval(PartialVars.of(CelAttributePattern.create("unk")));
1009+
1010+
assertThat(result)
1011+
.isEqualTo(
1012+
CelUnknownSet.create(ImmutableSet.of(CelAttribute.create("unk")), ImmutableSet.of(2L)));
1013+
}
1014+
1015+
@Test
1016+
public void plan_fold_withUnknownCondition() throws Exception {
1017+
CelCompiler compiler =
1018+
CelCompilerFactory.standardCelCompilerBuilder()
1019+
.setStandardMacros(CelStandardMacro.STANDARD_MACROS)
1020+
.addVar("unk", SimpleType.BOOL)
1021+
.build();
1022+
CelAbstractSyntaxTree ast = compile(compiler, "[1, 2].all(x, unk)");
1023+
1024+
Program program = PLANNER.plan(ast);
1025+
1026+
CelUnknownSet result =
1027+
(CelUnknownSet) program.eval(PartialVars.of(CelAttributePattern.create("unk")));
1028+
1029+
assertThat(result)
1030+
.isEqualTo(
1031+
CelUnknownSet.create(ImmutableSet.of(CelAttribute.create("unk")), ImmutableSet.of(6L)));
1032+
}
1033+
1034+
@Test
1035+
public void plan_binaryFunction_withUnknownArg() throws Exception {
1036+
CelCompiler compiler =
1037+
CelCompilerFactory.standardCelCompilerBuilder()
1038+
.addVar("unk", SimpleType.INT)
1039+
.addFunctionDeclarations(
1040+
newFunctionDeclaration(
1041+
"add",
1042+
newGlobalOverload("add_int", SimpleType.INT, SimpleType.INT, SimpleType.INT)))
1043+
.build();
1044+
CelAbstractSyntaxTree ast = compile(compiler, "add(1, unk)");
1045+
1046+
Program program = PLANNER.plan(ast);
1047+
1048+
CelUnknownSet result =
1049+
(CelUnknownSet) program.eval(PartialVars.of(CelAttributePattern.create("unk")));
1050+
1051+
assertThat(result)
1052+
.isEqualTo(
1053+
CelUnknownSet.create(ImmutableSet.of(CelAttribute.create("unk")), ImmutableSet.of(3L)));
1054+
}
1055+
1056+
@Test
1057+
public void plan_varargsFunction_withUnknownArg() throws Exception {
1058+
CelCompiler compiler =
1059+
CelCompilerFactory.standardCelCompilerBuilder()
1060+
.addVar("unk", SimpleType.INT)
1061+
.addFunctionDeclarations(
1062+
newFunctionDeclaration(
1063+
"func",
1064+
newGlobalOverload(
1065+
"func_int",
1066+
SimpleType.INT,
1067+
SimpleType.INT,
1068+
SimpleType.INT,
1069+
SimpleType.INT)))
1070+
.build();
1071+
CelAbstractSyntaxTree ast = compile(compiler, "func(1, 2, unk)");
1072+
1073+
Program program = PLANNER.plan(ast);
1074+
1075+
CelUnknownSet result =
1076+
(CelUnknownSet) program.eval(PartialVars.of(CelAttributePattern.create("unk")));
1077+
1078+
assertThat(result)
1079+
.isEqualTo(
1080+
CelUnknownSet.create(ImmutableSet.of(CelAttribute.create("unk")), ImmutableSet.of(4L)));
1081+
}
1082+
9801083
@Test
9811084
public void localShadowIdentifier_inSelect() throws Exception {
9821085
CelCompiler celCompiler =

0 commit comments

Comments
 (0)