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
|
package parse
import (
"github.com/tinylib/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
// propInline identifies and inlines candidates
func (f *FileSet) propInline() {
for name, el := range f.Identities {
pushstate(name)
switch el := 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)
}
// inline bottom-up so as not to miss
// other inlining opportunities.
f.nextInline(&node, root)
*ref = node.Copy()
} 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")
}
}
|