From fd024b9bf97b11abbac4f1926f3453b098e3b66a Mon Sep 17 00:00:00 2001 From: Steven McCanne Date: Sat, 2 May 2026 07:28:44 -0700 Subject: [PATCH] fix bug fusing option-type fields With the new design for option types, the fuser needs to fuse optional fields such that the option type of the field is pushed into the field's fusion type so we have fusion(...|none) instead of none|fusion(...). This problem was causing upcast to fail on such patterns. We've added test coverage to catch this. --- runtime/sam/expr/agg/fuser.go | 11 +++++++++-- runtime/ztests/expr/fuser.yaml | 11 +++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/runtime/sam/expr/agg/fuser.go b/runtime/sam/expr/agg/fuser.go index 9d3afb7f6..0a52eb41e 100644 --- a/runtime/sam/expr/agg/fuser.go +++ b/runtime/sam/expr/agg/fuser.go @@ -60,7 +60,7 @@ func (f *Fuser) fuse(a, b super.Type) super.Type { // First change all fields to optional that are in "a" but not in "b". for k, field := range fields { if _, ok := indexOfField(b.Fields, field.Name); !ok { - fields[k].Type = f.sctx.Option(fields[k].Type) + fields[k].Type = f.makeOption(fields[k].Type) } } // Now fuse all the fields in "b" that are also in "a" and add the fields @@ -70,7 +70,7 @@ func (f *Fuser) fuse(a, b super.Type) super.Type { if ok { fields[i].Type = f.fuse(fields[i].Type, field.Type) } else { - typ := f.sctx.Option(field.Type) + typ := f.makeOption(field.Type) fields = append(fields, super.NewField(field.Name, typ)) } } @@ -144,6 +144,13 @@ func (f *Fuser) fuse(a, b super.Type) super.Type { return f.fusion(union) } +func (f *Fuser) makeOption(t super.Type) super.Type { + if fusion, ok := t.(*super.TypeFusion); ok { + return f.sctx.LookupTypeFusion(f.makeOption(fusion.Type)) + } + return f.sctx.Option(t) +} + func isAll(t super.Type) bool { _, ok := t.(*super.TypeOfAll) return ok diff --git a/runtime/ztests/expr/fuser.yaml b/runtime/ztests/expr/fuser.yaml index 908c4a86e..a13161e0c 100644 --- a/runtime/ztests/expr/fuser.yaml +++ b/runtime/ztests/expr/fuser.yaml @@ -59,3 +59,14 @@ input: &input | [{id:1,s:"foo"},{id:2,s:null}] output: *input + +--- + +spq: fuse | defuse(this) + +input: &input | + {x:1,y:{z:"foo"}} + {x:2,y:{z:"bar",w:true}} + {x:3} + +output: *input