forked from tinylib/msgp
/
inline.go
169 lines (154 loc) · 3.97 KB
/
inline.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
package parse
import (
"sort"
"github.com/fubotv/msgp/gen"
)
// This file defines when and how we
// propagate type information from
// one type declaration to another.
// After the processing pass, every
// non-primitive type is marshalled/unmarshalled/etc.
// through a function call. Here, we propagate
// the type information into the caller's type
// tree *if* the child type is simple enough.
//
// For example, types like
//
// type A [4]int
//
// will get pushed into parent methods,
// whereas types like
//
// type B [3]map[string]struct{A, B [4]string}
//
// will not.
// this is an approximate measure
// of the number of children in a node
const maxComplex = 5
// begin recursive search for identities with the
// given name and replace them with be
func (f *FileSet) findShim(id string, be *gen.BaseElem) {
for name, el := range f.Identities {
pushstate(name)
switch el := el.(type) {
case *gen.Struct:
for i := range el.Fields {
f.nextShim(&el.Fields[i].FieldElem, id, be)
}
case *gen.Array:
f.nextShim(&el.Els, id, be)
case *gen.Slice:
f.nextShim(&el.Els, id, be)
case *gen.Map:
f.nextShim(&el.Value, id, be)
case *gen.Ptr:
f.nextShim(&el.Value, id, be)
}
popstate()
}
// we'll need this at the top level as well
f.Identities[id] = be
}
func (f *FileSet) nextShim(ref *gen.Elem, id string, be *gen.BaseElem) {
if (*ref).TypeName() == id {
vn := (*ref).Varname()
*ref = be.Copy()
(*ref).SetVarname(vn)
} else {
switch el := (*ref).(type) {
case *gen.Struct:
for i := range el.Fields {
f.nextShim(&el.Fields[i].FieldElem, id, be)
}
case *gen.Array:
f.nextShim(&el.Els, id, be)
case *gen.Slice:
f.nextShim(&el.Els, id, be)
case *gen.Map:
f.nextShim(&el.Value, id, be)
case *gen.Ptr:
f.nextShim(&el.Value, id, be)
}
}
}
// propInline identifies and inlines candidates
func (f *FileSet) propInline() {
type gelem struct {
name string
el gen.Elem
}
all := make([]gelem, 0, len(f.Identities))
for name, el := range f.Identities {
all = append(all, gelem{name: name, el: el})
}
// make sure we process inlining determinstically:
// start with the least-complex elems;
// use identifier names as a tie-breaker
sort.Slice(all, func(i, j int) bool {
ig, jg := &all[i], &all[j]
ic, jc := ig.el.Complexity(), jg.el.Complexity()
return ic < jc || (ic == jc && ig.name < jg.name)
})
for i := range all {
name := all[i].name
pushstate(name)
switch el := all[i].el.(type) {
case *gen.Struct:
for i := range el.Fields {
f.nextInline(&el.Fields[i].FieldElem, name)
}
case *gen.Array:
f.nextInline(&el.Els, name)
case *gen.Slice:
f.nextInline(&el.Els, name)
case *gen.Map:
f.nextInline(&el.Value, name)
case *gen.Ptr:
f.nextInline(&el.Value, name)
}
popstate()
}
}
const fatalloop = `detected infinite recursion in inlining loop!
Please file a bug at github.com/tinylib/msgp/issues!
Thanks!
`
func (f *FileSet) nextInline(ref *gen.Elem, root string) {
switch el := (*ref).(type) {
case *gen.BaseElem:
// ensure that we're not inlining
// a type into itself
typ := el.TypeName()
if el.Value == gen.IDENT && typ != root {
if node, ok := f.Identities[typ]; ok && node.Complexity() < maxComplex {
infof("inlining %s\n", typ)
// This should never happen; it will cause
// infinite recursion.
if node == *ref {
panic(fatalloop)
}
*ref = node.Copy()
f.nextInline(ref, node.TypeName())
} else if !ok && !el.Resolved() {
// this is the point at which we're sure that
// we've got a type that isn't a primitive,
// a library builtin, or a processed type
warnf("unresolved identifier: %s\n", typ)
}
}
case *gen.Struct:
for i := range el.Fields {
f.nextInline(&el.Fields[i].FieldElem, root)
}
case *gen.Array:
f.nextInline(&el.Els, root)
case *gen.Slice:
f.nextInline(&el.Els, root)
case *gen.Map:
f.nextInline(&el.Value, root)
case *gen.Ptr:
f.nextInline(&el.Value, root)
default:
panic("bad elem type")
}
}