Skip to content

Commit 4f461de

Browse files
l46kokcopybara-github
authored andcommitted
Hoist loop-invariant subexpressions in SubexpressionOptimizer
PiperOrigin-RevId: 1005057100
1 parent 3c5d875 commit 4f461de

9 files changed

Lines changed: 2360 additions & 617 deletions

File tree

‎optimizer/src/main/java/dev/cel/optimizer/optimizers/BUILD.bazel‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,13 @@ java_library(
6060
":default_optimizer_constants",
6161
"//:auto_value",
6262
"//bundle:cel",
63+
"//checker:standard_decl",
6364
"//common:cel_ast",
6465
"//common:cel_source",
6566
"//common:compiler_common",
6667
"//common:mutable_ast",
6768
"//common:mutable_source",
69+
"//common:operator",
6870
"//common/ast",
6971
"//common/ast:cel_block",
7072
"//common/ast:mutable_expr",

‎optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java‎

Lines changed: 241 additions & 20 deletions
Large diffs are not rendered by default.

‎optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java‎

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import static com.google.common.truth.Truth.assertThat;
1818
import static dev.cel.common.CelOverloadDecl.newGlobalOverload;
1919

20+
import com.google.common.collect.ImmutableList;
2021
import com.google.common.collect.ImmutableMap;
2122
import com.google.testing.junit.testparameterinjector.TestParameter;
2223
import com.google.testing.junit.testparameterinjector.TestParameterInjector;
@@ -95,6 +96,8 @@ private static Cel setupCelEnv(CelBuilder celBuilder) {
9596
TestAllTypes.newBuilder()
9697
.setSingleInt64(3L)
9798
.setSingleInt32(5)
99+
.addAllRepeatedInt64(ImmutableList.of(1L, 2L, 3L))
100+
.addRepeatedInt32(2)
98101
.setOneofType(
99102
NestedTestAllTypes.newBuilder()
100103
.setPayload(
@@ -403,7 +406,37 @@ private enum CseTestCase {
403406
"pure_custom_func(msg.oneof_type.payload.single_int64) +"
404407
+ " pure_custom_func(msg.oneof_type.payload.single_int32) +"
405408
+ " pure_custom_func(msg.oneof_type.payload.single_int64) +"
406-
+ " pure_custom_func(msg.single_int64)");
409+
+ " pure_custom_func(msg.single_int64)"),
410+
VALUE_NUMBERING_COMMUTATIVE_ADD_CONVERSE_RELATION_LOGICAL_AND(
411+
"(msg.single_int64 + msg.single_int32 > 5 && msg.oneof_type.payload.single_int64 <"
412+
+ " msg.single_int64 + msg.single_int32) == (msg.single_int32 + msg.single_int64 >"
413+
+ " msg.oneof_type.payload.single_int64 && 5 < msg.single_int32 + msg.single_int64)"),
414+
VALUE_NUMBERING_COMMUTATIVE_MULTIPLY_EQUALITY_LOGICAL_OR(
415+
"(msg.oneof_type.payload.single_int32 * msg.single_int64 == 24 || msg.single_int32 !="
416+
+ " msg.oneof_type.payload.single_int64) && (msg.oneof_type.payload.single_int64 !="
417+
+ " msg.single_int32 || 24 == msg.single_int64 * msg.oneof_type.payload.single_int32)"),
418+
HOIST_NESTED_COMPREHENSION("msg.repeated_int64.all(i, msg.repeated_int32.exists(j, j == 2))"),
419+
HOIST_INVARIANT_ARITHMETIC(
420+
"msg.repeated_int64.exists(i, i == msg.single_int64 * 2 + msg.single_int32)"),
421+
HOIST_ZERO_TRIP_ERROR_NOT_EVALUATED(
422+
"msg.repeated_nested_message.exists(m, m.bb == 1 / (msg.single_int32 - 5))"),
423+
HOIST_MAP_ACCUMULATION_PRESERVED("msg.repeated_int64.map(i, msg.single_int64 * 2)"),
424+
HOIST_LIST_LITERAL("msg.repeated_int64.exists(i, i in [msg.single_int64, msg.single_int32])"),
425+
HOIST_LIST_APPENDED_TO_ITER_VAR("[[1], [2]].map(l, l + [msg.single_int64])"),
426+
HOIST_INVARIANT_INSIDE_DUPLICATE(
427+
"msg.repeated_int64.exists(i, i in [msg.single_int64, msg.single_int32]) ||"
428+
+ " msg.repeated_int64.exists(i, i in [msg.single_int64, msg.single_int32])"),
429+
HOIST_INVARIANT_OF_NESTED_COMPREHENSION(
430+
"msg.repeated_int64.all(i, msg.repeated_int32.exists(j, j == msg.single_int64 * 2))"),
431+
HOIST_SHARED_TERMS_ONCE(
432+
"msg.repeated_int64.exists(i, i == msg.single_int64 + msg.single_int32 +"
433+
+ " msg.single_sint64) && [msg.single_int64, msg.single_int32, msg.single_sint64]"
434+
+ ".size() > 0"),
435+
HOIST_SHARED_WITH_ACCUMULATED_LIST(
436+
"msg.repeated_int64.exists(i, i in [msg.single_int64]) &&"
437+
+ " msg.repeated_int64.map(i, msg.single_int64).size() > 0"),
438+
;
439+
407440
private final String source;
408441

409442
CseTestCase(String source) {

‎optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java‎

Lines changed: 176 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,9 @@ private static Cel setupCelEnv(CelBuilder celBuilder) {
7979
.populateMacroCalls(true)
8080
.enableHeterogeneousNumericComparisons(true)
8181
.build())
82-
.addCompilerLibraries(CelExtensions.bindings(), CelExtensions.strings())
83-
.addRuntimeLibraries(CelExtensions.strings())
82+
.addCompilerLibraries(
83+
CelExtensions.bindings(), CelExtensions.strings(), CelExtensions.optional())
84+
.addRuntimeLibraries(CelExtensions.strings(), CelExtensions.optional())
8485
.addFunctionDeclarations(
8586
CelFunctionDecl.newFunctionDeclaration(
8687
"non_pure_custom_func",
@@ -756,12 +757,12 @@ public void cse_nestedMacro_noOp_assertAstIdCorrectness() throws Exception {
756757
.addAstOptimizers(SubexpressionOptimizer.getInstance())
757758
.build();
758759
CelAbstractSyntaxTree ast =
759-
cel.compile("[{}, {\"a\": 1}, {\"b\": 2}].filter(m, has(x.a))").getAst();
760+
cel.compile("[{}, {\"a\": 1}, {\"b\": 2}].filter(m, has(m.a))").getAst();
760761

761762
CelAbstractSyntaxTree optimizedAst = celOptimizer.optimize(ast);
762763

763764
assertThat(CEL_UNPARSER.unparse(optimizedAst))
764-
.isEqualTo("[{}, {\"a\": 1}, {\"b\": 2}].filter(m, has(x.a))");
765+
.isEqualTo("[{}, {\"a\": 1}, {\"b\": 2}].filter(m, has(m.a))");
765766
assertThat(optimizedAst).isSameInstanceAs(ast);
766767
}
767768

@@ -796,8 +797,8 @@ public void cse_nestedMacro_withOptimization_assertAstIdCorrectness() throws Exc
796797

797798
assertThat(CEL_UNPARSER.unparse(optimizedAst))
798799
.isEqualTo(
799-
"cel.@block([[{}, {\"a\": 1}, {\"b\": 2}].filter(@it:0:0, has(x.a))], @index0 =="
800-
+ " @index0)");
800+
"cel.@block([has(x.a), [{}, {\"a\": 1}, {\"b\": 2}].filter(@it:0:0, @index0)], @index1"
801+
+ " == @index1)");
801802
}
802803

803804
@Test
@@ -822,6 +823,175 @@ public void optimize_afterSelectOptimizer_throwsException(
822823
.contains("SubexpressionOptimizer must run before SelectOptimizer.");
823824
}
824825

826+
private enum ValueNumberingTestCase {
827+
COMMUTATIVE_INT_ADD(
828+
"(msg.single_int64 + msg.single_int32) * (msg.single_int32 + msg.single_int64)",
829+
"cel.@block([msg.single_int64 + msg.single_int32], @index0 * @index0)"),
830+
COMMUTATIVE_UINT_MULTIPLY(
831+
"(msg.single_uint64 * msg.single_uint32) + (msg.single_uint32 * msg.single_uint64)",
832+
"cel.@block([msg.single_uint64 * msg.single_uint32], @index0 + @index0)"),
833+
COMMUTATIVE_DOUBLE_ADD(
834+
"(msg.single_double + 1.5) * (1.5 + msg.single_double)",
835+
"cel.@block([msg.single_double + 1.5], @index0 * @index0)"),
836+
COMMUTATIVE_DURATION_TIMESTAMP_ADD(
837+
"(msg.single_duration + msg.single_timestamp) == (msg.single_timestamp +"
838+
+ " msg.single_duration)",
839+
"cel.@block([msg.single_duration + msg.single_timestamp], @index0 == @index0)"),
840+
NON_COMMUTATIVE_INT_SUBTRACT_PRESERVED(
841+
"(msg.single_int64 - msg.single_int32) == (msg.single_int32 - msg.single_int64)",
842+
"cel.@block([msg.single_int32, msg.single_int64], @index1 - @index0 == @index0 - @index1)"),
843+
NON_COMMUTATIVE_STRING_CONCAT_PRESERVED(
844+
"(msg.single_string + \"a\") == (\"a\" + msg.single_string)",
845+
"cel.@block([msg.single_string], @index0 + \"a\" == \"a\" + @index0)"),
846+
NON_COMMUTATIVE_DYN_ADD_PRESERVED(
847+
"(dyn(msg.single_string) + dyn(\"a\")) == (dyn(\"a\") + dyn(msg.single_string))",
848+
"cel.@block([dyn(\"a\"), dyn(msg.single_string)], @index1 + @index0 == @index0 +"
849+
+ " @index1)"),
850+
COMMUTATIVE_EQUALS(
851+
"(msg.single_int64 == 1) && (1 == msg.single_int64)",
852+
"cel.@block([msg.single_int64 == 1], @index0 && @index0)"),
853+
COMMUTATIVE_NOT_EQUALS(
854+
"(msg.single_int64 != 1) || (1 != msg.single_int64)",
855+
"cel.@block([msg.single_int64 != 1], @index0 || @index0)"),
856+
COMMUTATIVE_LOGICAL_AND(
857+
"((msg.single_int64 == 1) && (msg.single_int32 == 2)) || ((msg.single_int32 == 2) &&"
858+
+ " (msg.single_int64 == 1))",
859+
"cel.@block([msg.single_int64 == 1 && msg.single_int32 == 2], @index0 || @index0)"),
860+
COMMUTATIVE_LOGICAL_OR(
861+
"((msg.single_int64 == 1) || (msg.single_int32 == 2)) && ((msg.single_int32 == 2) ||"
862+
+ " (msg.single_int64 == 1))",
863+
"cel.@block([msg.single_int64 == 1 || msg.single_int32 == 2], @index0 && @index0)"),
864+
RELATIONAL_CONVERSE_LESS_GREATER(
865+
"(msg.single_int64 < msg.single_int32) && (msg.single_int32 > msg.single_int64)",
866+
"cel.@block([msg.single_int64 < msg.single_int32], @index0 && @index0)"),
867+
RELATIONAL_CONVERSE_LESS_EQUALS_GREATER_EQUALS(
868+
"(msg.single_int64 <= msg.single_int32) && (msg.single_int32 >= msg.single_int64)",
869+
"cel.@block([msg.single_int64 <= msg.single_int32], @index0 && @index0)"),
870+
NOT_EQUALS_WITHOUT_SHARED_EQUALS_PRESERVED(
871+
"[msg.single_int64 != 1, msg.single_int64 != 1, msg.single_int64 == 1]",
872+
"cel.@block([msg.single_int64 != 1], [@index0, @index0, msg.single_int64 == 1])"),
873+
OPTIONAL_LIST_AND_MAP_DISTINCT_VALUE_NUMBERS(
874+
"([?optional.of(msg.single_int64)].size() == [optional.of(msg.single_int64)].size()) &&"
875+
+ " ({?\"k\": optional.of(msg.single_int64)}.size() == {\"k\":"
876+
+ " optional.of(msg.single_int64)}.size())",
877+
"cel.@block([optional.of(msg.single_int64)], [?@index0].size() == [@index0].size() &&"
878+
+ " {?\"k\": @index0}.size() == {\"k\": @index0}.size())"),
879+
;
880+
881+
private final String source;
882+
private final String expectedUnparsed;
883+
884+
ValueNumberingTestCase(String source, String expectedUnparsed) {
885+
this.source = source;
886+
this.expectedUnparsed = expectedUnparsed;
887+
}
888+
}
889+
890+
@Test
891+
public void cse_valueNumbering(@TestParameter ValueNumberingTestCase testCase) throws Exception {
892+
CelAbstractSyntaxTree ast = cel.compile(testCase.source).getAst();
893+
CelOptimizer optimizer =
894+
newCseOptimizer(
895+
SubexpressionOptimizerOptions.newBuilder().populateMacroCalls(true).build());
896+
ImmutableMap<String, Object> input =
897+
ImmutableMap.of(
898+
"msg",
899+
TestAllTypes.newBuilder()
900+
.setSingleInt64(1L)
901+
.setSingleInt32(2)
902+
.setSingleUint64(3L)
903+
.setSingleUint32(4)
904+
.setSingleDouble(2.5)
905+
.setSingleString("hello")
906+
.build());
907+
908+
CelAbstractSyntaxTree optimizedAst = optimizer.optimize(ast);
909+
910+
assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(testCase.expectedUnparsed);
911+
assertThat(cel.createProgram(optimizedAst).eval(input))
912+
.isEqualTo(cel.createProgram(ast).eval(input));
913+
}
914+
915+
@Test
916+
public void cse_customOperatorOverloads_preservesSemantics(
917+
@TestParameter({
918+
"(msg.single_string + msg.single_int64) == (msg.single_int64 + msg.single_string)",
919+
"(msg.single_string > msg.single_int64) == (msg.single_int64 < msg.single_string)"
920+
})
921+
String source)
922+
throws Exception {
923+
Cel cel =
924+
this.cel
925+
.toCelBuilder()
926+
.addFunctionDeclarations(
927+
CelFunctionDecl.newFunctionDeclaration(
928+
"_+_",
929+
newGlobalOverload(
930+
"add_string_int", SimpleType.INT, SimpleType.STRING, SimpleType.INT),
931+
newGlobalOverload(
932+
"add_int_string", SimpleType.INT, SimpleType.INT, SimpleType.STRING)),
933+
CelFunctionDecl.newFunctionDeclaration(
934+
"_>_",
935+
newGlobalOverload(
936+
"greater_string_int", SimpleType.BOOL, SimpleType.STRING, SimpleType.INT)),
937+
CelFunctionDecl.newFunctionDeclaration(
938+
"_<_",
939+
newGlobalOverload(
940+
"less_int_string", SimpleType.BOOL, SimpleType.INT, SimpleType.STRING)))
941+
.addFunctionBindings(
942+
CelFunctionBinding.from(
943+
"add_string_int", String.class, Long.class, (s, i) -> s.length() + i),
944+
CelFunctionBinding.from(
945+
"add_int_string", Long.class, String.class, (i, s) -> i * 100 + s.length()),
946+
CelFunctionBinding.from(
947+
"greater_string_int", String.class, Long.class, (s, i) -> s.length() > i),
948+
CelFunctionBinding.from(
949+
"less_int_string", Long.class, String.class, (i, s) -> i >= 0))
950+
.build();
951+
CelOptimizer optimizer =
952+
CelOptimizerFactory.standardCelOptimizerBuilder(cel)
953+
.addAstOptimizers(SubexpressionOptimizer.getInstance())
954+
.build();
955+
CelAbstractSyntaxTree ast = cel.compile(source).getAst();
956+
ImmutableMap<String, Object> input =
957+
ImmutableMap.of(
958+
"msg", TestAllTypes.newBuilder().setSingleString("a").setSingleInt64(1L).build());
959+
960+
CelAbstractSyntaxTree optimizedAst = optimizer.optimize(ast);
961+
962+
assertThat(cel.createProgram(optimizedAst).eval(input))
963+
.isEqualTo(cel.createProgram(ast).eval(input));
964+
}
965+
966+
@Test
967+
public void cse_oneSidedCustomOverloadOnDyn_notMerged(
968+
@TestParameter({"(x < 5) == (5 > x)", "(x + 1) == (1 + x)"}) String source) throws Exception {
969+
// With x: dyn, only the left operand also resolves to the custom overload, so the right one is
970+
// standard-only and swappable. The two must not share a value number.
971+
Cel cel =
972+
this.cel
973+
.toCelBuilder()
974+
.addFunctionDeclarations(
975+
CelFunctionDecl.newFunctionDeclaration(
976+
"_<_",
977+
newGlobalOverload(
978+
"less_string_int", SimpleType.BOOL, SimpleType.STRING, SimpleType.INT)),
979+
CelFunctionDecl.newFunctionDeclaration(
980+
"_+_",
981+
newGlobalOverload(
982+
"add_string_int", SimpleType.INT, SimpleType.STRING, SimpleType.INT)))
983+
.build();
984+
CelOptimizer optimizer =
985+
CelOptimizerFactory.standardCelOptimizerBuilder(cel)
986+
.addAstOptimizers(SubexpressionOptimizer.getInstance())
987+
.build();
988+
CelAbstractSyntaxTree ast = cel.compile(source).getAst();
989+
990+
CelAbstractSyntaxTree optimizedAst = optimizer.optimize(ast);
991+
992+
assertThat(CEL_UNPARSER.unparse(optimizedAst)).isEqualTo(CEL_UNPARSER.unparse(ast));
993+
}
994+
825995
/**
826996
* Converts AST containing cel.block related test functions to internal functions (e.g: cel.block
827997
* -> cel.@block)

‎optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline‎

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,4 +314,76 @@ Test case: CUSTOM_FUNCTION_ELIMINABLE
314314
Source: pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.oneof_type.payload.single_int32) + pure_custom_func(msg.oneof_type.payload.single_int64) + pure_custom_func(msg.single_int64)
315315
=====>
316316
Result: 31
317-
Unparsed: cel.@block([msg.oneof_type.payload, pure_custom_func(@index0.single_int64)], @index1 + pure_custom_func(@index0.single_int32) + @index1 + pure_custom_func(msg.single_int64))
317+
Unparsed: cel.@block([msg.oneof_type.payload, pure_custom_func(@index0.single_int64)], @index1 + pure_custom_func(@index0.single_int32) + @index1 + pure_custom_func(msg.single_int64))
318+
319+
Test case: VALUE_NUMBERING_COMMUTATIVE_ADD_CONVERSE_RELATION_LOGICAL_AND
320+
Source: (msg.single_int64 + msg.single_int32 > 5 && msg.oneof_type.payload.single_int64 < msg.single_int64 + msg.single_int32) == (msg.single_int32 + msg.single_int64 > msg.oneof_type.payload.single_int64 && 5 < msg.single_int32 + msg.single_int64)
321+
=====>
322+
Result: true
323+
Unparsed: cel.@block([msg.single_int64 + msg.single_int32, @index0 > 5 && msg.oneof_type.payload.single_int64 < @index0], @index1 == @index1)
324+
325+
Test case: VALUE_NUMBERING_COMMUTATIVE_MULTIPLY_EQUALITY_LOGICAL_OR
326+
Source: (msg.oneof_type.payload.single_int32 * msg.single_int64 == 24 || msg.single_int32 != msg.oneof_type.payload.single_int64) && (msg.oneof_type.payload.single_int64 != msg.single_int32 || 24 == msg.single_int64 * msg.oneof_type.payload.single_int32)
327+
=====>
328+
Result: true
329+
Unparsed: cel.@block([msg.oneof_type.payload, @index0.single_int32 * msg.single_int64 == 24 || msg.single_int32 != @index0.single_int64], @index1 && @index1)
330+
331+
Test case: HOIST_NESTED_COMPREHENSION
332+
Source: msg.repeated_int64.all(i, msg.repeated_int32.exists(j, j == 2))
333+
=====>
334+
Result: true
335+
Unparsed: cel.@block([msg.repeated_int32.exists(@it:0:0, @it:0:0 == 2)], msg.repeated_int64.all(@it:1:0, @index0))
336+
337+
Test case: HOIST_INVARIANT_ARITHMETIC
338+
Source: msg.repeated_int64.exists(i, i == msg.single_int64 * 2 + msg.single_int32)
339+
=====>
340+
Result: false
341+
Unparsed: cel.@block([msg.single_int64 * 2 + msg.single_int32], msg.repeated_int64.exists(@it:0:0, @it:0:0 == @index0))
342+
343+
Test case: HOIST_ZERO_TRIP_ERROR_NOT_EVALUATED
344+
Source: msg.repeated_nested_message.exists(m, m.bb == 1 / (msg.single_int32 - 5))
345+
=====>
346+
Result: false
347+
Unparsed: cel.@block([1 / (msg.single_int32 - 5)], msg.repeated_nested_message.exists(@it:0:0, @it:0:0.bb == @index0))
348+
349+
Test case: HOIST_MAP_ACCUMULATION_PRESERVED
350+
Source: msg.repeated_int64.map(i, msg.single_int64 * 2)
351+
=====>
352+
Result: [6, 6, 6]
353+
Unparsed: cel.@block([msg.single_int64 * 2], msg.repeated_int64.map(@it:0:0, @index0))
354+
355+
Test case: HOIST_LIST_LITERAL
356+
Source: msg.repeated_int64.exists(i, i in [msg.single_int64, msg.single_int32])
357+
=====>
358+
Result: true
359+
Unparsed: cel.@block([[msg.single_int64, msg.single_int32]], msg.repeated_int64.exists(@it:0:0, @it:0:0 in @index0))
360+
361+
Test case: HOIST_LIST_APPENDED_TO_ITER_VAR
362+
Source: [[1], [2]].map(l, l + [msg.single_int64])
363+
=====>
364+
Result: [[1, 3], [2, 3]]
365+
Unparsed: cel.@block([[msg.single_int64]], [[1], [2]].map(@it:0:0, @it:0:0 + @index0))
366+
367+
Test case: HOIST_INVARIANT_INSIDE_DUPLICATE
368+
Source: msg.repeated_int64.exists(i, i in [msg.single_int64, msg.single_int32]) || msg.repeated_int64.exists(i, i in [msg.single_int64, msg.single_int32])
369+
=====>
370+
Result: true
371+
Unparsed: cel.@block([[msg.single_int64, msg.single_int32], msg.repeated_int64.exists(@it:0:0, @it:0:0 in @index0)], @index1 || @index1)
372+
373+
Test case: HOIST_INVARIANT_OF_NESTED_COMPREHENSION
374+
Source: msg.repeated_int64.all(i, msg.repeated_int32.exists(j, j == msg.single_int64 * 2))
375+
=====>
376+
Result: false
377+
Unparsed: cel.@block([msg.single_int64 * 2, msg.repeated_int32.exists(@it:0:0, @it:0:0 == @index0)], msg.repeated_int64.all(@it:1:0, @index1))
378+
379+
Test case: HOIST_SHARED_TERMS_ONCE
380+
Source: msg.repeated_int64.exists(i, i == msg.single_int64 + msg.single_int32 + msg.single_sint64) && [msg.single_int64, msg.single_int32, msg.single_sint64].size() > 0
381+
=====>
382+
Result: false
383+
Unparsed: cel.@block([msg.single_int64, msg.single_int32, msg.single_sint64, @index0 + @index1 + @index2], msg.repeated_int64.exists(@it:0:0, @it:0:0 == @index3) && [@index0, @index1, @index2].size() > 0)
384+
385+
Test case: HOIST_SHARED_WITH_ACCUMULATED_LIST
386+
Source: msg.repeated_int64.exists(i, i in [msg.single_int64]) && msg.repeated_int64.map(i, msg.single_int64).size() > 0
387+
=====>
388+
Result: true
389+
Unparsed: cel.@block([msg.single_int64, [@index0], msg.repeated_int64], @index2.exists(@it:0:0, @it:0:0 in @index1) && @index2.map(@it:0:1, @index0).size() > 0)

‎optimizer/src/test/resources/large_expressions_block_common_subexpr.baseline‎

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)