diff --git a/v1/test/cases/testdata/v1/walkbuiltin/test-walkbuiltin-issue-7656.yaml b/v1/test/cases/testdata/v1/walkbuiltin/test-walkbuiltin-issue-7656.yaml new file mode 100644 index 0000000000..1ec0bc1e88 --- /dev/null +++ b/v1/test/cases/testdata/v1/walkbuiltin/test-walkbuiltin-issue-7656.yaml @@ -0,0 +1,26 @@ +--- +cases: + # verify fix for issue 7656 + - note: walkbuiltin/array path not overwritten + query: data.generated.p = x + modules: + - | + package generated + + x := {"a": [{"b": [{"c": [ + {"aa": "AA"}, + {"bb": "BB"}, + {"cc": "CC"}, + {"dd": "DDD"}, + ]}]}]} + + p := {path: value | + [path, value] := walk(x) + count(value) == 2 + } + data: {} + want_result: + - x: + "[\"a\",0,\"b\",0,\"c\",0,\"aa\"]": "AA" + "[\"a\",0,\"b\",0,\"c\",1,\"bb\"]": "BB" + "[\"a\",0,\"b\",0,\"c\",2,\"cc\"]": "CC" diff --git a/v1/topdown/walk.go b/v1/topdown/walk.go index b85076ac92..f6edcbdd62 100644 --- a/v1/topdown/walk.go +++ b/v1/topdown/walk.go @@ -30,7 +30,7 @@ func walk(filter, path *ast.Array, input *ast.Term, iter func(*ast.Term) error) pathCopy = ast.InternedEmptyArrayValue } else { // Shallow copy, as while the array is modified, the elements are not - pathCopy = path.Slice(0, path.Len()) + pathCopy = copyShallow(path) } // TODO(ae): I'd *really* like these terms to be retrieved from a sync.Pool, and @@ -48,8 +48,7 @@ func walk(filter, path *ast.Array, input *ast.Term, iter func(*ast.Term) error) filter = filter.Slice(1, -1) if key.IsGround() { if term := input.Get(key); term != nil { - path = pathAppend(path, key) - return walk(filter, path, term, iter) + return walk(filter, pathAppend(path, key), term, iter) } return nil } @@ -149,6 +148,16 @@ func pathIsWildcard(operands []*ast.Term) bool { return false } +func copyShallow(arr *ast.Array) *ast.Array { + cpy := make([]*ast.Term, 0, arr.Len()) + + arr.Foreach(func(elem *ast.Term) { + cpy = append(cpy, elem) + }) + + return ast.NewArray(cpy...) +} + func init() { RegisterBuiltinFunc(ast.WalkBuiltin.Name, evalWalk) }