Skip to content

Commit 61a01d8

Browse files
l46kokcopybara-github
authored andcommitted
Change function failures (dispatch / overload match) to always include the function name
PiperOrigin-RevId: 904088792
1 parent e7dff9b commit 61a01d8

25 files changed

Lines changed: 266 additions & 77 deletions

extensions/src/test/java/dev/cel/extensions/CelListsExtensionsTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import dev.cel.expr.conformance.test.SimpleTest;
3030
import dev.cel.parser.CelStandardMacro;
3131
import dev.cel.runtime.CelEvaluationException;
32+
import dev.cel.testing.CelRuntimeFlavor;
3233
import org.junit.Assume;
3334
import org.junit.Test;
3435
import org.junit.runner.RunWith;
@@ -143,7 +144,7 @@ public void flatten_negativeDepth_throws() {
143144
CelEvaluationException e =
144145
assertThrows(CelEvaluationException.class, () -> eval(cel, "[1,2,3,4].flatten(-1)"));
145146

146-
if (isParseOnly) {
147+
if (runtimeFlavor.equals(CelRuntimeFlavor.PLANNER)) {
147148
assertThat(e)
148149
.hasMessageThat()
149150
.contains("evaluation error at <input>:17: Function 'flatten' failed");

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ LITE_PROGRAM_IMPL_SOURCES = [
5353
FUNCTION_BINDING_SOURCES = [
5454
"CelFunctionBinding.java",
5555
"FunctionBindingImpl.java",
56+
"InternalCelFunctionBinding.java",
5657
]
5758

5859
# keep sorted
@@ -740,6 +741,7 @@ java_library(
740741
deps = [
741742
":evaluation_exception",
742743
":function_overload",
744+
"//common/annotations",
743745
"//common/exceptions:overload_not_found",
744746
"@maven//:com_google_errorprone_error_prone_annotations",
745747
"@maven//:com_google_guava_guava",
@@ -754,6 +756,7 @@ cel_android_library(
754756
deps = [
755757
":evaluation_exception",
756758
":function_overload_android",
759+
"//common/annotations",
757760
"//common/exceptions:overload_not_found",
758761
"@maven//:com_google_errorprone_error_prone_annotations",
759762
"@maven_android//:com_google_guava_guava",
@@ -890,7 +893,6 @@ java_library(
890893
"//common/types:type_providers",
891894
"//common/values:cel_value_provider",
892895
"//common/values:proto_message_value_provider",
893-
"//runtime/standard:add",
894896
"//runtime/standard:int",
895897
"//runtime/standard:timestamp",
896898
"@maven//:com_google_code_findbugs_annotations",

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ static CelFunctionBinding from(
100100
overloadId, ImmutableList.copyOf(argTypes), impl, /* isStrict= */ true);
101101
}
102102

103+
103104
/** See {@link #fromOverloads(String, Collection)}. */
104105
static ImmutableSet<CelFunctionBinding> fromOverloads(
105106
String functionName, CelFunctionBinding... overloadBindings) {

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,12 @@ public static CelLateFunctionBindings from(Collection<CelFunctionBinding> functi
6363
}
6464

6565
private static CelResolvedOverload createResolvedOverload(CelFunctionBinding binding) {
66+
String functionName = binding.getOverloadId();
67+
if (binding instanceof InternalCelFunctionBinding) {
68+
functionName = ((InternalCelFunctionBinding) binding).getFunctionName();
69+
}
6670
return CelResolvedOverload.of(
71+
functionName,
6772
binding.getOverloadId(),
6873
binding.getDefinition(),
6974
binding.isStrict(),

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

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
@Internal
3131
public abstract class CelResolvedOverload {
3232

33+
/** The base function name. */
34+
public abstract String getFunctionName();
35+
3336
/** The overload id of the function. */
3437
public abstract String getOverloadId();
3538

@@ -61,40 +64,44 @@ public Object invoke(Object[] args) throws CelEvaluationException {
6164
|| CelFunctionOverload.canHandle(args, getParameterTypes(), isStrict())) {
6265
return getDefinition().apply(args);
6366
}
64-
throw new CelOverloadNotFoundException(getOverloadId());
67+
throw new CelOverloadNotFoundException(getFunctionName(), ImmutableList.of(getOverloadId()));
6568
}
6669

6770
public Object invoke(Object arg) throws CelEvaluationException {
6871
if (isDynamicDispatch()
6972
|| CelFunctionOverload.canHandle(arg, getParameterTypes(), isStrict())) {
7073
return getOptimizedDefinition().apply(arg);
7174
}
72-
throw new CelOverloadNotFoundException(getOverloadId());
75+
throw new CelOverloadNotFoundException(getFunctionName(), ImmutableList.of(getOverloadId()));
7376
}
7477

7578
public Object invoke(Object arg1, Object arg2) throws CelEvaluationException {
7679
if (isDynamicDispatch()
7780
|| CelFunctionOverload.canHandle(arg1, arg2, getParameterTypes(), isStrict())) {
7881
return getOptimizedDefinition().apply(arg1, arg2);
7982
}
80-
throw new CelOverloadNotFoundException(getOverloadId());
83+
throw new CelOverloadNotFoundException(getFunctionName(), ImmutableList.of(getOverloadId()));
8184
}
8285

8386
/**
84-
* Creates a new resolved overload from the given overload id, parameter types, and definition.
87+
* Creates a new resolved overload from the given function name, overload id, parameter types, and
88+
* definition.
8589
*/
8690
public static CelResolvedOverload of(
91+
String functionName,
8792
String overloadId,
8893
CelFunctionOverload definition,
8994
boolean isStrict,
9095
Class<?>... parameterTypes) {
91-
return of(overloadId, definition, isStrict, ImmutableList.copyOf(parameterTypes));
96+
return of(functionName, overloadId, definition, isStrict, ImmutableList.copyOf(parameterTypes));
9297
}
9398

9499
/**
95-
* Creates a new resolved overload from the given overload id, parameter types, and definition.
100+
* Creates a new resolved overload from the given function name, overload id, parameter types, and
101+
* definition.
96102
*/
97103
public static CelResolvedOverload of(
104+
String functionName,
98105
String overloadId,
99106
CelFunctionOverload definition,
100107
boolean isStrict,
@@ -104,7 +111,12 @@ public static CelResolvedOverload of(
104111
? (OptimizedFunctionOverload) definition
105112
: definition::apply;
106113
return new AutoValue_CelResolvedOverload(
107-
overloadId, ImmutableList.copyOf(parameterTypes), isStrict, definition, optimizedDef);
114+
functionName,
115+
overloadId,
116+
ImmutableList.copyOf(parameterTypes),
117+
isStrict,
118+
definition,
119+
optimizedDef);
108120
}
109121

110122
/**

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,15 +381,25 @@ private static DefaultDispatcher newDispatcher(
381381
DefaultDispatcher.Builder builder = DefaultDispatcher.newBuilder();
382382
for (CelFunctionBinding binding :
383383
standardFunctions.newFunctionBindings(runtimeEquality, options)) {
384+
String functionName = binding.getOverloadId();
385+
if (binding instanceof InternalCelFunctionBinding) {
386+
functionName = ((InternalCelFunctionBinding) binding).getFunctionName();
387+
}
384388
builder.addOverload(
389+
functionName,
385390
binding.getOverloadId(),
386391
binding.getArgTypes(),
387392
binding.isStrict(),
388393
binding.getDefinition());
389394
}
390395

391396
for (CelFunctionBinding binding : customFunctionBindings) {
397+
String functionName = binding.getOverloadId();
398+
if (binding instanceof InternalCelFunctionBinding) {
399+
functionName = ((InternalCelFunctionBinding) binding).getFunctionName();
400+
}
392401
builder.addOverload(
402+
functionName,
393403
binding.getOverloadId(),
394404
binding.getArgTypes(),
395405
binding.isStrict(),

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,15 +305,25 @@ public CelRuntimeLegacyImpl build() {
305305
DefaultDispatcher.Builder dispatcherBuilder = DefaultDispatcher.newBuilder();
306306
for (CelFunctionBinding standardFunctionBinding :
307307
newStandardFunctionBindings(runtimeEquality)) {
308+
String functionName = standardFunctionBinding.getOverloadId();
309+
if (standardFunctionBinding instanceof InternalCelFunctionBinding) {
310+
functionName = ((InternalCelFunctionBinding) standardFunctionBinding).getFunctionName();
311+
}
308312
dispatcherBuilder.addOverload(
313+
functionName,
309314
standardFunctionBinding.getOverloadId(),
310315
standardFunctionBinding.getArgTypes(),
311316
standardFunctionBinding.isStrict(),
312317
standardFunctionBinding.getDefinition());
313318
}
314319

315320
for (CelFunctionBinding customBinding : customFunctionBindings.values()) {
321+
String functionName = customBinding.getOverloadId();
322+
if (customBinding instanceof InternalCelFunctionBinding) {
323+
functionName = ((InternalCelFunctionBinding) customBinding).getFunctionName();
324+
}
316325
dispatcherBuilder.addOverload(
326+
functionName,
317327
customBinding.getOverloadId(),
318328
customBinding.getArgTypes(),
319329
customBinding.isStrict(),

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

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,32 +134,41 @@ public static class Builder {
134134
@AutoValue
135135
@Immutable
136136
abstract static class OverloadEntry {
137+
abstract String functionName();
138+
137139
abstract ImmutableList<Class<?>> argTypes();
138140

139141
abstract boolean isStrict();
140142

141143
abstract CelFunctionOverload overload();
142144

143145
private static OverloadEntry of(
144-
ImmutableList<Class<?>> argTypes, boolean isStrict, CelFunctionOverload overload) {
145-
return new AutoValue_DefaultDispatcher_Builder_OverloadEntry(argTypes, isStrict, overload);
146+
String functionName,
147+
ImmutableList<Class<?>> argTypes,
148+
boolean isStrict,
149+
CelFunctionOverload overload) {
150+
return new AutoValue_DefaultDispatcher_Builder_OverloadEntry(
151+
functionName, argTypes, isStrict, overload);
146152
}
147153
}
148154

149155
private final Map<String, OverloadEntry> overloads;
150156

151157
@CanIgnoreReturnValue
152158
public Builder addOverload(
159+
String functionName,
153160
String overloadId,
154161
ImmutableList<Class<?>> argTypes,
155162
boolean isStrict,
156163
CelFunctionOverload overload) {
164+
checkNotNull(functionName);
165+
checkArgument(!functionName.isEmpty(), "Function name cannot be empty.");
157166
checkNotNull(overloadId);
158167
checkArgument(!overloadId.isEmpty(), "Overload ID cannot be empty.");
159168
checkNotNull(argTypes);
160169
checkNotNull(overload);
161170

162-
OverloadEntry newEntry = OverloadEntry.of(argTypes, isStrict, overload);
171+
OverloadEntry newEntry = OverloadEntry.of(functionName, argTypes, isStrict, overload);
163172

164173
overloads.merge(
165174
overloadId,
@@ -188,7 +197,7 @@ private OverloadEntry mergeDynamicDispatchesOrThrow(
188197
boolean isStrict =
189198
mergedOverload.getOverloadBindings().stream().allMatch(CelFunctionBinding::isStrict);
190199

191-
return OverloadEntry.of(incoming.argTypes(), isStrict, mergedOverload);
200+
return OverloadEntry.of(overloadId, incoming.argTypes(), isStrict, mergedOverload);
192201
}
193202

194203
throw new IllegalArgumentException("Duplicate overload ID binding: " + overloadId);
@@ -204,7 +213,11 @@ public DefaultDispatcher build() {
204213
resolvedOverloads.put(
205214
overloadId,
206215
CelResolvedOverload.of(
207-
overloadId, overloadImpl, overloadEntry.isStrict(), overloadEntry.argTypes()));
216+
overloadEntry.functionName(),
217+
overloadId,
218+
overloadImpl,
219+
overloadEntry.isStrict(),
220+
overloadEntry.argTypes()));
208221
}
209222

210223
return new DefaultDispatcher(resolvedOverloads.buildOrThrow());

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

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
import dev.cel.common.exceptions.CelOverloadNotFoundException;
2424

2525
@Immutable
26-
final class FunctionBindingImpl implements CelFunctionBinding {
26+
final class FunctionBindingImpl implements InternalCelFunctionBinding {
27+
28+
private final String functionName;
2729

2830
private final String overloadId;
2931

@@ -33,6 +35,11 @@ final class FunctionBindingImpl implements CelFunctionBinding {
3335

3436
private final boolean isStrict;
3537

38+
@Override
39+
public String getFunctionName() {
40+
return functionName;
41+
}
42+
3643
@Override
3744
public String getOverloadId() {
3845
return overloadId;
@@ -54,20 +61,34 @@ public boolean isStrict() {
5461
}
5562

5663
FunctionBindingImpl(
64+
String functionName,
5765
String overloadId,
5866
ImmutableList<Class<?>> argTypes,
5967
CelFunctionOverload definition,
6068
boolean isStrict) {
69+
this.functionName = functionName;
6170
this.overloadId = overloadId;
6271
this.argTypes = argTypes;
6372
this.definition = definition;
6473
this.isStrict = isStrict;
6574
}
6675

76+
FunctionBindingImpl(
77+
String overloadId,
78+
ImmutableList<Class<?>> argTypes,
79+
CelFunctionOverload definition,
80+
boolean isStrict) {
81+
this(overloadId, overloadId, argTypes, definition, isStrict);
82+
}
83+
6784
static ImmutableSet<CelFunctionBinding> groupOverloadsToFunction(
6885
String functionName, ImmutableSet<CelFunctionBinding> overloadBindings) {
6986
ImmutableSet.Builder<CelFunctionBinding> builder = ImmutableSet.builder();
70-
builder.addAll(overloadBindings);
87+
for (CelFunctionBinding b : overloadBindings) {
88+
builder.add(
89+
new FunctionBindingImpl(
90+
functionName, b.getOverloadId(), b.getArgTypes(), b.getDefinition(), b.isStrict()));
91+
}
7192

7293
// If there is already a binding with the same name as the function, we treat it as a
7394
// "Singleton" binding and do not create a dynamic dispatch wrapper for it.
@@ -80,11 +101,12 @@ static ImmutableSet<CelFunctionBinding> groupOverloadsToFunction(
80101
CelFunctionBinding singleBinding = Iterables.getOnlyElement(overloadBindings);
81102
builder.add(
82103
new FunctionBindingImpl(
104+
functionName,
83105
functionName,
84106
singleBinding.getArgTypes(),
85107
singleBinding.getDefinition(),
86108
singleBinding.isStrict()));
87-
} else {
109+
} else if (overloadBindings.size() > 1) {
88110
builder.add(new DynamicDispatchBinding(functionName, overloadBindings));
89111
}
90112
}
@@ -93,7 +115,7 @@ static ImmutableSet<CelFunctionBinding> groupOverloadsToFunction(
93115
}
94116

95117
@Immutable
96-
static final class DynamicDispatchBinding implements CelFunctionBinding {
118+
static final class DynamicDispatchBinding implements InternalCelFunctionBinding {
97119

98120
private final boolean isStrict;
99121
private final DynamicDispatchOverload dynamicDispatchOverload;
@@ -103,6 +125,11 @@ public String getOverloadId() {
103125
return dynamicDispatchOverload.functionName;
104126
}
105127

128+
@Override
129+
public String getFunctionName() {
130+
return dynamicDispatchOverload.functionName;
131+
}
132+
106133
@Override
107134
public ImmutableList<Class<?>> getArgTypes() {
108135
return ImmutableList.of();
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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.runtime;
16+
17+
import com.google.errorprone.annotations.Immutable;
18+
import dev.cel.common.annotations.Internal;
19+
20+
/**
21+
* Internal interface to expose the function name associated with a binding.
22+
*
23+
* <p>CEL Library Internals. Do Not Use.
24+
*/
25+
@Internal
26+
@Immutable
27+
public interface InternalCelFunctionBinding extends CelFunctionBinding {
28+
String getFunctionName();
29+
}

0 commit comments

Comments
 (0)