| 105 | }; |
| 106 | |
| 107 | IsConst IsConstExpr(const Expr& expr, const Resolver& resolver) { |
| 108 | switch (expr.kind_case()) { |
| 109 | case ExprKindCase::kConstant: |
| 110 | return IsConst::kConditional; |
| 111 | case ExprKindCase::kIdentExpr: |
| 112 | return IsConst::kNonConst; |
| 113 | case ExprKindCase::kComprehensionExpr: |
| 114 | // Not yet supported, need to identify whether range and |
| 115 | // iter vars are compatible with const folding. |
| 116 | return IsConst::kNonConst; |
| 117 | case ExprKindCase::kStructExpr: |
| 118 | return IsConst::kNonConst; |
| 119 | case ExprKindCase::kMapExpr: |
| 120 | // Empty maps are rare and not currently supported as they may eventually |
| 121 | // have similar issues to empty list when used within comprehensions or |
| 122 | // macros. |
| 123 | if (expr.map_expr().entries().empty()) { |
| 124 | return IsConst::kNonConst; |
| 125 | } |
| 126 | return IsConst::kConditional; |
| 127 | case ExprKindCase::kListExpr: |
| 128 | if (expr.list_expr().elements().empty()) { |
| 129 | // Don't fold for empty list to allow comprehension |
| 130 | // list append optimization. |
| 131 | return IsConst::kNonConst; |
| 132 | } |
| 133 | return IsConst::kConditional; |
| 134 | case ExprKindCase::kSelectExpr: |
| 135 | return IsConst::kConditional; |
| 136 | case ExprKindCase::kCallExpr: { |
| 137 | const auto& call = expr.call_expr(); |
| 138 | // Short Circuiting operators not yet supported. |
| 139 | if (call.function() == kAnd || call.function() == kOr || |
| 140 | call.function() == kTernary) { |
| 141 | return IsConst::kNonConst; |
| 142 | } |
| 143 | // For now we skip constant folding for cel.@block. We do not yet setup |
| 144 | // slots. When we enable constant folding for comprehensions (like |
| 145 | // cel.bind), we can address cel.@block. |
| 146 | if (call.function() == "cel.@block") { |
| 147 | return IsConst::kNonConst; |
| 148 | } |
| 149 | |
| 150 | int arg_len = call.args().size() + (call.has_target() ? 1 : 0); |
| 151 | // Check for any lazy overloads (activation dependant) |
| 152 | if (!resolver |
| 153 | .FindLazyOverloads(call.function(), call.has_target(), arg_len) |
| 154 | .empty()) { |
| 155 | return IsConst::kNonConst; |
| 156 | } |
| 157 | |
| 158 | auto overloads = |
| 159 | resolver.FindOverloads(call.function(), call.has_target(), arg_len); |
| 160 | // Check for any contextual overloads. If there are any, we cowardly |
| 161 | // avoid constant folding instead of trying to check if one of the |
| 162 | // overloads would be safe to use. |
| 163 | for (const auto& overload : overloads) { |
| 164 | if (overload.descriptor.is_contextual()) { |
no test coverage detected