Skip to content

Commit 4c37890

Browse files
authored
remove some unnecessary fusion wrappers (#6760)
This commit makes record fusion a bit lighter by recognizing that fusion wrappers are needed only when field list changes name/order/etc as any type variation in descendent types will have their own fusion wrappers and defuse will recursively unravel those.
1 parent f5b1cc7 commit 4c37890

File tree

4 files changed

+40
-4
lines changed

4 files changed

+40
-4
lines changed

book/src/super-sql/aggregates/fuse.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,5 @@ fuse(this)
2525
{a:1,b:2}
2626
{a:2,b:"foo"}
2727
# expected output
28-
<fusion({a:int64,b:fusion(int64|string)})>
28+
<{a:int64,b:fusion(int64|string)}>
2929
```

book/src/super-sql/operators/fuse.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ fuse
5050
{a:1}
5151
{a:"foo"}
5252
# expected output
53-
fusion({a:fusion(1::(int64|string),<int64>)},<{a:int64}>)
54-
fusion({a:fusion("foo"::(int64|string),<string>)},<{a:string}>)
53+
{a:fusion(1::(int64|string),<int64>)}
54+
{a:fusion("foo"::(int64|string),<string>)}
5555
```
5656

5757
---

runtime/sam/expr/agg/fuser.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,11 @@ func (f *Fuser) fuse(a, b super.Type) super.Type {
7171
fields = append(fields, super.NewFieldWithOpt(field.Name, field.Type, true))
7272
}
7373
}
74-
return f.fusion(f.sctx.MustLookupTypeRecord(fields))
74+
fusedRec := f.sctx.MustLookupTypeRecord(fields)
75+
if recChanged(a, fusedRec) || recChanged(b, fusedRec) {
76+
return f.fusion(fusedRec)
77+
}
78+
return fusedRec
7579
}
7680
case *super.TypeArray:
7781
if b, ok := b.(*super.TypeArray); ok {
@@ -216,3 +220,21 @@ func indexOfField(fields []super.Field, name string) (int, bool) {
216220
}
217221
return -1, false
218222
}
223+
224+
// recChanged returns true iff the two record types are different
225+
// enough after fusing that they need to be wrapped in a fusion type.
226+
// As long as all the fields names and optionality are the same, then
227+
// any type differences in the fused type of the child fields will be
228+
// captured by a fusion wrapper somewhere in the descendent type.
229+
func recChanged(a, b *super.TypeRecord) bool {
230+
if len(a.Fields) != len(b.Fields) {
231+
return true
232+
}
233+
for k, af := range a.Fields {
234+
bf := b.Fields[k]
235+
if af.Name != bf.Name || af.Opt != bf.Opt {
236+
return true
237+
}
238+
}
239+
return false
240+
}

runtime/ztests/op/aggregate/fuse.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,17 @@ output: |
1414
{key:"a",supertype:<fusion({a?:string,r:fusion({x?:int32,y:int32,z?:int32}),key:string,s?:string,r2?:{x:int32}})>}
1515
{key:"b",supertype:<fusion({a?:string,r:fusion({x?:int32,y:int32,z?:int32}),key:string,s?:string,r2?:{x:int32}})>}
1616
{key:"c",supertype:<fusion({a?:string,r:fusion({x?:int32,y:int32,z?:int32}),key:string,s?:string,r2?:{x:int32}})>}
17+
18+
---
19+
20+
spq: fuse(this)
21+
22+
input: |
23+
{fixed:{x:1},var:{s:"foo"}}
24+
{fixed:{x:2},var:{s:"bar",a:[1,2]}}
25+
{fixed:{x:3},var:{s:"bar",a:[3]}}
26+
{fixed:{x:4},var:{s:"foo",t:123}}
27+
{fixed:{x:5},var:{s:"foo",t:{x:1}}}
28+
29+
output: |
30+
<{fixed:{x:int64},var:fusion({s:string,a?:[int64],t?:fusion(int64|{x:int64})})}>

0 commit comments

Comments
 (0)