diff --git a/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java b/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java index bacc027cd..dad6e0a97 100644 --- a/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java +++ b/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java @@ -28,12 +28,14 @@ import dev.cel.common.CelFunctionDecl; import dev.cel.common.CelIssue; import dev.cel.common.CelOverloadDecl; +import dev.cel.common.CelVarDecl; import dev.cel.common.ast.CelExpr; import dev.cel.common.types.ListType; import dev.cel.common.types.MapType; import dev.cel.common.types.OptionalType; import dev.cel.common.types.SimpleType; import dev.cel.common.types.TypeParamType; +import dev.cel.common.types.TypeType; import dev.cel.compiler.CelCompilerLibrary; import dev.cel.parser.CelMacro; import dev.cel.parser.CelMacroExprFactory; @@ -93,6 +95,11 @@ public void setCheckerOptions(CelCheckerBuilder checkerBuilder) { OptionalType optionalTypeV = OptionalType.create(paramTypeV); ListType listTypeV = ListType.create(paramTypeV); MapType mapTypeKv = MapType.create(paramTypeK, paramTypeV); + + // Type declaration for optional_type -> type(optional_type(V)) + checkerBuilder.addVarDeclarations( + CelVarDecl.newVarDeclaration(OptionalType.NAME, TypeType.create(optionalTypeV))); + checkerBuilder.addFunctionDeclarations( CelFunctionDecl.newFunctionDeclaration( Function.OPTIONAL_OF.getFunction(), diff --git a/extensions/src/test/java/dev/cel/extensions/BUILD.bazel b/extensions/src/test/java/dev/cel/extensions/BUILD.bazel index 7f572f58f..c2a362a81 100644 --- a/extensions/src/test/java/dev/cel/extensions/BUILD.bazel +++ b/extensions/src/test/java/dev/cel/extensions/BUILD.bazel @@ -27,6 +27,7 @@ java_library( "//parser:macro", "//runtime", "//runtime:interpreter_util", + "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", diff --git a/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java b/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java index 31df7a325..be215b645 100644 --- a/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java +++ b/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java @@ -17,6 +17,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; +import dev.cel.expr.Value; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.primitives.UnsignedLong; @@ -1409,4 +1410,23 @@ public void optionalFlatMapMacro_withNonIdent_throws() { .hasMessageThat() .contains("optFlatMap() variable name must be a simple identifier"); } + + @Test + public void optionalType_typeResolution() throws Exception { + Cel cel = newCelBuilder().build(); + + CelAbstractSyntaxTree ast = cel.compile("optional_type").getAst(); + + assertThat(cel.createProgram(ast).eval()) + .isEqualTo(Value.newBuilder().setTypeValue("optional_type").build()); + } + + @Test + public void optionalType_typeComparison() throws Exception { + Cel cel = newCelBuilder().build(); + + CelAbstractSyntaxTree ast = cel.compile("type(optional.none()) == optional_type").getAst(); + + assertThat(cel.createProgram(ast).eval()).isEqualTo(true); + } } diff --git a/runtime/src/main/java/dev/cel/runtime/StandardTypeResolver.java b/runtime/src/main/java/dev/cel/runtime/StandardTypeResolver.java index c0860f26b..3a46ebea5 100644 --- a/runtime/src/main/java/dev/cel/runtime/StandardTypeResolver.java +++ b/runtime/src/main/java/dev/cel/runtime/StandardTypeResolver.java @@ -34,6 +34,7 @@ import dev.cel.common.types.TypeType; import java.util.Collection; import java.util.Map; +import java.util.Optional; import org.jspecify.nullness.Nullable; /** @@ -76,6 +77,8 @@ private static ImmutableMap> commonTypes(boolean unsignedLongs) // Aggregate types. .put(createType("list"), Collection.class) .put(createType("map"), Map.class) + // Optional type + .put(createType("optional_type"), Optional.class) .buildOrThrow(); }