Skip to content

Commit 423036c

Browse files
l46kokcopybara-github
authored andcommitted
Improve the error message in planned CreateMap when duplicate key exists
PiperOrigin-RevId: 851474395
1 parent bee8115 commit 423036c

32 files changed

Lines changed: 937 additions & 398 deletions

common/exceptions/BUILD.bazel

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,15 @@ java_library(
4646
# used_by_android
4747
exports = ["//common/src/main/java/dev/cel/common/exceptions:iteration_budget_exceeded"],
4848
)
49+
50+
java_library(
51+
name = "duplicate_key",
52+
# used_by_android
53+
exports = ["//common/src/main/java/dev/cel/common/exceptions:duplicate_key"],
54+
)
55+
56+
java_library(
57+
name = "overload_not_found",
58+
# used_by_android
59+
exports = ["//common/src/main/java/dev/cel/common/exceptions:overload_not_found"],
60+
)

common/src/main/java/dev/cel/common/exceptions/BUILD.bazel

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,29 @@ java_library(
9898
"//common/annotations",
9999
],
100100
)
101+
102+
java_library(
103+
name = "duplicate_key",
104+
srcs = ["CelDuplicateKeyException.java"],
105+
# used_by_android
106+
tags = [
107+
],
108+
deps = [
109+
"//common:error_codes",
110+
"//common:runtime_exception",
111+
"//common/annotations",
112+
],
113+
)
114+
115+
java_library(
116+
name = "overload_not_found",
117+
srcs = ["CelOverloadNotFoundException.java"],
118+
# used_by_android
119+
tags = [
120+
],
121+
deps = [
122+
"//common:error_codes",
123+
"//common:runtime_exception",
124+
"//common/annotations",
125+
],
126+
)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2026 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package dev.cel.common.exceptions;
16+
17+
import dev.cel.common.CelErrorCode;
18+
import dev.cel.common.CelRuntimeException;
19+
import dev.cel.common.annotations.Internal;
20+
21+
/** Indicates an attempt to create a map using duplicate keys. */
22+
@Internal
23+
public final class CelDuplicateKeyException extends CelRuntimeException {
24+
25+
public static CelDuplicateKeyException of(Object key) {
26+
return new CelDuplicateKeyException(String.format("duplicate map key [%s]", key));
27+
}
28+
29+
private CelDuplicateKeyException(String message) {
30+
super(message, CelErrorCode.DUPLICATE_ATTRIBUTE);
31+
}
32+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright 2026 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package dev.cel.common.exceptions;
16+
17+
import dev.cel.common.CelErrorCode;
18+
import dev.cel.common.CelRuntimeException;
19+
import dev.cel.common.annotations.Internal;
20+
import java.util.Collection;
21+
import java.util.Collections;
22+
23+
/** Indicates that a matching overload could not be found during function dispatch. */
24+
@Internal
25+
public final class CelOverloadNotFoundException extends CelRuntimeException {
26+
27+
public CelOverloadNotFoundException(String functionName) {
28+
this(functionName, Collections.emptyList());
29+
}
30+
31+
public CelOverloadNotFoundException(String functionName, Collection<String> overloadIds) {
32+
super(formatErrorMessage(functionName, overloadIds), CelErrorCode.OVERLOAD_NOT_FOUND);
33+
}
34+
35+
private static String formatErrorMessage(String functionName, Collection<String> overloadIds) {
36+
StringBuilder sb = new StringBuilder();
37+
sb.append("No matching overload for function '").append(functionName).append("'.");
38+
if (!overloadIds.isEmpty()) {
39+
sb.append(" Overload candidates: ").append(String.join(", ", overloadIds));
40+
}
41+
42+
return sb.toString();
43+
}
44+
}

runtime/BUILD.bazel

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ java_library(
1616
"//runtime/src/main/java/dev/cel/runtime:descriptor_message_provider",
1717
"//runtime/src/main/java/dev/cel/runtime:function_overload",
1818
"//runtime/src/main/java/dev/cel/runtime:runtime_type_provider",
19+
"//runtime/src/main/java/dev/cel/runtime:variable_resolver",
1920
],
2021
)
2122

@@ -263,3 +264,10 @@ java_library(
263264
"//runtime/src/main/java/dev/cel/runtime:concatenated_list_view",
264265
],
265266
)
267+
268+
java_library(
269+
name = "variable_resolver",
270+
exports = [
271+
"//runtime/src/main/java/dev/cel/runtime:variable_resolver",
272+
],
273+
)

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

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,12 +123,14 @@ java_library(
123123
deps = [
124124
":evaluation_exception",
125125
":evaluation_exception_builder",
126+
":function_binding",
126127
":function_overload",
127128
":function_resolver",
128129
":resolved_overload",
129130
"//:auto_value",
130131
"//common:error_codes",
131132
"//common/annotations",
133+
"//common/exceptions:overload_not_found",
132134
"@maven//:com_google_code_findbugs_annotations",
133135
"@maven//:com_google_errorprone_error_prone_annotations",
134136
"@maven//:com_google_guava_guava",
@@ -142,12 +144,14 @@ cel_android_library(
142144
deps = [
143145
":evaluation_exception",
144146
":evaluation_exception_builder",
147+
":function_binding_android",
145148
":function_overload_android",
146149
":function_resolver_android",
147150
":resolved_overload_android",
148151
"//:auto_value",
149152
"//common:error_codes",
150153
"//common/annotations",
154+
"//common/exceptions:overload_not_found",
151155
"@maven//:com_google_code_findbugs_annotations",
152156
"@maven//:com_google_errorprone_error_prone_annotations",
153157
"@maven_android//:com_google_guava_guava",
@@ -477,8 +481,6 @@ RUNTIME_SOURCES = [
477481
"CelRuntimeFactory.java",
478482
"CelRuntimeLegacyImpl.java",
479483
"CelRuntimeLibrary.java",
480-
"CelVariableResolver.java",
481-
"HierarchicalVariableResolver.java",
482484
"ProgramImpl.java",
483485
"UnknownContext.java",
484486
]
@@ -611,6 +613,7 @@ java_library(
611613
deps = [
612614
":function_binding",
613615
":runtime_equality",
616+
"//common:operator",
614617
"//common:options",
615618
"//common/annotations",
616619
"//runtime/standard:add",
@@ -668,6 +671,7 @@ cel_android_library(
668671
deps = [
669672
":function_binding_android",
670673
":runtime_equality_android",
674+
"//common:operator_android",
671675
"//common:options",
672676
"//common/annotations",
673677
"//runtime/standard:add_android",
@@ -725,7 +729,9 @@ java_library(
725729
tags = [
726730
],
727731
deps = [
732+
":evaluation_exception",
728733
":function_overload",
734+
"//common/exceptions:overload_not_found",
729735
"@maven//:com_google_errorprone_error_prone_annotations",
730736
"@maven//:com_google_guava_guava",
731737
],
@@ -737,7 +743,9 @@ cel_android_library(
737743
tags = [
738744
],
739745
deps = [
746+
":evaluation_exception",
740747
":function_overload_android",
748+
"//common/exceptions:overload_not_found",
741749
"@maven//:com_google_errorprone_error_prone_annotations",
742750
"@maven_android//:com_google_guava_guava",
743751
],
@@ -776,7 +784,9 @@ java_library(
776784
],
777785
deps = [
778786
":evaluation_exception",
787+
"//runtime:unknown_attributes",
779788
"@maven//:com_google_errorprone_error_prone_annotations",
789+
"@maven//:com_google_guava_guava",
780790
],
781791
)
782792

@@ -787,7 +797,9 @@ cel_android_library(
787797
],
788798
deps = [
789799
":evaluation_exception",
800+
"//runtime:unknown_attributes_android",
790801
"@maven//:com_google_errorprone_error_prone_annotations",
802+
"@maven_android//:com_google_guava_guava",
791803
],
792804
)
793805

@@ -828,6 +840,7 @@ java_library(
828840
"//common/types:cel_types",
829841
"//common/values:cel_value_provider",
830842
"//common/values:proto_message_value_provider",
843+
"//runtime:variable_resolver",
831844
"//runtime/standard:add",
832845
"//runtime/standard:int",
833846
"//runtime/standard:timestamp",
@@ -896,6 +909,7 @@ java_library(
896909
":interpretable",
897910
":program",
898911
"//:auto_value",
912+
"//runtime:variable_resolver",
899913
"@maven//:com_google_errorprone_error_prone_annotations",
900914
],
901915
)
@@ -909,6 +923,7 @@ cel_android_library(
909923
":function_resolver_android",
910924
":interpretable_android",
911925
":program_android",
926+
":variable_resolver",
912927
"//:auto_value",
913928
"@maven//:com_google_errorprone_error_prone_annotations",
914929
],
@@ -1177,7 +1192,6 @@ java_library(
11771192
],
11781193
deps = [
11791194
":function_overload",
1180-
":unknown_attributes",
11811195
"//:auto_value",
11821196
"//common/annotations",
11831197
"@maven//:com_google_errorprone_error_prone_annotations",
@@ -1192,14 +1206,26 @@ cel_android_library(
11921206
],
11931207
deps = [
11941208
":function_overload_android",
1195-
":unknown_attributes_android",
11961209
"//:auto_value",
11971210
"//common/annotations",
11981211
"@maven//:com_google_errorprone_error_prone_annotations",
11991212
"@maven_android//:com_google_guava_guava",
12001213
],
12011214
)
12021215

1216+
java_library(
1217+
name = "variable_resolver",
1218+
srcs = [
1219+
"CelVariableResolver.java",
1220+
"HierarchicalVariableResolver.java",
1221+
],
1222+
# used_by_android
1223+
tags = [
1224+
],
1225+
deps = [
1226+
],
1227+
)
1228+
12031229
java_library(
12041230
name = "program",
12051231
srcs = ["Program.java"],
@@ -1208,6 +1234,7 @@ java_library(
12081234
deps = [
12091235
":evaluation_exception",
12101236
":function_resolver",
1237+
":variable_resolver",
12111238
"@maven//:com_google_errorprone_error_prone_annotations",
12121239
],
12131240
)
@@ -1220,6 +1247,7 @@ cel_android_library(
12201247
deps = [
12211248
":evaluation_exception",
12221249
":function_resolver_android",
1250+
":variable_resolver",
12231251
"//:auto_value",
12241252
"@maven//:com_google_errorprone_error_prone_annotations",
12251253
],

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

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,13 @@
1414

1515
package dev.cel.runtime;
1616

17+
import static com.google.common.base.Preconditions.checkArgument;
18+
19+
import com.google.common.base.Strings;
1720
import com.google.common.collect.ImmutableList;
21+
import com.google.common.collect.ImmutableSet;
1822
import com.google.errorprone.annotations.Immutable;
23+
import java.util.Collection;
1924

2025
/**
2126
* Binding consisting of an overload id, a Java-native argument signature, and an overload
@@ -35,7 +40,6 @@
3540
*
3641
* <p>Examples: string_startsWith_string, mathMax_list, lessThan_money_money
3742
*/
38-
3943
@Immutable
4044
public interface CelFunctionBinding {
4145
String getOverloadId();
@@ -70,4 +74,23 @@ static CelFunctionBinding from(
7074
return new FunctionBindingImpl(
7175
overloadId, ImmutableList.copyOf(argTypes), impl, /* isStrict= */ true);
7276
}
77+
78+
/** See {@link #fromOverloads(String, Collection)}. */
79+
static ImmutableSet<CelFunctionBinding> fromOverloads(
80+
String functionName, CelFunctionBinding... overloadBindings) {
81+
return fromOverloads(functionName, ImmutableList.copyOf(overloadBindings));
82+
}
83+
84+
/**
85+
* Creates a set of bindings for a function, enabling dynamic dispatch logic to select the correct
86+
* overload at runtime based on argument types.
87+
*/
88+
static ImmutableSet<CelFunctionBinding> fromOverloads(
89+
String functionName, Collection<CelFunctionBinding> overloadBindings) {
90+
checkArgument(!Strings.isNullOrEmpty(functionName), "Function name cannot be null or empty");
91+
checkArgument(!overloadBindings.isEmpty(), "You must provide at least one binding.");
92+
93+
return FunctionBindingImpl.groupOverloadsToFunction(
94+
functionName, ImmutableSet.copyOf(overloadBindings));
95+
}
7396
}

0 commit comments

Comments
 (0)