Closed
Description
Describe the bug
ResidualAst
mutates the input *Ast
which causes subsequent evaluations to fail or return incorrect results.
To Reproduce
Check which components this affects:
- parser
- checker
- interpreter
Sample expression and input that reproduces the issue:
Test setup:
func Test_ResidualAst_Modified(t *testing.T) {
e, _ := cel.NewEnv(
cel.Declarations(
decls.NewVar("x", decls.NewMapType(decls.String, decls.Int)),
decls.NewVar("y", decls.Int),
),
)
ast, _ := e.Parse("x == y")
prg, _ := e.Program(ast,
cel.EvalOptions(cel.OptTrackState, cel.OptPartialEval),
)
for _, x := range []int{123, 456} {
vars, _ := cel.PartialVars(map[string]interface{}{
"x": x,
}, cel.AttributePattern("y"))
out, det, err := prg.Eval(vars)
if !types.IsUnknown(out) {
t.Fatalf("got %v, expected unknown", out)
}
if err != nil {
t.Fatal(err)
}
residual, err := e.ResidualAst(ast, det)
if err != nil {
t.Fatal(err)
}
orig, err := cel.AstToString(ast)
if err != nil {
t.Fatal(err)
}
if orig != "x == y" {
t.Errorf("parsed ast: got expr: %s, wanted x == y", orig)
}
expr, err := cel.AstToString(residual)
if err != nil {
t.Fatal(err)
}
want := fmt.Sprintf("%d == y", x)
if expr != want {
t.Errorf("residual ast: got expr: %s, wanted %s", expr, want)
}
}
}
=== RUN Test_ResidualAst_Modified
filter_test.go:83: parsed ast: got expr: 123 == y, wanted x == y
filter_test.go:83: parsed ast: got expr: 123 == y, wanted x == y
filter_test.go:91: residual ast: got expr: 123 == y, wanted 456 == y
--- FAIL: Test_ResidualAst_Modified (0.00s)
Expected behavior
ResidualAst
should not be mutating it's input *Ast
and should instead return a copy.
Additional context
Either ResidualAst
or interpreter.PruneAst
should be making a copy of the expr that can then be safely mutated.
<
4C7E
/div>