Skip to content

Commit 174bce0

Browse files
l46kokcopybara-github
authored andcommitted
Refactor type-checker to use canonical CelTypeProvider
PiperOrigin-RevId: 862321687
1 parent 83e91cc commit 174bce0

File tree

11 files changed

+234
-271
lines changed

11 files changed

+234
-271
lines changed

bundle/src/test/java/dev/cel/bundle/CelImplTest.java

Lines changed: 21 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import dev.cel.expr.Reference;
3636
import dev.cel.expr.Type;
3737
import dev.cel.expr.Type.PrimitiveType;
38+
import com.google.common.collect.ImmutableCollection;
3839
import com.google.common.collect.ImmutableList;
3940
import com.google.common.collect.ImmutableMap;
4041
import com.google.common.collect.ImmutableSet;
@@ -63,7 +64,6 @@
6364
import dev.cel.checker.CelCheckerLegacyImpl;
6465
import dev.cel.checker.DescriptorTypeProvider;
6566
import dev.cel.checker.ProtoTypeMask;
66-
import dev.cel.checker.TypeProvider;
6767
import dev.cel.common.CelAbstractSyntaxTree;
6868
import dev.cel.common.CelContainer;
6969
import dev.cel.common.CelDescriptorUtil;
@@ -82,12 +82,14 @@
8282
import dev.cel.common.types.CelProtoMessageTypes;
8383
import dev.cel.common.types.CelProtoTypes;
8484
import dev.cel.common.types.CelType;
85+
import dev.cel.common.types.CelTypeProvider;
8586
import dev.cel.common.types.EnumType;
8687
import dev.cel.common.types.ListType;
8788
import dev.cel.common.types.MapType;
8889
import dev.cel.common.types.OptionalType;
8990
import dev.cel.common.types.ProtoMessageTypeProvider;
9091
import dev.cel.common.types.SimpleType;
92+
import dev.cel.common.types.StructType;
9193
import dev.cel.common.types.StructTypeReference;
9294
import dev.cel.common.values.CelByteString;
9395
import dev.cel.common.values.NullValue;
@@ -123,7 +125,6 @@
123125
import java.util.concurrent.Executors;
124126
import java.util.concurrent.Future;
125127
import java.util.concurrent.ThreadPoolExecutor;
126-
import org.jspecify.annotations.Nullable;
127128
import org.junit.Assert;
128129
import org.junit.Test;
129130
import org.junit.runner.RunWith;
@@ -297,13 +298,12 @@ public void compile_customTypeProvider() {
297298

298299
@Test
299300
public void compile_customTypesWithAliasingCombinedProviders() throws Exception {
300-
301301
// The custom type provider sets up an alias from "Condition" to "google.type.Expr".
302302
// However, the first type resolution from the alias to the qualified type name won't be
303303
// sufficient as future checks will expect the resolved alias to also be a type.
304-
TypeProvider customTypeProvider =
304+
CelTypeProvider customTypeProvider =
305305
aliasingProvider(
306-
ImmutableMap.of("Condition", CelProtoTypes.createMessage("google.type.Expr")));
306+
ImmutableMap.of("Condition", StructTypeReference.create("google.type.Expr")));
307307

308308
// The registration of the aliasing TypeProvider and the google.type.Expr descriptor
309309
// ensures that once the alias is resolved, the additional details about the Expr type
@@ -329,15 +329,19 @@ public void compile_customTypesWithAliasingCombinedProviders() throws Exception
329329

330330
@Test
331331
public void compile_customTypesWithAliasingSelfContainedProvider() throws Exception {
332-
333332
// The custom type provider sets up an alias from "Condition" to "google.type.Expr".
334-
TypeProvider customTypeProvider =
333+
StructType exprStruct = StructType.create(
334+
"google.type.Expr",
335+
ImmutableSet.of("expression"),
336+
fieldName -> Optional.of(SimpleType.STRING)
337+
);
338+
CelTypeProvider customTypeProvider =
335339
aliasingProvider(
336340
ImmutableMap.of(
337341
"Condition",
338-
CelProtoTypes.createMessage("google.type.Expr"),
342+
exprStruct,
339343
"google.type.Expr",
340-
CelProtoTypes.createMessage("google.type.Expr")));
344+
exprStruct));
341345

342346
// The registration of the aliasing TypeProvider and the google.type.Expr descriptor
343347
// ensures that once the alias is resolved, the additional details about the Expr type
@@ -1001,14 +1005,11 @@ public void program_protoActivation() throws Exception {
10011005
}
10021006

10031007
@Test
1004-
@TestParameters("{resolveTypeDependencies: false}")
1005-
@TestParameters("{resolveTypeDependencies: true}")
1006-
public void program_enumTypeDirectResolution(boolean resolveTypeDependencies) throws Exception {
1008+
public void program_enumTypeDirectResolution() throws Exception {
10071009
Cel cel =
10081010
standardCelBuilderWithMacros()
10091011
.addFileTypes(StandaloneGlobalEnum.getDescriptor().getFile())
1010-
.setOptions(
1011-
CelOptions.current().resolveTypeDependencies(resolveTypeDependencies).build())
1012+
.setOptions(CelOptions.current().resolveTypeDependencies(true).build())
10121013
.setContainer(
10131014
CelContainer.ofName("dev.cel.testing.testdata.proto3.StandaloneGlobalEnum"))
10141015
.setResultType(SimpleType.BOOL)
@@ -2193,28 +2194,16 @@ public void toBuilder_isImmutable() {
21932194
assertThat(newRuntimeBuilder).isNotEqualTo(celImpl.toRuntimeBuilder());
21942195
}
21952196

2196-
private static TypeProvider aliasingProvider(ImmutableMap<String, Type> typeAliases) {
2197-
return new TypeProvider() {
2198-
@Override
2199-
public @Nullable Type lookupType(String typeName) {
2200-
Type alias = typeAliases.get(typeName);
2201-
if (alias != null) {
2202-
return CelProtoTypes.create(alias);
2203-
}
2204-
return null;
2205-
}
2206-
2197+
private static CelTypeProvider aliasingProvider(ImmutableMap<String, CelType> typeAliases) {
2198+
return new CelTypeProvider() {
22072199
@Override
2208-
public @Nullable Integer lookupEnumValue(String enumName) {
2209-
return null;
2200+
public ImmutableCollection<CelType> types() {
2201+
return typeAliases.values();
22102202
}
22112203

22122204
@Override
2213-
public TypeProvider.@Nullable FieldType lookupFieldType(Type type, String fieldName) {
2214-
if (typeAliases.containsKey(type.getMessageType())) {
2215-
return TypeProvider.FieldType.of(CelProtoTypes.STRING);
2216-
}
2217-
return null;
2205+
public Optional<CelType> findType(String typeName) {
2206+
return Optional.ofNullable(typeAliases.get(typeName));
22182207
}
22192208
};
22202209
}

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ CHECKER_LEGACY_ENV_SOURCES = [
3232
"InferenceContext.java",
3333
"TypeFormatter.java",
3434
"TypeProvider.java",
35+
"TypeProviderLegacyImpl.java",
3536
"Types.java",
3637
]
3738

@@ -70,7 +71,6 @@ java_library(
7071
":checker_legacy_environment",
7172
":proto_type_mask",
7273
":standard_decl",
73-
":type_provider_legacy_impl",
7474
"//:auto_value",
7575
"//common:cel_ast",
7676
"//common:cel_descriptor_util",
@@ -158,12 +158,9 @@ java_library(
158158
"//:auto_value",
159159
"//common/annotations",
160160
"//common/types",
161-
"//common/types:cel_proto_types",
162161
"//common/types:type_providers",
163-
"@cel_spec//proto/cel/expr:checked_java_proto",
164162
"@maven//:com_google_errorprone_error_prone_annotations",
165163
"@maven//:com_google_guava_guava",
166-
"@maven//:org_jspecify_jspecify",
167164
],
168165
)
169166

@@ -190,6 +187,7 @@ java_library(
190187
"//common/types",
191188
"//common/types:cel_proto_types",
192189
"//common/types:cel_types",
190+
"//common/types:message_type_provider",
193191
"//common/types:type_providers",
194192
"//parser:macro",
195193
"@cel_spec//proto/cel/expr:checked_java_proto",

checker/src/main/java/dev/cel/checker/CelCheckerLegacyImpl.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -163,11 +163,11 @@ public void accept(EnvVisitor envVisitor) {
163163
private Env getEnv(Errors errors) {
164164
Env env;
165165
if (standardEnvironmentEnabled) {
166-
env = Env.standard(errors, typeProvider, celOptions);
166+
env = Env.standard(errors, celTypeProvider, celOptions);
167167
} else if (overriddenStandardDeclarations != null) {
168-
env = Env.standard(overriddenStandardDeclarations, errors, typeProvider, celOptions);
168+
env = Env.standard(overriddenStandardDeclarations, errors, celTypeProvider, celOptions);
169169
} else {
170-
env = Env.unconfigured(errors, typeProvider, celOptions);
170+
env = Env.unconfigured(errors, celTypeProvider, celOptions);
171171
}
172172
identDeclarations.forEach(env::add);
173173
functionDeclarations.forEach(env::add);
@@ -483,11 +483,10 @@ public CelCheckerLegacyImpl build() {
483483
messageTypeProvider = protoTypeMaskTypeProvider;
484484
}
485485

486-
TypeProvider legacyProvider = new TypeProviderLegacyImpl(messageTypeProvider);
487486
if (customTypeProvider != null) {
488-
legacyProvider =
489-
new TypeProvider.CombinedTypeProvider(
490-
ImmutableList.of(customTypeProvider, legacyProvider));
487+
messageTypeProvider =
488+
new CelTypeProvider.CombinedCelTypeProvider(
489+
messageTypeProvider, new TypeProviderLegacyImpl(customTypeProvider));
491490
}
492491

493492
return new CelCheckerLegacyImpl(
@@ -496,7 +495,7 @@ public CelCheckerLegacyImpl build() {
496495
identDeclarationSet,
497496
functionDeclarations.build(),
498497
Optional.fromNullable(expectedResultType),
499-
legacyProvider,
498+
customTypeProvider,
500499
messageTypeProvider,
501500
standardEnvironmentEnabled,
502501
standardDeclarations,

checker/src/main/java/dev/cel/checker/DescriptorTypeProvider.java

Lines changed: 65 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import com.google.auto.value.AutoValue;
1919
import com.google.common.base.Ascii;
2020
import com.google.common.base.Joiner;
21+
import com.google.common.collect.ImmutableCollection;
2122
import com.google.common.collect.ImmutableList;
2223
import com.google.common.collect.ImmutableMap;
2324
import com.google.common.collect.ImmutableSet;
@@ -32,28 +33,29 @@
3233
import com.google.protobuf.Descriptors.FieldDescriptor;
3334
import com.google.protobuf.Descriptors.FileDescriptor;
3435
import com.google.protobuf.Descriptors.OneofDescriptor;
35-
import dev.cel.common.annotations.Internal;
3636
import dev.cel.common.internal.FileDescriptorSetConverter;
37+
import dev.cel.common.types.CelProtoTypes;
38+
import dev.cel.common.types.CelType;
39+
import dev.cel.common.types.ProtoMessageType;
40+
import dev.cel.common.types.TypeType;
3741
import java.util.ArrayList;
3842
import java.util.Collection;
3943
import java.util.HashMap;
4044
import java.util.HashSet;
4145
import java.util.List;
4246
import java.util.Map;
47+
import java.util.Optional;
4348
import java.util.Set;
4449
import org.jspecify.annotations.Nullable;
4550

4651
/**
4752
* The {@code DescriptorTypeProvider} provides type information for one or more {@link Descriptor}
4853
* instances of proto messages.
4954
*
50-
* <p>TODO: Unify implementation across the runtime (i.e: DescriptorMessageProvider)
51-
* and the compilation. This class can likely be eliminated as part of the work.
52-
*
53-
* <p>CEL Library Internals. Do Not Use.
55+
* @deprecated Do not use. Migrate to {@code ProtoMessageTypeProvider).
5456
*/
5557
@Immutable
56-
@Internal
58+
@Deprecated
5759
public class DescriptorTypeProvider implements TypeProvider {
5860

5961
@SuppressWarnings("Immutable")
@@ -86,6 +88,45 @@ public DescriptorTypeProvider(Iterable<Descriptor> descriptors) {
8688
return typeDef != null ? Types.create(Types.createMessage(typeDef.name())) : null;
8789
}
8890

91+
@Override
92+
public Optional<TypeType> lookupCelType(String typeName) {
93+
TypeDef typeDef = lookupMessageTypeDef(typeName);
94+
if (typeDef == null) {
95+
return Optional.empty();
96+
}
97+
98+
ImmutableSet.Builder<String> fieldsBuilder = ImmutableSet.builder();
99+
for (FieldDef fieldDef : typeDef.fields()) {
100+
fieldsBuilder.add(fieldDef.name());
101+
}
102+
103+
@SuppressWarnings("Immutable")
104+
ProtoMessageType protoMessageType =
105+
ProtoMessageType.create(
106+
typeName,
107+
fieldsBuilder.build(),
108+
fieldName -> {
109+
FieldDef fieldDef = typeDef.lookupField(fieldName);
110+
if (fieldDef == null) {
111+
return Optional.empty();
112+
}
113+
114+
Type type = fieldDefToType(fieldDef);
115+
return Optional.of(CelProtoTypes.typeToCelType(type));
116+
},
117+
extensionFieldName -> {
118+
ExtensionFieldType extensionFieldType =
119+
symbolTable.lookupExtension(extensionFieldName);
120+
if (extensionFieldType == null) {
121+
return Optional.empty();
122+
}
123+
124+
return Optional.of(extensionFieldType.fieldType().celType());
125+
});
126+
127+
return Optional.of(TypeType.create(protoMessageType));
128+
}
129+
89130
@Override
90131
public @Nullable Integer lookupEnumValue(String enumName) {
91132
int dot = enumName.lastIndexOf('.');
@@ -339,6 +380,8 @@ private TypeDef buildTypeDef(EnumDescriptor descriptor, Map<String, TypeDef> typ
339380

340381
/** Value object for a proto-based primitive, message, or enum definition. */
341382
@AutoValue
383+
@AutoValue.CopyAnnotations
384+
@SuppressWarnings("Immutable")
342385
protected abstract static class TypeDef {
343386

344387
/** The qualified name of the message or enum. */
@@ -434,12 +477,28 @@ static TypeDef ofEnum(String name, Iterable<EnumValueDef> enumValues) {
434477
}
435478
}
436479

480+
@Override
481+
public ImmutableCollection<CelType> types() {
482+
ImmutableList.Builder<CelType> typesBuilder = ImmutableList.builder();
483+
for (TypeDef typeDef : symbolTable.typeMap.values()) {
484+
TypeType typeType = lookupCelType(typeDef.name()).orElse(null);
485+
if (typeType == null) {
486+
continue;
487+
}
488+
489+
typesBuilder.add(typeType.type());
490+
}
491+
492+
return typesBuilder.build();
493+
}
494+
437495
/**
438496
* Value object for a proto-based field definition.
439497
*
440498
* <p>Only one of the {@link #type} or {@link #mapEntryType} may be set.
441499
*/
442500
@AutoValue
501+
@AutoValue.CopyAnnotations
443502
protected abstract static class FieldDef {
444503

445504
/** The field name. */

0 commit comments

Comments
 (0)