Skip to content

Commit 298c386

Browse files
l46kokcopybara-github
authored andcommitted
Track source of evaluation errors in planner, surface error location
PiperOrigin-RevId: 845024050
1 parent d240eb9 commit 298c386

24 files changed

+336
-121
lines changed

common/src/main/java/dev/cel/common/values/CelValueConverter.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,6 @@ public Object toRuntimeValue(Object value) {
7272
.map(this::toRuntimeValue)
7373
.map(OptionalValue::create)
7474
.orElse(OptionalValue.EMPTY);
75-
} else if (value instanceof Exception) {
76-
return ErrorValue.create((Exception) value);
7775
}
7876

7977
return normalizePrimitive(value);

common/src/main/java/dev/cel/common/values/ErrorValue.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
"Immutable") // Exception is technically not immutable as the stacktrace is malleable.
3434
public abstract class ErrorValue extends CelValue {
3535

36+
public abstract long exprId();
37+
3638
@Override
3739
public abstract Exception value();
3840

@@ -46,7 +48,7 @@ public CelType celType() {
4648
return SimpleType.ERROR;
4749
}
4850

49-
public static ErrorValue create(Exception value) {
50-
return new AutoValue_ErrorValue(value);
51+
public static ErrorValue create(long exprId, Exception value) {
52+
return new AutoValue_ErrorValue(exprId, value);
5153
}
5254
}

common/src/test/java/dev/cel/common/values/CelValueConverterTest.java

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,6 @@ public void toRuntimeValue_optionalValue() {
3434
assertThat(optionalValue).isEqualTo(OptionalValue.create("test"));
3535
}
3636

37-
@Test
38-
public void toRuntimeValue_errorValue() {
39-
IllegalArgumentException e = new IllegalArgumentException("error");
40-
41-
ErrorValue errorValue = (ErrorValue) CEL_VALUE_CONVERTER.toRuntimeValue(e);
42-
43-
assertThat(errorValue.value()).isEqualTo(e);
44-
}
45-
4637
@Test
4738
@SuppressWarnings("unchecked") // Test only
4839
public void unwrap_optionalValue() {

common/src/test/java/dev/cel/common/values/ErrorValueTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,20 @@ public class ErrorValueTest {
2727
@Test
2828
public void errorValue_construct() {
2929
IllegalArgumentException exception = new IllegalArgumentException("test");
30-
ErrorValue opaqueValue = ErrorValue.create(exception);
30+
ErrorValue opaqueValue = ErrorValue.create(0L, exception);
3131

3232
assertThat(opaqueValue.value()).isEqualTo(exception);
3333
assertThat(opaqueValue.isZeroValue()).isFalse();
3434
}
3535

3636
@Test
3737
public void create_nullValue_throws() {
38-
assertThrows(NullPointerException.class, () -> ErrorValue.create(null));
38+
assertThrows(NullPointerException.class, () -> ErrorValue.create(0L, null));
3939
}
4040

4141
@Test
4242
public void celTypeTest() {
43-
ErrorValue value = ErrorValue.create(new IllegalArgumentException("test"));
43+
ErrorValue value = ErrorValue.create(0L, new IllegalArgumentException("test"));
4444

4545
assertThat(value.celType()).isEqualTo(SimpleType.ERROR);
4646
}

runtime/BUILD.bazel

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ java_library(
1111
exports = [
1212
":evaluation_exception",
1313
":late_function_binding",
14+
":metadata",
1415
"//runtime/src/main/java/dev/cel/runtime",
1516
"//runtime/src/main/java/dev/cel/runtime:descriptor_message_provider",
1617
"//runtime/src/main/java/dev/cel/runtime:function_overload",
17-
"//runtime/src/main/java/dev/cel/runtime:metadata",
1818
"//runtime/src/main/java/dev/cel/runtime:runtime_type_provider",
1919
],
2020
)
@@ -249,3 +249,9 @@ cel_android_library(
249249
name = "program_android",
250250
exports = ["//runtime/src/main/java/dev/cel/runtime:program_android"],
251251
)
252+
253+
java_library(
254+
name = "metadata",
255+
visibility = ["//:internal"],
256+
exports = ["//runtime/src/main/java/dev/cel/runtime:metadata"],
257+
)

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

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ java_library(
1414
],
1515
deps = [
1616
":attribute",
17+
":error_metadata",
1718
":eval_and",
1819
":eval_attribute",
1920
":eval_conditional",
@@ -25,6 +26,7 @@ java_library(
2526
":eval_unary",
2627
":eval_var_args_call",
2728
":eval_zero_arity",
29+
":planned_interpretable",
2830
":planned_program",
2931
"//:auto_value",
3032
"//common:cel_ast",
@@ -51,6 +53,9 @@ java_library(
5153
name = "planned_program",
5254
srcs = ["PlannedProgram.java"],
5355
deps = [
56+
":error_metadata",
57+
":planned_interpretable",
58+
":strict_error_exception",
5459
"//:auto_value",
5560
"//common:runtime_exception",
5661
"//common/values",
@@ -68,6 +73,7 @@ java_library(
6873
name = "eval_const",
6974
srcs = ["EvalConstant.java"],
7075
deps = [
76+
":planned_interpretable",
7177
"//common/values",
7278
"//common/values:cel_byte_string",
7379
"//runtime:evaluation_listener",
@@ -99,6 +105,7 @@ java_library(
99105
srcs = ["EvalAttribute.java"],
100106
deps = [
101107
":attribute",
108+
":planned_interpretable",
102109
"//runtime:evaluation_listener",
103110
"//runtime:function_resolver",
104111
"//runtime:interpretable",
@@ -111,6 +118,7 @@ java_library(
111118
name = "eval_zero_arity",
112119
srcs = ["EvalZeroArity.java"],
113120
deps = [
121+
":planned_interpretable",
114122
"//runtime:evaluation_exception",
115123
"//runtime:evaluation_listener",
116124
"//runtime:function_resolver",
@@ -123,6 +131,8 @@ java_library(
123131
name = "eval_unary",
124132
srcs = ["EvalUnary.java"],
125133
deps = [
134+
":eval_helpers",
135+
":planned_interpretable",
126136
"//runtime:evaluation_exception",
127137
"//runtime:evaluation_listener",
128138
"//runtime:function_resolver",
@@ -135,6 +145,8 @@ java_library(
135145
name = "eval_var_args_call",
136146
srcs = ["EvalVarArgsCall.java"],
137147
deps = [
148+
":eval_helpers",
149+
":planned_interpretable",
138150
"//runtime:evaluation_exception",
139151
"//runtime:evaluation_listener",
140152
"//runtime:function_resolver",
@@ -148,6 +160,7 @@ java_library(
148160
srcs = ["EvalOr.java"],
149161
deps = [
150162
":eval_helpers",
163+
":planned_interpretable",
151164
"//common/values",
152165
"//runtime:evaluation_listener",
153166
"//runtime:function_resolver",
@@ -161,6 +174,7 @@ java_library(
161174
srcs = ["EvalAnd.java"],
162175
deps = [
163176
":eval_helpers",
177+
":planned_interpretable",
164178
"//common/values",
165179
"//runtime:evaluation_listener",
166180
"//runtime:function_resolver",
@@ -173,6 +187,7 @@ java_library(
173187
name = "eval_conditional",
174188
srcs = ["EvalConditional.java"],
175189
deps = [
190+
":planned_interpretable",
176191
"//runtime:evaluation_exception",
177192
"//runtime:evaluation_listener",
178193
"//runtime:function_resolver",
@@ -185,6 +200,7 @@ java_library(
185200
name = "eval_create_struct",
186201
srcs = ["EvalCreateStruct.java"],
187202
deps = [
203+
":planned_interpretable",
188204
"//common/types",
189205
"//common/values",
190206
"//common/values:cel_value_provider",
@@ -201,6 +217,7 @@ java_library(
201217
name = "eval_create_list",
202218
srcs = ["EvalCreateList.java"],
203219
deps = [
220+
":planned_interpretable",
204221
"//runtime:evaluation_exception",
205222
"//runtime:evaluation_listener",
206223
"//runtime:function_resolver",
@@ -214,6 +231,7 @@ java_library(
214231
name = "eval_create_map",
215232
srcs = ["EvalCreateMap.java"],
216233
deps = [
234+
":planned_interpretable",
217235
"//runtime:evaluation_exception",
218236
"//runtime:evaluation_listener",
219237
"//runtime:function_resolver",
@@ -227,7 +245,39 @@ java_library(
227245
name = "eval_helpers",
228246
srcs = ["EvalHelpers.java"],
229247
deps = [
248+
":planned_interpretable",
249+
":strict_error_exception",
250+
"//common:error_codes",
251+
"//common:runtime_exception",
230252
"//common/values",
231253
"//runtime:interpretable",
232254
],
233255
)
256+
257+
java_library(
258+
name = "strict_error_exception",
259+
srcs = ["StrictErrorException.java"],
260+
deps = [
261+
"//common:error_codes",
262+
"//common:runtime_exception",
263+
],
264+
)
265+
266+
java_library(
267+
name = "error_metadata",
268+
srcs = ["ErrorMetadata.java"],
269+
deps = [
270+
"//runtime:metadata",
271+
"@maven//:com_google_errorprone_error_prone_annotations",
272+
"@maven//:com_google_guava_guava",
273+
],
274+
)
275+
276+
java_library(
277+
name = "planned_interpretable",
278+
srcs = ["PlannedInterpretable.java"],
279+
deps = [
280+
"//runtime:interpretable",
281+
"@maven//:com_google_errorprone_error_prone_annotations",
282+
],
283+
)
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright 2025 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.planner;
16+
17+
import static com.google.common.base.Preconditions.checkNotNull;
18+
19+
import com.google.common.collect.ImmutableMap;
20+
import com.google.errorprone.annotations.Immutable;
21+
import dev.cel.runtime.Metadata;
22+
23+
@Immutable
24+
final class ErrorMetadata implements Metadata {
25+
26+
private final ImmutableMap<Long, Integer> exprIdToPositionMap;
27+
private final String location;
28+
29+
@Override
30+
public String getLocation() {
31+
return location;
32+
}
33+
34+
@Override
35+
public int getPosition(long exprId) {
36+
return exprIdToPositionMap.getOrDefault(exprId, 0);
37+
}
38+
39+
@Override
40+
public boolean hasPosition(long exprId) {
41+
return exprIdToPositionMap.containsKey(exprId);
42+
}
43+
44+
static ErrorMetadata create(ImmutableMap<Long, Integer> exprIdToPositionMap, String location) {
45+
return new ErrorMetadata(exprIdToPositionMap, location);
46+
}
47+
48+
private ErrorMetadata(ImmutableMap<Long, Integer> exprIdToPositionMap, String location) {
49+
this.exprIdToPositionMap = checkNotNull(exprIdToPositionMap);
50+
this.location = checkNotNull(location);
51+
}
52+
}

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,16 @@
2121
import dev.cel.runtime.CelEvaluationListener;
2222
import dev.cel.runtime.CelFunctionResolver;
2323
import dev.cel.runtime.GlobalResolver;
24-
import dev.cel.runtime.Interpretable;
2524

26-
final class EvalAnd implements Interpretable {
25+
final class EvalAnd extends PlannedInterpretable {
2726

2827
@SuppressWarnings("Immutable")
29-
private final Interpretable[] args;
28+
private final PlannedInterpretable[] args;
3029

3130
@Override
3231
public Object eval(GlobalResolver resolver) {
3332
ErrorValue errorValue = null;
34-
for (Interpretable arg : args) {
33+
for (PlannedInterpretable arg : args) {
3534
Object argVal = evalNonstrictly(arg, resolver);
3635
if (argVal instanceof Boolean) {
3736
// Short-circuit on false
@@ -75,11 +74,12 @@ public Object eval(
7574
throw new UnsupportedOperationException("Not yet supported");
7675
}
7776

78-
static EvalAnd create(Interpretable[] args) {
79-
return new EvalAnd(args);
77+
static EvalAnd create(long exprId, PlannedInterpretable[] args) {
78+
return new EvalAnd(exprId, args);
8079
}
8180

82-
private EvalAnd(Interpretable[] args) {
81+
private EvalAnd(long exprId, PlannedInterpretable[] args) {
82+
super(exprId);
8383
Preconditions.checkArgument(args.length == 2);
8484
this.args = args;
8585
}

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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,9 @@
1818
import dev.cel.runtime.CelEvaluationListener;
1919
import dev.cel.runtime.CelFunctionResolver;
2020
import dev.cel.runtime.GlobalResolver;
21-
import dev.cel.runtime.Interpretable;
2221

2322
@Immutable
24-
final class EvalAttribute implements Interpretable {
23+
final class EvalAttribute extends PlannedInterpretable {
2524

2625
private final Attribute attr;
2726

@@ -47,15 +46,15 @@ public Object eval(
4746
GlobalResolver resolver,
4847
CelFunctionResolver lateBoundFunctionResolver,
4948
CelEvaluationListener listener) {
50-
// TODO: Implement support
5149
throw new UnsupportedOperationException("Not yet supported");
5250
}
5351

54-
static EvalAttribute create(Attribute attr) {
55-
return new EvalAttribute(attr);
52+
static EvalAttribute create(long exprId, Attribute attr) {
53+
return new EvalAttribute(exprId, attr);
5654
}
5755

58-
private EvalAttribute(Attribute attr) {
56+
private EvalAttribute(long exprId, Attribute attr) {
57+
super(exprId);
5958
this.attr = attr;
6059
}
6160
}

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import dev.cel.runtime.GlobalResolver;
2222
import dev.cel.runtime.Interpretable;
2323

24-
final class EvalConditional implements Interpretable {
24+
final class EvalConditional extends PlannedInterpretable {
2525

2626
@SuppressWarnings("Immutable")
2727
private final Interpretable[] args;
@@ -67,11 +67,12 @@ public Object eval(
6767
throw new UnsupportedOperationException("Not yet supported");
6868
}
6969

70-
static EvalConditional create(Interpretable[] args) {
71-
return new EvalConditional(args);
70+
static EvalConditional create(long exprId, Interpretable[] args) {
71+
return new EvalConditional(exprId, args);
7272
}
7373

74-
private EvalConditional(Interpretable[] args) {
74+
private EvalConditional(long exprId, Interpretable[] args) {
75+
super(exprId);
7576
Preconditions.checkArgument(args.length == 3);
7677
this.args = args;
7778
}

0 commit comments

Comments
 (0)