Optimize queries the expression graph for scalar and aggregate literal expressions within call and select statements and then evaluates them and replaces the call site with the literal result. Note: only values which can be represented as literals in CEL syntax are supported.
(ctx *OptimizerContext, a *ast.AST)
| 81 | // |
| 82 | // Note: only values which can be represented as literals in CEL syntax are supported. |
| 83 | func (opt *constantFoldingOptimizer) Optimize(ctx *OptimizerContext, a *ast.AST) *ast.AST { |
| 84 | root := ast.NavigateAST(a) |
| 85 | |
| 86 | // Walk the list of foldable expression and continue to fold until there are no more folds left. |
| 87 | // All of the fold candidates returned by the constantExprMatcher should succeed unless there's |
| 88 | // a logic bug with the selection of expressions. |
| 89 | constantExprMatcherCapture := func(e ast.NavigableExpr) bool { return opt.constantExprMatcher(ctx, a, e) } |
| 90 | foldableExprs := ast.MatchDescendants(root, constantExprMatcherCapture) |
| 91 | foldCount := 0 |
| 92 | for len(foldableExprs) != 0 && foldCount < opt.maxFoldIterations { |
| 93 | for _, fold := range foldableExprs { |
| 94 | // If the expression could be folded because it's a non-strict call, and the |
| 95 | // branches are pruned, continue to the next fold. |
| 96 | if fold.Kind() == ast.CallKind && maybePruneBranches(ctx, fold) { |
| 97 | continue |
| 98 | } |
| 99 | // Late-bound function calls cannot be folded. |
| 100 | if fold.Kind() == ast.CallKind && isLateBoundFunctionCall(ctx, fold) { |
| 101 | continue |
| 102 | } |
| 103 | // Otherwise, assume all context is needed to evaluate the expression. |
| 104 | err := opt.tryFold(ctx, a, fold) |
| 105 | // Ignore errors for identifiers, since there is no guarantee that the environment |
| 106 | // has a value for them. |
| 107 | if err != nil && fold.Kind() != ast.IdentKind { |
| 108 | ctx.ReportErrorAtID(fold.ID(), "constant-folding evaluation failed: %v", err.Error()) |
| 109 | return a |
| 110 | } |
| 111 | } |
| 112 | foldCount++ |
| 113 | foldableExprs = ast.MatchDescendants(root, constantExprMatcherCapture) |
| 114 | } |
| 115 | // Once all of the constants have been folded, try to run through the remaining comprehensions |
| 116 | // one last time. In this case, there's no guarantee they'll run, so we only update the |
| 117 | // target comprehension node with the literal value if the evaluation succeeds. |
| 118 | for _, compre := range ast.MatchDescendants(root, ast.KindMatcher(ast.ComprehensionKind)) { |
| 119 | opt.tryFold(ctx, a, compre) |
| 120 | } |
| 121 | |
| 122 | // If the output is a list, map, or struct which contains optional entries, then prune it |
| 123 | // to make sure that the optionals, if resolved, do not surface in the output literal. |
| 124 | pruneOptionalElements(ctx, root) |
| 125 | |
| 126 | // Ensure that all intermediate values in the folded expression can be represented as valid |
| 127 | // CEL literals within the AST structure. Use `PostOrderVisit` rather than `MatchDescendents` |
| 128 | // to avoid extra allocations during this final pass through the AST. |
| 129 | ast.PostOrderVisit(root, ast.NewExprVisitor(func(e ast.Expr) { |
| 130 | if e.Kind() != ast.LiteralKind { |
| 131 | return |
| 132 | } |
| 133 | val := e.AsLiteral() |
| 134 | adapted, err := adaptLiteral(ctx, val) |
| 135 | if err != nil { |
| 136 | ctx.ReportErrorAtID(root.ID(), "constant-folding evaluation failed: %v", err.Error()) |
| 137 | return |
| 138 | } |
| 139 | ctx.UpdateExpr(e, adapted) |
| 140 | })) |
nothing calls this directly
no test coverage detected