From 21e172fbf4e6616bb1ce4a207e027380f5d4a06a Mon Sep 17 00:00:00 2001 From: Noah Treuhaft Date: Thu, 28 May 2026 18:33:27 -0400 Subject: [PATCH 1/4] handle named types in vector.Empty.Kind --- vector/empty.go | 87 ++++++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 41 deletions(-) diff --git a/vector/empty.go b/vector/empty.go index c67594bf4..7b20346e4 100644 --- a/vector/empty.go +++ b/vector/empty.go @@ -21,47 +21,52 @@ func NewEmpty(typ super.Type) *Empty { } func (e *Empty) Kind() Kind { - switch e.typ.(type) { - case *super.TypeOfUint8, *super.TypeOfUint16, *super.TypeOfUint32, *super.TypeOfUint64: - return KindUint - case *super.TypeOfInt8, *super.TypeOfInt16, *super.TypeOfInt32, *super.TypeOfInt64, *super.TypeOfDuration, *super.TypeOfTime: - return KindInt - case *super.TypeOfFloat16, *super.TypeOfFloat32, *super.TypeOfFloat64: - return KindFloat - case *super.TypeOfBool: - return KindBool - case *super.TypeOfBytes: - return KindBytes - case *super.TypeOfString: - return KindString - case *super.TypeOfIP: - return KindIP - case *super.TypeOfNet: - return KindNet - case *super.TypeOfType: - return KindType - case *super.TypeOfNull: - return KindNull - case *super.TypeOfNone: - return KindNone - case *super.TypeRecord: - return KindRecord - case *super.TypeArray: - return KindArray - case *super.TypeSet: - return KindSet - case *super.TypeMap: - return KindMap - case *super.TypeUnion: - return KindUnion - case *super.TypeEnum: - return KindEnum - case *super.TypeError: - return KindError - case *super.TypeFusion: - return KindFusion - default: - panic(sup.String(e.typ)) + typ := e.typ + for { + switch t := typ.(type) { + case *super.TypeOfUint8, *super.TypeOfUint16, *super.TypeOfUint32, *super.TypeOfUint64: + return KindUint + case *super.TypeOfInt8, *super.TypeOfInt16, *super.TypeOfInt32, *super.TypeOfInt64, *super.TypeOfDuration, *super.TypeOfTime: + return KindInt + case *super.TypeOfFloat16, *super.TypeOfFloat32, *super.TypeOfFloat64: + return KindFloat + case *super.TypeOfBool: + return KindBool + case *super.TypeOfBytes: + return KindBytes + case *super.TypeOfString: + return KindString + case *super.TypeOfIP: + return KindIP + case *super.TypeOfNet: + return KindNet + case *super.TypeOfType: + return KindType + case *super.TypeOfNull: + return KindNull + case *super.TypeOfNone: + return KindNone + case *super.TypeRecord: + return KindRecord + case *super.TypeArray: + return KindArray + case *super.TypeSet: + return KindSet + case *super.TypeMap: + return KindMap + case *super.TypeUnion: + return KindUnion + case *super.TypeEnum: + return KindEnum + case *super.TypeError: + return KindError + case *super.TypeFusion: + return KindFusion + case *super.TypeNamed: + typ = t.Type + default: + panic(sup.String(e.typ)) + } } } From 4d1b9d2c77843460bb0751db4e3dbce77a9f1928 Mon Sep 17 00:00:00 2001 From: Noah Treuhaft Date: Fri, 29 May 2026 11:44:27 -0400 Subject: [PATCH 2/4] 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 3/4] 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 From f0c032a389acacc1a2971673b6dde33139b7b56b Mon Sep 17 00:00:00 2001 From: Noah Treuhaft Date: Mon, 1 Jun 2026 14:26:48 -0400 Subject: [PATCH 4/4] revert runtime/vam/expr/unblend.go --- runtime/vam/expr/unblend.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/runtime/vam/expr/unblend.go b/runtime/vam/expr/unblend.go index 35514f23f..c456599ac 100644 --- a/runtime/vam/expr/unblend.go +++ b/runtime/vam/expr/unblend.go @@ -231,9 +231,7 @@ func SlotTypesInList(sctx *super.Context, inner vector.Any, offsets []uint32) [] var alltypes []super.Type if dynamic != nil { for _, val := range dynamic.Values { - if val != nil { - alltypes = append(alltypes, val.Type()) - } + alltypes = append(alltypes, val.Type()) } } else { alltypes = []super.Type{inner.Type()}