Skip to content

Commit f7b9112

Browse files
l46kokcopybara-github
authored andcommitted
Plan late function bindings, add CelOverloadNotFound exception
PiperOrigin-RevId: 853788116
1 parent b84982e commit f7b9112

21 files changed

+471
-70
lines changed

common/exceptions/BUILD.bazel

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,9 @@ java_library(
5252
# used_by_android
5353
exports = ["//common/src/main/java/dev/cel/common/exceptions:iteration_budget_exceeded"],
5454
)
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: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,16 @@ java_library(
110110
"//common/annotations",
111111
],
112112
)
113+
114+
java_library(
115+
name = "overload_not_found",
116+
srcs = ["CelOverloadNotFoundException.java"],
117+
# used_by_android
118+
tags = [
119+
],
120+
deps = [
121+
":runtime_exception",
122+
"//common:error_codes",
123+
"//common/annotations",
124+
],
125+
)
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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.annotations.Internal;
19+
import java.util.Collection;
20+
import java.util.Collections;
21+
22+
/** Indicates that a matching overload could not be found during function dispatch. */
23+
@Internal
24+
public final class CelOverloadNotFoundException extends CelRuntimeException {
25+
26+
public CelOverloadNotFoundException(String functionName) {
27+
this(functionName, Collections.emptyList());
28+
}
29+
30+
public CelOverloadNotFoundException(String functionName, Collection<String> overloadIds) {
31+
super(formatErrorMessage(functionName, overloadIds), CelErrorCode.OVERLOAD_NOT_FOUND);
32+
}
33+
34+
private static String formatErrorMessage(String functionName, Collection<String> overloadIds) {
35+
StringBuilder sb = new StringBuilder();
36+
sb.append("No matching overload for function '").append(functionName).append("'.");
37+
if (!overloadIds.isEmpty()) {
38+
sb.append(" Overload candidates: ").append(String.join(", ", overloadIds));
39+
}
40+
41+
return sb.toString();
42+
}
43+
}

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: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ java_library(
129129
"//:auto_value",
130130
"//common:error_codes",
131131
"//common/annotations",
132+
"//common/exceptions:overload_not_found",
132133
"@maven//:com_google_code_findbugs_annotations",
133134
"@maven//:com_google_errorprone_error_prone_annotations",
134135
"@maven//:com_google_guava_guava",
@@ -149,6 +150,7 @@ cel_android_library(
149150
"//:auto_value",
150151
"//common:error_codes",
151152
"//common/annotations",
153+
"//common/exceptions:overload_not_found",
152154
"@maven//:com_google_code_findbugs_annotations",
153155
"@maven//:com_google_errorprone_error_prone_annotations",
154156
"@maven_android//:com_google_guava_guava",
@@ -477,8 +479,6 @@ RUNTIME_SOURCES = [
477479
"CelRuntimeFactory.java",
478480
"CelRuntimeLegacyImpl.java",
479481
"CelRuntimeLibrary.java",
480-
"CelVariableResolver.java",
481-
"HierarchicalVariableResolver.java",
482482
"ProgramImpl.java",
483483
"UnknownContext.java",
484484
]
@@ -729,6 +729,7 @@ java_library(
729729
deps = [
730730
":evaluation_exception",
731731
":function_overload",
732+
"//common/exceptions:overload_not_found",
732733
"@maven//:com_google_errorprone_error_prone_annotations",
733734
"@maven//:com_google_guava_guava",
734735
],
@@ -742,6 +743,7 @@ cel_android_library(
742743
deps = [
743744
":evaluation_exception",
744745
":function_overload_android",
746+
"//common/exceptions:overload_not_found",
745747
"@maven//:com_google_errorprone_error_prone_annotations",
746748
"@maven_android//:com_google_guava_guava",
747749
],
@@ -836,6 +838,7 @@ java_library(
836838
"//common/types:cel_types",
837839
"//common/values:cel_value_provider",
838840
"//common/values:proto_message_value_provider",
841+
"//runtime:variable_resolver",
839842
"//runtime/standard:add",
840843
"//runtime/standard:int",
841844
"//runtime/standard:timestamp",
@@ -904,6 +907,7 @@ java_library(
904907
":interpretable",
905908
":program",
906909
"//:auto_value",
910+
"//runtime:variable_resolver",
907911
"@maven//:com_google_errorprone_error_prone_annotations",
908912
],
909913
)
@@ -917,6 +921,7 @@ cel_android_library(
917921
":function_resolver_android",
918922
":interpretable_android",
919923
":program_android",
924+
":variable_resolver",
920925
"//:auto_value",
921926
"@maven//:com_google_errorprone_error_prone_annotations",
922927
],
@@ -1204,6 +1209,19 @@ cel_android_library(
12041209
],
12051210
)
12061211

1212+
java_library(
1213+
name = "variable_resolver",
1214+
srcs = [
1215+
"CelVariableResolver.java",
1216+
"HierarchicalVariableResolver.java",
1217+
],
1218+
# used_by_android
1219+
tags = [
1220+
],
1221+
deps = [
1222+
],
1223+
)
1224+
12071225
java_library(
12081226
name = "program",
12091227
srcs = ["Program.java"],
@@ -1212,6 +1230,7 @@ java_library(
12121230
deps = [
12131231
":evaluation_exception",
12141232
":function_resolver",
1233+
":variable_resolver",
12151234
"@maven//:com_google_errorprone_error_prone_annotations",
12161235
],
12171236
)
@@ -1224,6 +1243,7 @@ cel_android_library(
12241243
deps = [
12251244
":evaluation_exception",
12261245
":function_resolver_android",
1246+
":variable_resolver",
12271247
"//:auto_value",
12281248
"@maven//:com_google_errorprone_error_prone_annotations",
12291249
],

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
package dev.cel.runtime;
1616

1717
import javax.annotation.concurrent.ThreadSafe;
18-
import java.util.List;
18+
import java.util.Collection;
1919
import java.util.Optional;
2020

2121
/**
@@ -36,5 +36,18 @@ public interface CelFunctionResolver {
3636
* @throws CelEvaluationException if the overload resolution is ambiguous,
3737
*/
3838
Optional<CelResolvedOverload> findOverloadMatchingArgs(
39-
String functionName, List<String> overloadIds, Object[] args) throws CelEvaluationException;
39+
String functionName, Collection<String> overloadIds, Object[] args)
40+
throws CelEvaluationException;
41+
42+
/**
43+
* Finds a specific function overload to invoke based on given parameters, scanning all available
44+
* overloads if necessary.
45+
*
46+
* @param functionName the logical name of the function being invoked.
47+
* @param args The arguments to pass to the function.
48+
* @return an optional value of the resolved overload.
49+
* @throws CelEvaluationException if the overload resolution is ambiguous.
50+
*/
51+
Optional<CelResolvedOverload> findOverloadMatchingArgs(String functionName, Object[] args)
52+
throws CelEvaluationException;
4053
}

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import com.google.common.collect.ImmutableMap;
2020
import com.google.errorprone.annotations.Immutable;
2121
import java.util.Arrays;
22-
import java.util.List;
22+
import java.util.Collection;
2323
import java.util.Optional;
2424

2525
/**
@@ -37,15 +37,23 @@ private CelLateFunctionBindings(ImmutableMap<String, CelResolvedOverload> functi
3737

3838
@Override
3939
public Optional<CelResolvedOverload> findOverloadMatchingArgs(
40-
String functionName, List<String> overloadIds, Object[] args) throws CelEvaluationException {
40+
String functionName, Collection<String> overloadIds, Object[] args)
41+
throws CelEvaluationException {
4142
return DefaultDispatcher.findOverloadMatchingArgs(functionName, overloadIds, functions, args);
4243
}
4344

45+
@Override
46+
public Optional<CelResolvedOverload> findOverloadMatchingArgs(String functionName, Object[] args)
47+
throws CelEvaluationException {
48+
return DefaultDispatcher.findOverloadMatchingArgs(
49+
functionName, functions.keySet(), functions, args);
50+
}
51+
4452
public static CelLateFunctionBindings from(CelFunctionBinding... functions) {
4553
return from(Arrays.asList(functions));
4654
}
4755

48-
public static CelLateFunctionBindings from(List<CelFunctionBinding> functions) {
56+
public static CelLateFunctionBindings from(Collection<CelFunctionBinding> functions) {
4957
return new CelLateFunctionBindings(
5058
functions.stream()
5159
.collect(

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

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,6 @@ interface Program extends dev.cel.runtime.Program {
4242
/** Evaluate the expression using {@code message} fields as the source of input variables. */
4343
Object eval(Message message) throws CelEvaluationException;
4444

45-
/** Evaluate a compiled program with a custom variable {@code resolver}. */
46-
Object eval(CelVariableResolver resolver) throws CelEvaluationException;
47-
48-
/**
49-
* Evaluate a compiled program with a custom variable {@code resolver} and late-bound functions
50-
* {@code lateBoundFunctionResolver}.
51-
*/
52-
Object eval(CelVariableResolver resolver, CelFunctionResolver lateBoundFunctionResolver)
53-
throws CelEvaluationException;
54-
5545
/**
5646
* Trace evaluates a compiled program without any variables and invokes the listener as
5747
* evaluation progresses through the AST.

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

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@
2525
import com.google.errorprone.annotations.Immutable;
2626
import dev.cel.common.CelErrorCode;
2727
import dev.cel.common.annotations.Internal;
28+
import dev.cel.common.exceptions.CelOverloadNotFoundException;
2829
import dev.cel.runtime.FunctionBindingImpl.DynamicDispatchOverload;
2930
import java.util.ArrayList;
31+
import java.util.Collection;
3032
import java.util.List;
3133
import java.util.Map;
3234
import java.util.Optional;
@@ -46,16 +48,23 @@ public Optional<CelResolvedOverload> findOverload(String functionName) {
4648
return Optional.ofNullable(overloads.get(functionName));
4749
}
4850

51+
@Override
52+
public Optional<CelResolvedOverload> findOverloadMatchingArgs(String functionName, Object[] args)
53+
throws CelEvaluationException {
54+
return findOverloadMatchingArgs(functionName, overloads.keySet(), overloads, args);
55+
}
56+
4957
@Override
5058
public Optional<CelResolvedOverload> findOverloadMatchingArgs(
51-
String functionName, List<String> overloadIds, Object[] args) throws CelEvaluationException {
59+
String functionName, Collection<String> overloadIds, Object[] args)
60+
throws CelEvaluationException {
5261
return findOverloadMatchingArgs(functionName, overloadIds, overloads, args);
5362
}
5463

5564
/** Finds the overload that matches the given function name, overload IDs, and arguments. */
5665
static Optional<CelResolvedOverload> findOverloadMatchingArgs(
5766
String functionName,
58-
List<String> overloadIds,
67+
Collection<String> overloadIds,
5968
Map<String, ? extends CelResolvedOverload> overloads,
6069
Object[] args)
6170
throws CelEvaluationException {
@@ -165,7 +174,7 @@ private static Object guardedOp(
165174
return overload.apply(args);
166175
}
167176

168-
throw new IllegalArgumentException("No matching overload for function: " + functionName);
177+
throw new CelOverloadNotFoundException(functionName);
169178
}
170179

171180
DefaultDispatcher(ImmutableMap<String, CelResolvedOverload> overloads) {

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

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

1515
package dev.cel.runtime;
1616

17+
import static com.google.common.collect.ImmutableList.toImmutableList;
18+
1719
import com.google.common.collect.ImmutableList;
1820
import com.google.common.collect.ImmutableSet;
1921
import com.google.common.collect.Iterables;
2022
import com.google.errorprone.annotations.Immutable;
23+
import dev.cel.common.exceptions.CelOverloadNotFoundException;
2124

2225
@Immutable
2326
final class FunctionBindingImpl implements CelFunctionBinding {
@@ -135,7 +138,11 @@ public Object apply(Object[] args) throws CelEvaluationException {
135138
}
136139
}
137140

138-
throw new IllegalArgumentException("No matching overload for function: " + functionName);
141+
throw new CelOverloadNotFoundException(
142+
functionName,
143+
overloadBindings.stream()
144+
.map(CelFunctionBinding::getOverloadId)
145+
.collect(toImmutableList()));
139146
}
140147

141148
private DynamicDispatchOverload(

0 commit comments

Comments
 (0)