From 4d1b9d2c77843460bb0751db4e3dbce77a9f1928 Mon Sep 17 00:00:00 2001 From: Noah Treuhaft Date: Fri, 29 May 2026 11:44:27 -0400 Subject: [PATCH 1/2] vam: fix panic in upcast() from union to union In runtime/vam/expr/function.Upcast.toUnion, when casting from a union, the loop that calls toUnionValue can produce multiple vectors with the same type (as when casting from to ), triggering a panic when those vectors are passed to vector.NewUnion. Fix by merging same-type vectors with vector.MergeSameTypesInDynamic. --- runtime/vam/expr/function/upcast.go | 20 ++++++++++++++++++-- runtime/vam/expr/unblend.go | 4 +++- runtime/ztests/expr/function/defuse.yaml | 10 ++++++++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/runtime/vam/expr/function/upcast.go b/runtime/vam/expr/function/upcast.go index 98bcc5af4..fd7c1c1ca 100644 --- a/runtime/vam/expr/function/upcast.go +++ b/runtime/vam/expr/function/upcast.go @@ -214,14 +214,30 @@ func (u *Upcast) toUnion(vec vector.Any, to *super.TypeUnion) vector.Any { if unionVec, ok := vec.(*vector.Union); ok { types := map[super.Type]struct{}{} values := make([]vector.Any, 0, len(to.Types)) + var needMerge bool for _, vec := range unionVec.Values() { vec = u.toUnionValue(vec, to) if vec == nil { return nil } - types[vec.Type()] = struct{}{} + typ := vec.Type() + if _, ok := types[typ]; !ok { + needMerge = true + } + types[typ] = struct{}{} values = append(values, vec) } + tags := unionVec.Tags() + if needMerge { + mergedVec := vbuild.MergeSameTypesInDynamic(vector.NewDynamic(tags, values)) + if d, ok := mergedVec.(*vector.Dynamic); ok { + tags, values = d.Tags, d.Values + } else { + tags = make([]uint32, mergedVec.Len()) + values = values[:1] + values[0] = mergedVec + } + } for _, typ := range to.Types { if _, ok := types[typ]; !ok { values = append(values, vector.NewEmpty(typ)) @@ -229,7 +245,7 @@ func (u *Upcast) toUnion(vec vector.Any, to *super.TypeUnion) vector.Any { } //XXX We should copy RLE instead of making tags when we can. // This will be addressed in a subsequent PR. - return vector.NewUnion(to, unionVec.Tags(), values) + return vector.NewUnion(to, tags, values) } values := u.toUnionValue(vec, to) if values == nil { diff --git a/runtime/vam/expr/unblend.go b/runtime/vam/expr/unblend.go index c456599ac..35514f23f 100644 --- a/runtime/vam/expr/unblend.go +++ b/runtime/vam/expr/unblend.go @@ -231,7 +231,9 @@ func SlotTypesInList(sctx *super.Context, inner vector.Any, offsets []uint32) [] var alltypes []super.Type if dynamic != nil { for _, val := range dynamic.Values { - alltypes = append(alltypes, val.Type()) + if val != nil { + alltypes = append(alltypes, val.Type()) + } } } else { alltypes = []super.Type{inner.Type()} diff --git a/runtime/ztests/expr/function/defuse.yaml b/runtime/ztests/expr/function/defuse.yaml index 7d613d77d..191157c1b 100644 --- a/runtime/ztests/expr/function/defuse.yaml +++ b/runtime/ztests/expr/function/defuse.yaml @@ -211,6 +211,16 @@ output: *input spq: fuse | defuse(this) +input: &input | + 1::(int64|[int64]|[string]) + [1,2]::(int64|[int64]|[string]) + +output: *input + +--- + +spq: fuse | defuse(this) + input: &input | [{a:1}] [{a:3},{b:3}] From 77f93cd4806afe5a638b75438adc96c25bb20d35 Mon Sep 17 00:00:00 2001 From: Noah Treuhaft Date: Fri, 29 May 2026 17:41:34 -0400 Subject: [PATCH 2/2] update defuse.yaml --- runtime/ztests/expr/function/defuse.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/ztests/expr/function/defuse.yaml b/runtime/ztests/expr/function/defuse.yaml index 191157c1b..9bcb4162b 100644 --- a/runtime/ztests/expr/function/defuse.yaml +++ b/runtime/ztests/expr/function/defuse.yaml @@ -213,7 +213,7 @@ spq: fuse | defuse(this) input: &input | 1::(int64|[int64]|[string]) - [1,2]::(int64|[int64]|[string]) + [2]::(int64|[int64]|[string]) output: *input