Skip to content

Commit 68fbf95

Browse files
l46kokcopybara-github
authored andcommitted
Fix function dispatch failure error messages to be properly formatted
PiperOrigin-RevId: 868911649
1 parent d4e4984 commit 68fbf95

File tree

9 files changed

+44
-41
lines changed

9 files changed

+44
-41
lines changed

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -199,10 +199,10 @@ java_library(
199199
name = "eval_zero_arity",
200200
srcs = ["EvalZeroArity.java"],
201201
deps = [
202+
":eval_helpers",
202203
":execution_frame",
203204
":planned_interpretable",
204205
"//common/values",
205-
"//common/values:cel_value",
206206
"//runtime:evaluation_exception",
207207
"//runtime:interpretable",
208208
"//runtime:resolved_overload",
@@ -217,7 +217,6 @@ java_library(
217217
":execution_frame",
218218
":planned_interpretable",
219219
"//common/values",
220-
"//common/values:cel_value",
221220
"//runtime:evaluation_exception",
222221
"//runtime:interpretable",
223222
"//runtime:resolved_overload",
@@ -232,7 +231,6 @@ java_library(
232231
":execution_frame",
233232
":planned_interpretable",
234233
"//common/values",
235-
"//common/values:cel_value",
236234
"//runtime:evaluation_exception",
237235
"//runtime:interpretable",
238236
"//runtime:resolved_overload",
@@ -248,7 +246,6 @@ java_library(
248246
":planned_interpretable",
249247
"//common/exceptions:overload_not_found",
250248
"//common/values",
251-
"//common/values:cel_value",
252249
"//runtime:evaluation_exception",
253250
"//runtime:interpretable",
254251
"//runtime:resolved_overload",
@@ -377,7 +374,11 @@ java_library(
377374
"//common:error_codes",
378375
"//common/exceptions:runtime_exception",
379376
"//common/values",
377+
"//common/values:cel_value",
378+
"//runtime:evaluation_exception",
380379
"//runtime:interpretable",
380+
"//runtime:resolved_overload",
381+
"@maven//:com_google_guava_guava",
381382
],
382383
)
383384

runtime/src/main/java/dev/cel/runtime/planner/EvalHelpers.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,14 @@
1414

1515
package dev.cel.runtime.planner;
1616

17+
import com.google.common.base.Joiner;
1718
import dev.cel.common.CelErrorCode;
1819
import dev.cel.common.exceptions.CelRuntimeException;
20+
import dev.cel.common.values.CelValue;
21+
import dev.cel.common.values.CelValueConverter;
1922
import dev.cel.common.values.ErrorValue;
23+
import dev.cel.runtime.CelEvaluationException;
24+
import dev.cel.runtime.CelResolvedOverload;
2025
import dev.cel.runtime.GlobalResolver;
2126

2227
final class EvalHelpers {
@@ -51,5 +56,26 @@ static Object evalStrictly(
5156
}
5257
}
5358

59+
static Object dispatch(CelResolvedOverload overload, CelValueConverter valueConverter, Object[] args) throws CelEvaluationException {
60+
try {
61+
Object result = overload.getDefinition().apply(args);
62+
Object runtimeValue = valueConverter.toRuntimeValue(result);
63+
if (runtimeValue instanceof CelValue) {
64+
return valueConverter.unwrap((CelValue) runtimeValue);
65+
}
66+
67+
return runtimeValue;
68+
} catch (CelRuntimeException e) {
69+
// Function dispatch failure that's already been handled -- just propagate.
70+
throw e;
71+
} catch (RuntimeException e) {
72+
// Unexpected function dispatch failure.
73+
throw new IllegalArgumentException(String.format(
74+
"Function '%s' failed with arg(s) '%s'",
75+
overload.getOverloadId(), Joiner.on(", ").join(args)),
76+
e);
77+
}
78+
}
79+
5480
private EvalHelpers() {}
5581
}

runtime/src/main/java/dev/cel/runtime/planner/EvalLateBoundCall.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
import com.google.common.collect.ImmutableList;
2020
import dev.cel.common.exceptions.CelOverloadNotFoundException;
21-
import dev.cel.common.values.CelValue;
2221
import dev.cel.common.values.CelValueConverter;
2322
import dev.cel.runtime.CelEvaluationException;
2423
import dev.cel.runtime.CelResolvedOverload;
@@ -48,12 +47,7 @@ public Object eval(GlobalResolver resolver, ExecutionFrame frame) throws CelEval
4847
.findOverload(functionName, overloadIds, argVals)
4948
.orElseThrow(() -> new CelOverloadNotFoundException(functionName, overloadIds));
5049

51-
Object result = resolvedOverload.getDefinition().apply(argVals);
52-
Object runtimeValue = celValueConverter.toRuntimeValue(result);
53-
if (runtimeValue instanceof CelValue) {
54-
return celValueConverter.unwrap((CelValue) runtimeValue);
55-
}
56-
return runtimeValue;
50+
return EvalHelpers.dispatch(resolvedOverload, celValueConverter, argVals);
5751
}
5852

5953
static EvalLateBoundCall create(

runtime/src/main/java/dev/cel/runtime/planner/EvalUnary.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import static dev.cel.runtime.planner.EvalHelpers.evalNonstrictly;
1818
import static dev.cel.runtime.planner.EvalHelpers.evalStrictly;
1919

20-
import dev.cel.common.values.CelValue;
2120
import dev.cel.common.values.CelValueConverter;
2221
import dev.cel.runtime.CelEvaluationException;
2322
import dev.cel.runtime.CelResolvedOverload;
@@ -37,12 +36,7 @@ public Object eval(GlobalResolver resolver, ExecutionFrame frame) throws CelEval
3736
: evalNonstrictly(arg, resolver, frame);
3837
Object[] arguments = new Object[] {argVal};
3938

40-
Object result = resolvedOverload.getDefinition().apply(arguments);
41-
Object runtimeValue = celValueConverter.toRuntimeValue(result);
42-
if (runtimeValue instanceof CelValue) {
43-
return celValueConverter.unwrap((CelValue) runtimeValue);
44-
}
45-
return runtimeValue;
39+
return EvalHelpers.dispatch(resolvedOverload, celValueConverter, arguments);
4640
}
4741

4842
static EvalUnary create(

runtime/src/main/java/dev/cel/runtime/planner/EvalVarArgsCall.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import static dev.cel.runtime.planner.EvalHelpers.evalNonstrictly;
1818
import static dev.cel.runtime.planner.EvalHelpers.evalStrictly;
1919

20-
import dev.cel.common.values.CelValue;
2120
import dev.cel.common.values.CelValueConverter;
2221
import dev.cel.runtime.CelEvaluationException;
2322
import dev.cel.runtime.CelResolvedOverload;
@@ -43,12 +42,7 @@ public Object eval(GlobalResolver resolver, ExecutionFrame frame) throws CelEval
4342
: evalNonstrictly(arg, resolver, frame);
4443
}
4544

46-
Object result = resolvedOverload.getDefinition().apply(argVals);
47-
Object runtimeValue = celValueConverter.toRuntimeValue(result);
48-
if (runtimeValue instanceof CelValue) {
49-
return celValueConverter.unwrap((CelValue) runtimeValue);
50-
}
51-
return runtimeValue;
45+
return EvalHelpers.dispatch(resolvedOverload, celValueConverter, argVals);
5246
}
5347

5448
static EvalVarArgsCall create(

runtime/src/main/java/dev/cel/runtime/planner/EvalZeroArity.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515
package dev.cel.runtime.planner;
1616

17-
import dev.cel.common.values.CelValue;
1817
import dev.cel.common.values.CelValueConverter;
1918
import dev.cel.runtime.CelEvaluationException;
2019
import dev.cel.runtime.CelResolvedOverload;
@@ -28,12 +27,7 @@ final class EvalZeroArity extends PlannedInterpretable {
2827

2928
@Override
3029
public Object eval(GlobalResolver resolver, ExecutionFrame frame) throws CelEvaluationException {
31-
Object result = resolvedOverload.getDefinition().apply(EMPTY_ARRAY);
32-
Object runtimeValue = celValueConverter.toRuntimeValue(result);
33-
if (runtimeValue instanceof CelValue) {
34-
return celValueConverter.unwrap((CelValue) runtimeValue);
35-
}
36-
return runtimeValue;
30+
return EvalHelpers.dispatch(resolvedOverload, celValueConverter, EMPTY_ARRAY);
3731
}
3832

3933
static EvalZeroArity create(

runtime/src/main/java/dev/cel/runtime/planner/PlannedProgram.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,11 @@ private CelEvaluationException newCelEvaluationException(long exprId, Exception
115115
} else if (e instanceof CelRuntimeException) {
116116
builder = CelEvaluationExceptionBuilder.newBuilder((CelRuntimeException) e);
117117
} else {
118-
builder = CelEvaluationExceptionBuilder.newBuilder(e.getMessage()).setCause(e);
118+
// Unhandled function dispatch failures wraps the original exception with a descriptive message
119+
// (e.g: "Function foo failed with...")
120+
// We need to unwrap the cause here to preserve the original exception message and its cause.
121+
Throwable cause = e.getCause() != null ? e.getCause() : e;
122+
builder = CelEvaluationExceptionBuilder.newBuilder(e.getMessage()).setCause(cause);
119123
}
120124

121125
return builder.setMetadata(metadata(), exprId).build();

runtime/src/test/java/dev/cel/runtime/PlannerInterpreterTest.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,6 @@ public void typeComparisons() {
5252
skipBaselineVerification();
5353
}
5454

55-
@Override
56-
public void optional_errors() {
57-
// TODO: Fix error message for function dispatch failures
58-
skipBaselineVerification();
59-
}
60-
6155
@Override
6256
public void jsonFieldNames() throws Exception {
6357
// TODO: Support JSON field names for planner

runtime/src/test/java/dev/cel/runtime/planner/ProgramPlannerTest.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -397,10 +397,12 @@ public void plan_call_zeroArgs() throws Exception {
397397
public void plan_call_throws() throws Exception {
398398
CelAbstractSyntaxTree ast = compile("error()");
399399
Program program = PLANNER.plan(ast);
400+
String expectedOverloadId = isParseOnly ? "error" : "error_overload";
400401

401402
CelEvaluationException e = assertThrows(CelEvaluationException.class, program::eval);
402-
assertThat(e).hasMessageThat().contains("evaluation error at <input>:5: Intentional error");
403-
assertThat(e).hasCauseThat().isInstanceOf(IllegalArgumentException.class);
403+
assertThat(e).hasMessageThat().contains("evaluation error at <input>:5: Function '" + expectedOverloadId + "' failed with arg(s) ''");
404+
assertThat(e.getCause()).isInstanceOf(IllegalArgumentException.class);
405+
assertThat(e.getCause().getMessage()).contains("Intentional error");
404406
}
405407

406408
@Test

0 commit comments

Comments
 (0)