Skip to content

Commit 38948bb

Browse files
l46kokcopybara-github
authored andcommitted
Support partial evaluation via unknowns in planner
PiperOrigin-RevId: 877616092
1 parent b3663bf commit 38948bb

44 files changed

Lines changed: 1667 additions & 323 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

extensions/src/test/java/dev/cel/extensions/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ java_library(
3838
"//runtime:interpreter_util",
3939
"//runtime:lite_runtime",
4040
"//runtime:lite_runtime_factory",
41+
"//runtime:partial_vars",
42+
"//runtime:unknown_attributes",
4143
"@cel_spec//proto/cel/expr/conformance/proto2:test_all_types_java_proto",
4244
"@cel_spec//proto/cel/expr/conformance/proto3:test_all_types_java_proto",
4345
"@cel_spec//proto/cel/expr/conformance/test:simple_java_proto",

extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,12 @@
4949
import dev.cel.expr.conformance.proto3.TestAllTypes.NestedMessage;
5050
import dev.cel.parser.CelMacro;
5151
import dev.cel.parser.CelStandardMacro;
52+
import dev.cel.runtime.CelAttributePattern;
5253
import dev.cel.runtime.CelEvaluationException;
5354
import dev.cel.runtime.CelFunctionBinding;
5455
import dev.cel.runtime.CelRuntime;
5556
import dev.cel.runtime.InterpreterUtil;
57+
import dev.cel.runtime.PartialVars;
5658
import java.time.Duration;
5759
import java.time.Instant;
5860
import java.util.List;
@@ -897,14 +899,12 @@ public void optionalIndex_onMap_returnsOptionalValue() throws Exception {
897899
@TestParameters("{source: '{?x: x}'}")
898900
public void optionalIndex_onMapWithUnknownInput_returnsUnknownResult(String source)
899901
throws Exception {
900-
if (testMode.equals(TestMode.PLANNER_CHECKED) || testMode.equals(TestMode.PLANNER_PARSE_ONLY)) {
901-
// TODO: Uncomment once unknowns is implemented
902-
return;
903-
}
904902
Cel cel = newCelBuilder().addVar("x", OptionalType.create(SimpleType.INT)).build();
905903
CelAbstractSyntaxTree ast = compile(cel, source);
906904

907-
Object result = cel.createProgram(ast).eval();
905+
Object result =
906+
cel.createProgram(ast)
907+
.eval(PartialVars.of(CelAttributePattern.fromQualifiedIdentifier("x")));
908908

909909
assertThat(InterpreterUtil.isUnknown(result)).isTrue();
910910
}
@@ -987,18 +987,16 @@ public void optionalIndex_onOptionalList_returnsOptionalValue() throws Exception
987987

988988
@Test
989989
public void optionalIndex_onListWithUnknownInput_returnsUnknownResult() throws Exception {
990-
if (testMode.equals(TestMode.PLANNER_CHECKED) || testMode.equals(TestMode.PLANNER_PARSE_ONLY)) {
991-
// TODO: Uncomment once unknowns is implemented
992-
return;
993-
}
994990
Cel cel =
995991
newCelBuilder()
996992
.addVar("x", OptionalType.create(SimpleType.INT))
997993
.setResultType(ListType.create(SimpleType.INT))
998994
.build();
999995
CelAbstractSyntaxTree ast = compile(cel, "[?x]");
1000996

1001-
Object result = cel.createProgram(ast).eval();
997+
Object result =
998+
cel.createProgram(ast)
999+
.eval(PartialVars.of(CelAttributePattern.fromQualifiedIdentifier("x")));
10021000

10031001
assertThat(InterpreterUtil.isUnknown(result)).isTrue();
10041002
}
@@ -1017,6 +1015,29 @@ public void traditionalIndex_onOptionalList_returnsOptionalEmpty() throws Except
10171015
assertThat(result).isEqualTo(Optional.empty());
10181016
}
10191017

1018+
@Test
1019+
public void optionalFieldSelect_fieldMarkedUnknown_returnsUnknownSet() throws Exception {
1020+
if (testMode.equals(TestMode.LEGACY_CHECKED)) {
1021+
// This case is not possible to setup for legacy runtime
1022+
return;
1023+
}
1024+
1025+
Cel cel =
1026+
newCelBuilder()
1027+
.addVar("msg", StructTypeReference.create(TestAllTypes.getDescriptor().getFullName()))
1028+
.build();
1029+
CelAbstractSyntaxTree ast = compile(cel, "msg.?single_int32");
1030+
1031+
Object result =
1032+
cel.createProgram(ast)
1033+
.eval(
1034+
PartialVars.of(
1035+
ImmutableMap.of("msg", TestAllTypes.newBuilder().setSingleInt32(42).build()),
1036+
CelAttributePattern.fromQualifiedIdentifier("msg.single_int32")));
1037+
1038+
assertThat(InterpreterUtil.isUnknown(result)).isTrue();
1039+
}
1040+
10201041
@Test
10211042
// LHS
10221043
@TestParameters("{expression: 'optx.or(optional.of(1))'}")
@@ -1026,18 +1047,16 @@ public void traditionalIndex_onOptionalList_returnsOptionalEmpty() throws Except
10261047
@TestParameters("{expression: 'optional.none().orValue(optx)'}")
10271048
public void optionalChainedFunctions_lhsIsUnknown_returnsUnknown(String expression)
10281049
throws Exception {
1029-
if (testMode.equals(TestMode.PLANNER_CHECKED) || testMode.equals(TestMode.PLANNER_PARSE_ONLY)) {
1030-
// TODO: Uncomment once unknowns is implemented
1031-
return;
1032-
}
10331050
Cel cel =
10341051
newCelBuilder()
10351052
.addVar("optx", OptionalType.create(SimpleType.INT))
10361053
.addVar("x", SimpleType.INT)
10371054
.build();
10381055
CelAbstractSyntaxTree ast = compile(cel, expression);
10391056

1040-
Object result = cel.createProgram(ast).eval();
1057+
Object result =
1058+
cel.createProgram(ast)
1059+
.eval(PartialVars.of(CelAttributePattern.fromQualifiedIdentifier("optx")));
10411060

10421061
assertThat(InterpreterUtil.isUnknown(result)).isTrue();
10431062
}

runtime/BUILD.bazel

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,3 +351,17 @@ java_library(
351351
"//runtime/src/main/java/dev/cel/runtime:runtime_planner_impl",
352352
],
353353
)
354+
355+
java_library(
356+
name = "accumulated_unknowns",
357+
visibility = ["//:internal"],
358+
exports = [
359+
"//runtime/src/main/java/dev/cel/runtime:accumulated_unknowns",
360+
],
361+
)
362+
363+
java_library(
364+
name = "partial_vars",
365+
visibility = ["//:internal"],
366+
exports = ["//runtime/src/main/java/dev/cel/runtime:partial_vars"],
367+
)

runtime/src/main/java/dev/cel/runtime/AccumulatedUnknowns.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,36 +26,36 @@
2626
* safety, this object should never be returned as an evaluated result and instead be adapted into
2727
* an immutable CelUnknownSet.
2828
*/
29-
final class AccumulatedUnknowns {
29+
public final class AccumulatedUnknowns {
3030
private static final int MAX_UNKNOWN_ATTRIBUTE_SIZE = 500_000;
3131
private final Set<Long> exprIds;
3232
private final Set<CelAttribute> attributes;
3333

34-
Set<Long> exprIds() {
34+
public Set<Long> exprIds() {
3535
return exprIds;
3636
}
3737

38-
Set<CelAttribute> attributes() {
38+
public Set<CelAttribute> attributes() {
3939
return attributes;
4040
}
4141

4242
@CanIgnoreReturnValue
43-
AccumulatedUnknowns merge(AccumulatedUnknowns arg) {
43+
public AccumulatedUnknowns merge(AccumulatedUnknowns arg) {
4444
enforceMaxAttributeSize(this.attributes, arg.attributes);
4545
this.exprIds.addAll(arg.exprIds);
4646
this.attributes.addAll(arg.attributes);
4747
return this;
4848
}
4949

50-
static AccumulatedUnknowns create(Long... ids) {
50+
public static AccumulatedUnknowns create(Long... ids) {
5151
return create(Arrays.asList(ids));
5252
}
5353

54-
static AccumulatedUnknowns create(Collection<Long> ids) {
54+
public static AccumulatedUnknowns create(Collection<Long> ids) {
5555
return create(ids, new ArrayList<>());
5656
}
5757

58-
static AccumulatedUnknowns create(Collection<Long> exprIds, Collection<CelAttribute> attributes) {
58+
public static AccumulatedUnknowns create(Collection<Long> exprIds, Collection<CelAttribute> attributes) {
5959
return new AccumulatedUnknowns(new HashSet<>(exprIds), new HashSet<>(attributes));
6060
}
6161

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

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,7 @@ java_library(
826826
":evaluation_listener",
827827
":function_binding",
828828
":function_resolver",
829+
":partial_vars",
829830
":program",
830831
":proto_message_runtime_equality",
831832
":runtime",
@@ -938,6 +939,7 @@ java_library(
938939
":function_resolver",
939940
":interpretable",
940941
":interpreter",
942+
":partial_vars",
941943
":program",
942944
":proto_message_activation_factory",
943945
":runtime_equality",
@@ -955,7 +957,6 @@ java_library(
955957
"@maven//:com_google_errorprone_error_prone_annotations",
956958
"@maven//:com_google_guava_guava",
957959
"@maven//:com_google_protobuf_protobuf_java",
958-
"@maven//:org_jspecify_jspecify",
959960
],
960961
)
961962

@@ -1014,6 +1015,7 @@ java_library(
10141015
":evaluation_exception",
10151016
":function_resolver",
10161017
":interpretable",
1018+
":partial_vars",
10171019
":program",
10181020
":variable_resolver",
10191021
"//:auto_value",
@@ -1029,6 +1031,7 @@ cel_android_library(
10291031
":evaluation_exception",
10301032
":function_resolver_android",
10311033
":interpretable_android",
1034+
":partial_vars_android",
10321035
":program_android",
10331036
":variable_resolver",
10341037
"//:auto_value",
@@ -1199,6 +1202,7 @@ java_library(
11991202
":unknown_attributes",
12001203
"//common/annotations",
12011204
"@maven//:com_google_errorprone_error_prone_annotations",
1205+
"@maven//:com_google_guava_guava",
12021206
"@maven//:org_jspecify_jspecify",
12031207
],
12041208
)
@@ -1214,6 +1218,7 @@ cel_android_library(
12141218
"//common/annotations",
12151219
"@maven//:com_google_errorprone_error_prone_annotations",
12161220
"@maven//:org_jspecify_jspecify",
1221+
"@maven_android//:com_google_guava_guava",
12171222
],
12181223
)
12191224

@@ -1273,7 +1278,8 @@ java_library(
12731278
java_library(
12741279
name = "accumulated_unknowns",
12751280
srcs = ["AccumulatedUnknowns.java"],
1276-
visibility = ["//visibility:private"],
1281+
tags = [
1282+
],
12771283
deps = [
12781284
":unknown_attributes",
12791285
"@maven//:com_google_errorprone_error_prone_annotations",
@@ -1318,6 +1324,34 @@ cel_android_library(
13181324
],
13191325
)
13201326

1327+
java_library(
1328+
name = "partial_vars",
1329+
srcs = ["PartialVars.java"],
1330+
tags = [
1331+
],
1332+
deps = [
1333+
":variable_resolver",
1334+
"//:auto_value",
1335+
"//runtime:unknown_attributes",
1336+
"@maven//:com_google_errorprone_error_prone_annotations",
1337+
"@maven//:com_google_guava_guava",
1338+
],
1339+
)
1340+
1341+
cel_android_library(
1342+
name = "partial_vars_android",
1343+
srcs = ["PartialVars.java"],
1344+
tags = [
1345+
],
1346+
deps = [
1347+
":variable_resolver",
1348+
"//:auto_value",
1349+
"//runtime:unknown_attributes_android",
1350+
"@maven//:com_google_errorprone_error_prone_annotations",
1351+
"@maven_android//:com_google_guava_guava",
1352+
],
1353+
)
1354+
13211355
java_library(
13221356
name = "program",
13231357
srcs = ["Program.java"],
@@ -1326,6 +1360,7 @@ java_library(
13261360
deps = [
13271361
":evaluation_exception",
13281362
":function_resolver",
1363+
":partial_vars",
13291364
":variable_resolver",
13301365
"@maven//:com_google_errorprone_error_prone_annotations",
13311366
],
@@ -1339,8 +1374,8 @@ cel_android_library(
13391374
deps = [
13401375
":evaluation_exception",
13411376
":function_resolver_android",
1377+
":partial_vars_android",
13421378
":variable_resolver",
1343-
"//:auto_value",
13441379
"@maven//:com_google_errorprone_error_prone_annotations",
13451380
],
13461381
)

runtime/src/main/java/dev/cel/runtime/CelRuntimeImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,11 @@ public Object eval(
134134
return program.eval(resolver, lateBoundFunctionResolver);
135135
}
136136

137+
@Override
138+
public Object eval(PartialVars partialVars) throws CelEvaluationException {
139+
return program.eval(partialVars);
140+
}
141+
137142
@Override
138143
public Object trace(CelEvaluationListener listener) throws CelEvaluationException {
139144
throw new UnsupportedOperationException("Trace is not yet supported.");

runtime/src/main/java/dev/cel/runtime/CelUnknownSet.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ static CelUnknownSet create(Iterable<Long> unknownExprIds) {
5959
return create(ImmutableSet.of(), ImmutableSet.copyOf(unknownExprIds));
6060
}
6161

62-
static CelUnknownSet create(
62+
public static CelUnknownSet create(
6363
ImmutableSet<CelAttribute> attributes, ImmutableSet<Long> unknownExprIds) {
6464
return new AutoValue_CelUnknownSet(attributes, unknownExprIds);
6565
}

runtime/src/main/java/dev/cel/runtime/InterpreterUtil.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
package dev.cel.runtime;
1616

17+
import com.google.common.collect.ImmutableSet;
1718
import com.google.errorprone.annotations.CheckReturnValue;
1819
import dev.cel.common.annotations.Internal;
1920
import org.jspecify.annotations.Nullable;
@@ -55,23 +56,33 @@ public static boolean isUnknown(Object obj) {
5556
return obj instanceof CelUnknownSet;
5657
}
5758

58-
static boolean isAccumulatedUnknowns(Object obj) {
59+
public static boolean isAccumulatedUnknowns(Object obj) {
5960
return obj instanceof AccumulatedUnknowns;
6061
}
6162

6263
/** If the argument is {@link CelUnknownSet}, adapts it into {@link AccumulatedUnknowns} */
63-
static Object maybeAdaptToAccumulatedUnknowns(Object val) {
64+
public static Object maybeAdaptToAccumulatedUnknowns(Object val) {
6465
if (!(val instanceof CelUnknownSet)) {
6566
return val;
6667
}
6768

6869
return adaptToAccumulatedUnknowns((CelUnknownSet) val);
6970
}
7071

71-
static AccumulatedUnknowns adaptToAccumulatedUnknowns(CelUnknownSet unknowns) {
72+
public static AccumulatedUnknowns adaptToAccumulatedUnknowns(CelUnknownSet unknowns) {
7273
return AccumulatedUnknowns.create(unknowns.unknownExprIds(), unknowns.attributes());
7374
}
7475

76+
public static Object maybeAdaptToCelUnknownSet(Object val) {
77+
if (!(val instanceof AccumulatedUnknowns)) {
78+
return val;
79+
}
80+
81+
AccumulatedUnknowns unknowns = (AccumulatedUnknowns) val;
82+
return CelUnknownSet.create(
83+
ImmutableSet.copyOf(unknowns.attributes()), ImmutableSet.copyOf(unknowns.exprIds()));
84+
}
85+
7586
/**
7687
* Enforces strictness on both lhs/rhs arguments from logical operators (i.e: intentionally throws
7788
* an appropriate exception when {@link Throwable} is encountered as part of evaluated result.

runtime/src/main/java/dev/cel/runtime/LiteProgramImpl.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ public Object eval(CelVariableResolver resolver) throws CelEvaluationException {
5252
throw new UnsupportedOperationException("To be implemented");
5353
}
5454

55+
@Override
56+
public Object eval(PartialVars partialVars) throws CelEvaluationException {
57+
// TODO: Wire in program planner
58+
throw new UnsupportedOperationException("To be implemented");
59+
}
60+
5561
static Program plan(Interpretable interpretable) {
5662
return new AutoValue_LiteProgramImpl(interpretable);
5763
}

0 commit comments

Comments
 (0)