Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion checker/src/main/java/dev/cel/checker/ExprChecker.java
Original file line number Diff line number Diff line change
Expand Up @@ -705,7 +705,7 @@ private CelExpr visitOptionalCall(CelExpr expr, CelExpr.CelCall call) {
CelExpr visitedOperand = visit(operand);
if (namespacedDeclarations && !operand.equals(visitedOperand)) {
// Subtree has been rewritten. Replace the operand.
expr = replaceSelectOperandSubtree(expr, visitedOperand);
expr = replaceCallArgumentSubtree(expr, visitedOperand, 0);
}
CelType resultType = visitSelectField(expr, operand, field.constant().stringValue(), true);
env.setType(expr, resultType);
Expand Down
1 change: 1 addition & 0 deletions extensions/src/test/java/dev/cel/extensions/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ java_library(
"//extensions:strings",
"//parser:macro",
"//runtime",
"//runtime:interpreter_util",
"@maven//:com_google_guava_guava",
"@maven//:com_google_protobuf_protobuf_java",
"@maven//:com_google_protobuf_protobuf_java_util",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import dev.cel.runtime.CelEvaluationException;
import dev.cel.runtime.CelRuntime;
import dev.cel.runtime.CelRuntime.CelFunctionBinding;
import dev.cel.runtime.InterpreterUtil;
import dev.cel.testing.testdata.proto2.TestAllTypesProto.TestAllTypes;
import dev.cel.testing.testdata.proto2.TestAllTypesProto.TestAllTypes.NestedMessage;
import java.util.List;
Expand Down Expand Up @@ -766,6 +767,38 @@ public void optionalIndex_onMap_returnsOptionalValue() throws Exception {
assertThat(result).isEqualTo(Optional.of("goodbye"));
}

@Test
@TestParameters("{source: '{?x: optional.of(1)}'}")
@TestParameters("{source: '{?1: x}'}")
@TestParameters("{source: '{?x: x}'}")
public void optionalIndex_onMapWithUnknownInput_returnsUnknownResult(String source)
throws Exception {
Cel cel = newCelBuilder().addVar("x", OptionalType.create(SimpleType.INT)).build();
CelAbstractSyntaxTree ast = cel.compile(source).getAst();

Object result = cel.createProgram(ast).eval();

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

@Test
public void optionalIndex_onOptionalMapUsingFieldSelection_returnsOptionalValue()
throws Exception {
Cel cel =
newCelBuilder()
.addVar(
"m",
MapType.create(
SimpleType.STRING, MapType.create(SimpleType.STRING, SimpleType.STRING)))
.setResultType(OptionalType.create(SimpleType.STRING))
.build();
CelAbstractSyntaxTree ast = cel.compile("{?'key': optional.of('test')}.?key").getAst();

Object result = cel.createProgram(ast).eval();

assertThat(result).isEqualTo(Optional.of("test"));
}

@Test
public void optionalIndex_onList_returnsOptionalEmpty() throws Exception {
Cel cel =
Expand Down Expand Up @@ -824,6 +857,20 @@ public void optionalIndex_onOptionalList_returnsOptionalValue() throws Exception
assertThat(result).isEqualTo(Optional.of("hello"));
}

@Test
public void optionalIndex_onListWithUnknownInput_returnsUnknownResult() throws Exception {
Cel cel =
newCelBuilder()
.addVar("x", OptionalType.create(SimpleType.INT))
.setResultType(ListType.create(SimpleType.INT))
.build();
CelAbstractSyntaxTree ast = cel.compile("[?x]").getAst();

Object result = cel.createProgram(ast).eval();

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

@Test
public void traditionalIndex_onOptionalList_returnsOptionalEmpty() throws Exception {
Cel cel =
Expand Down
4 changes: 2 additions & 2 deletions runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ private IntermediateResult evalList(

argChecker.checkArg(evaluatedElement);
Object value = evaluatedElement.value();
if (optionalIndicesSet.contains(i)) {
if (optionalIndicesSet.contains(i) && !isUnknownValue(value)) {
Optional<?> optionalVal = (Optional<?>) value;
if (!optionalVal.isPresent()) {
continue;
Expand Down Expand Up @@ -712,7 +712,7 @@ private IntermediateResult evalMap(ExecutionFrame frame, CelCreateMap mapExpr)
}

Object value = valueResult.value();
if (entry.optionalEntry()) {
if (entry.optionalEntry() && !isUnknownValue(value)) {
Optional<?> optionalVal = (Optional<?>) value;
if (!optionalVal.isPresent()) {
// This is a no-op currently but will be semantically correct when extended proto
Expand Down