mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.typeparams] cmd/compile: start using sub-dictionary entries where needed
Added new struct instInfo for information about an instantiation (of a generic function/method with gcshapes or concrete types). We use this to remember the dictionary param node, the nodes where sub-dictionaries need to be used, etc. The instInfo map replaces the Stencil map in Package. Added code to access sub-dictionary entries at the appropriate call sites. We are currently still calculating the corresponding main dictionary, even when we really only need a sub-dictionary. I'll clean that up in a follow-up CL. Added code to deal with "generic" closures (closures that reference some generic variables/types). We decided that closures will share the same dictionary as the containing function (accessing the dictionary via a closure variable). So, the getGfInfo function now traverses all the nodes of each closure in a function that it is analyzing, so that a function's dictionary has all the entries needed for all its closures as well. Also, the instInfo of a closure is largely shared with its containing function. A good test for generic closures already exists with orderedmap.go. Other improvements: - Only create sub-dictionary entries when the function/method call/value or closure actually has type params in it. Added new test file subdict.go with an example where a generic method has an instantiated method call that does not depend not have type params. Change-Id: I691b9dc024a89d2305fcf1d8ba8540e53c9d103f Reviewed-on: https://go-review.googlesource.com/c/go/+/331516 Trust: Dan Scales <danscales@google.com> Run-TryBot: Dan Scales <danscales@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
a18726a648
commit
6dec18cc75
4 changed files with 309 additions and 112 deletions
|
|
@ -44,7 +44,7 @@ func infoPrint(format string, a ...interface{}) {
|
|||
// encountered already or new ones that are encountered during the stenciling
|
||||
// process.
|
||||
func (g *irgen) stencil() {
|
||||
g.target.Stencils = make(map[*types.Sym]*ir.Func)
|
||||
g.instInfoMap = make(map[*types.Sym]*instInfo)
|
||||
g.gfInfoMap = make(map[*types.Sym]*gfInfo)
|
||||
|
||||
// Instantiate the methods of instantiated generic types that we have seen so far.
|
||||
|
|
@ -86,6 +86,9 @@ func (g *irgen) stencil() {
|
|||
// to calling that function directly.
|
||||
modified := false
|
||||
closureRequired := false
|
||||
// declInfo will be non-nil exactly if we are scanning an instantiated function
|
||||
declInfo := g.instInfoMap[decl.Sym()]
|
||||
|
||||
ir.Visit(decl, func(n ir.Node) {
|
||||
if n.Op() == ir.OFUNCINST {
|
||||
// generic F, not immediately called
|
||||
|
|
@ -103,11 +106,24 @@ func (g *irgen) stencil() {
|
|||
call := n.(*ir.CallExpr)
|
||||
inst := call.X.(*ir.InstExpr)
|
||||
st, dict := g.getInstantiationForNode(inst)
|
||||
if infoPrintMode && g.target.Stencils[decl.Sym()] == nil {
|
||||
dictkind := "Main dictionary"
|
||||
if declInfo != nil {
|
||||
// Get the dictionary arg via sub-dictionary reference
|
||||
entry, ok := declInfo.dictEntryMap[n]
|
||||
// If the entry is not found, it must be that
|
||||
// this node was did not have any type args
|
||||
// that depend on type params, so we need a
|
||||
// main dictionary, not a sub-dictionary.
|
||||
if ok {
|
||||
dict = getDictionaryEntry(n.Pos(), declInfo.dictParam, entry, declInfo.dictLen)
|
||||
dictkind = "Sub-dictionary"
|
||||
}
|
||||
}
|
||||
if infoPrintMode {
|
||||
if inst.X.Op() == ir.OMETHVALUE {
|
||||
fmt.Printf("Main dictionary in %v at generic method call: %v - %v\n", decl, inst.X, call)
|
||||
fmt.Printf("%s in %v at generic method call: %v - %v\n", dictkind, decl, inst.X, call)
|
||||
} else {
|
||||
fmt.Printf("Main dictionary in %v at generic function call: %v - %v\n", decl, inst.X, call)
|
||||
fmt.Printf("%s in %v at generic function call: %v - %v\n", dictkind, decl, inst.X, call)
|
||||
}
|
||||
}
|
||||
// Replace the OFUNCINST with a direct reference to the
|
||||
|
|
@ -147,6 +163,17 @@ func (g *irgen) stencil() {
|
|||
}
|
||||
|
||||
st, dict := g.getInstantiation(gf, targs, true)
|
||||
entry, ok := declInfo.dictEntryMap[n]
|
||||
// TODO: Not creating sub-dictionary entry for
|
||||
// absDifference in absdiff.go yet. Unusual case,
|
||||
// where there are different generic method
|
||||
// implementations of Abs in absDifference.
|
||||
if ok {
|
||||
if infoPrintMode {
|
||||
fmt.Printf("Sub-dictionary in %v at generic method call: %v\n", decl, call)
|
||||
}
|
||||
dict = getDictionaryEntry(n.Pos(), declInfo.dictParam, entry, declInfo.dictLen)
|
||||
}
|
||||
call.SetOp(ir.OCALL)
|
||||
call.X = st.Nname
|
||||
call.Args.Prepend(dict, meth.X)
|
||||
|
|
@ -175,8 +202,6 @@ func (g *irgen) stencil() {
|
|||
ir.EditChildren(x, edit)
|
||||
switch {
|
||||
case x.Op() == ir.OFUNCINST:
|
||||
// TODO: only set outer!=nil if this instantiation uses
|
||||
// a type parameter from outer. See comment in buildClosure.
|
||||
return g.buildClosure(outer, x)
|
||||
case x.Op() == ir.OMETHEXPR && len(deref(x.(*ir.SelectorExpr).X.Type()).RParams()) > 0 &&
|
||||
!types.IsInterfaceMethod(x.(*ir.SelectorExpr).Selection.Type): // TODO: test for ptr-to-method case
|
||||
|
|
@ -208,6 +233,11 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
|
|||
var dictValue ir.Node // dictionary to use
|
||||
var rcvrValue ir.Node // receiver, if a method value
|
||||
typ := x.Type() // type of the closure
|
||||
var outerInfo *instInfo
|
||||
if outer != nil {
|
||||
outerInfo = g.instInfoMap[outer.Sym()]
|
||||
}
|
||||
usingSubdict := false
|
||||
if x.Op() == ir.OFUNCINST {
|
||||
inst := x.(*ir.InstExpr)
|
||||
|
||||
|
|
@ -234,11 +264,20 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
|
|||
// as its first two arguments.
|
||||
// dictValue is the value to use for the dictionary argument.
|
||||
target, dictValue = g.getInstantiation(gf, targs, rcvrValue != nil)
|
||||
if infoPrintMode && (outer == nil || g.target.Stencils[outer.Sym()] == nil) {
|
||||
dictkind := "Main dictionary"
|
||||
if outerInfo != nil {
|
||||
entry, ok := outerInfo.dictEntryMap[x]
|
||||
if ok {
|
||||
dictValue = getDictionaryEntry(x.Pos(), outerInfo.dictParam, entry, outerInfo.dictLen)
|
||||
dictkind = "Sub-dictionary"
|
||||
usingSubdict = true
|
||||
}
|
||||
}
|
||||
if infoPrintMode {
|
||||
if rcvrValue == nil {
|
||||
fmt.Printf("Main dictionary in %v for function value %v\n", outer, inst.X)
|
||||
fmt.Printf("%s in %v for generic function value %v\n", dictkind, outer, inst.X)
|
||||
} else {
|
||||
fmt.Printf("Main dictionary in %v for method value %v\n", outer, inst.X)
|
||||
fmt.Printf("%s in %v for generic method value %v\n", dictkind, outer, inst.X)
|
||||
}
|
||||
}
|
||||
} else { // ir.OMETHEXPR
|
||||
|
|
@ -270,8 +309,17 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
|
|||
}
|
||||
}
|
||||
target, dictValue = g.getInstantiation(gf, targs, true)
|
||||
if infoPrintMode && (outer == nil || g.target.Stencils[outer.Sym()] == nil) {
|
||||
fmt.Printf("Main dictionary in %v for method expression %v\n", outer, x)
|
||||
dictkind := "Main dictionary"
|
||||
if outerInfo != nil {
|
||||
entry, ok := outerInfo.dictEntryMap[x]
|
||||
if ok {
|
||||
dictValue = getDictionaryEntry(x.Pos(), outerInfo.dictParam, entry, outerInfo.dictLen)
|
||||
dictkind = "Sub-dictionary"
|
||||
usingSubdict = true
|
||||
}
|
||||
}
|
||||
if infoPrintMode {
|
||||
fmt.Printf("%s in %v for method expression %v\n", dictkind, outer, x)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -386,14 +434,12 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
|
|||
|
||||
// First, figure out the dictionary argument.
|
||||
var dict2Var ir.Node
|
||||
if outer != nil {
|
||||
// If there's an outer function, the dictionary value will be read from
|
||||
// the dictionary of the outer function.
|
||||
// TODO: only use a subdictionary if any of the instantiating types
|
||||
// depend on the type params of the outer function.
|
||||
if usingSubdict {
|
||||
// Capture sub-dictionary calculated in the outer function
|
||||
dict2Var = ir.CaptureName(pos, fn, dictVar)
|
||||
typed(types.Types[types.TUINTPTR], dict2Var)
|
||||
} else {
|
||||
// No outer function, instantiating types are known concrete types.
|
||||
// Static dictionary, so can be used directly in the closure
|
||||
dict2Var = dictValue
|
||||
}
|
||||
// Also capture the receiver variable.
|
||||
|
|
@ -695,8 +741,8 @@ func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth
|
|||
nameNode.Func.Dcl = nameNode.Func.Inl.Dcl
|
||||
}
|
||||
sym := typecheck.MakeInstName(nameNode.Sym(), targs, isMeth)
|
||||
st := g.target.Stencils[sym]
|
||||
if st == nil {
|
||||
info := g.instInfoMap[sym]
|
||||
if info == nil {
|
||||
if false {
|
||||
// Testing out gcshapeType() and gcshapeName()
|
||||
for i, t := range targs {
|
||||
|
|
@ -706,27 +752,38 @@ func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth
|
|||
}
|
||||
// If instantiation doesn't exist yet, create it and add
|
||||
// to the list of decls.
|
||||
st = g.genericSubst(sym, nameNode, targs, isMeth)
|
||||
gfInfo := g.getGfInfo(nameNode)
|
||||
info = &instInfo{
|
||||
gf: nameNode,
|
||||
gfInfo: gfInfo,
|
||||
startSubDict: len(targs) + len(gfInfo.derivedTypes),
|
||||
dictLen: len(targs) + len(gfInfo.derivedTypes) + len(gfInfo.subDictCalls),
|
||||
dictEntryMap: make(map[ir.Node]int),
|
||||
}
|
||||
// genericSubst fills in info.dictParam and info.dictEntryMap.
|
||||
st := g.genericSubst(sym, nameNode, targs, isMeth, info)
|
||||
info.fun = st
|
||||
info.dictAddr = g.getDictionaryValue(nameNode, targs, isMeth)
|
||||
g.instInfoMap[sym] = info
|
||||
// This ensures that the linker drops duplicates of this instantiation.
|
||||
// All just works!
|
||||
st.SetDupok(true)
|
||||
g.target.Stencils[sym] = st
|
||||
g.target.Decls = append(g.target.Decls, st)
|
||||
if base.Flag.W > 1 {
|
||||
ir.Dump(fmt.Sprintf("\nstenciled %v", st), st)
|
||||
}
|
||||
}
|
||||
return st, g.getDictionaryValue(nameNode, targs, isMeth)
|
||||
return info.fun, info.dictAddr
|
||||
}
|
||||
|
||||
// Struct containing info needed for doing the substitution as we create the
|
||||
// instantiation of a generic function with specified type arguments.
|
||||
type subster struct {
|
||||
g *irgen
|
||||
isMethod bool // If a method is being instantiated
|
||||
newf *ir.Func // Func node for the new stenciled function
|
||||
ts typecheck.Tsubster
|
||||
dictionary *ir.Name // Name of dictionary variable
|
||||
g *irgen
|
||||
isMethod bool // If a method is being instantiated
|
||||
newf *ir.Func // Func node for the new stenciled function
|
||||
ts typecheck.Tsubster
|
||||
info *instInfo // Place to put extra info in the instantiation
|
||||
}
|
||||
|
||||
// genericSubst returns a new function with name newsym. The function is an
|
||||
|
|
@ -734,8 +791,8 @@ type subster struct {
|
|||
// args targs. For a method with a generic receiver, it returns an instantiated
|
||||
// function type where the receiver becomes the first parameter. Otherwise the
|
||||
// instantiated method would still need to be transformed by later compiler
|
||||
// phases.
|
||||
func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []*types.Type, isMethod bool) *ir.Func {
|
||||
// phases. genericSubst fills in info.dictParam and info.dictEntryMap.
|
||||
func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []*types.Type, isMethod bool, info *instInfo) *ir.Func {
|
||||
var tparams []*types.Type
|
||||
if isMethod {
|
||||
// Get the type params from the method receiver (after skipping
|
||||
|
|
@ -769,6 +826,7 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []*type
|
|||
g: g,
|
||||
isMethod: isMethod,
|
||||
newf: newf,
|
||||
info: info,
|
||||
ts: typecheck.Tsubster{
|
||||
Tparams: tparams,
|
||||
Targs: targs,
|
||||
|
|
@ -778,13 +836,7 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []*type
|
|||
|
||||
newf.Dcl = make([]*ir.Name, 0, len(gf.Dcl)+1)
|
||||
|
||||
// Replace the types in the function signature.
|
||||
// Ugly: also, we have to insert the Name nodes of the parameters/results into
|
||||
// the function type. The current function type has no Nname fields set,
|
||||
// because it came via conversion from the types2 type.
|
||||
oldt := nameNode.Type()
|
||||
// We also transform a generic method type to the corresponding
|
||||
// instantiated function type where the dictionary is the first parameter.
|
||||
// Create the needed dictionary param
|
||||
dictionarySym := newsym.Pkg.Lookup(".dict")
|
||||
dictionaryType := types.Types[types.TUINTPTR]
|
||||
dictionaryName := ir.NewNameAt(gf.Pos(), dictionarySym)
|
||||
|
|
@ -800,11 +852,21 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []*type
|
|||
}
|
||||
dictionaryArg := types.NewField(gf.Pos(), dictionarySym, dictionaryType)
|
||||
dictionaryArg.Nname = dictionaryName
|
||||
subst.dictionary = dictionaryName
|
||||
info.dictParam = dictionaryName
|
||||
|
||||
// We add the dictionary as the first parameter in the function signature.
|
||||
// We also transform a method type to the corresponding function type
|
||||
// (make the receiver be the next parameter after the dictionary).
|
||||
oldt := nameNode.Type()
|
||||
var args []*types.Field
|
||||
args = append(args, dictionaryArg)
|
||||
args = append(args, oldt.Recvs().FieldSlice()...)
|
||||
args = append(args, oldt.Params().FieldSlice()...)
|
||||
|
||||
// Replace the types in the function signature via subst.fields.
|
||||
// Ugly: also, we have to insert the Name nodes of the parameters/results into
|
||||
// the function type. The current function type has no Nname fields set,
|
||||
// because it came via conversion from the types2 type.
|
||||
newt := types.NewSignature(oldt.Pkg(), nil, nil,
|
||||
subst.fields(ir.PPARAM, args, newf.Dcl),
|
||||
subst.fields(ir.PPARAMOUT, oldt.Results().FieldSlice(), newf.Dcl))
|
||||
|
|
@ -884,6 +946,26 @@ func (g *irgen) checkDictionary(name *ir.Name, targs []*types.Type) (code []ir.N
|
|||
return
|
||||
}
|
||||
|
||||
// getDictionaryEntry gets the i'th entry in the dictionary dict.
|
||||
func getDictionaryEntry(pos src.XPos, dict *ir.Name, i int, size int) ir.Node {
|
||||
// Convert dictionary to *[N]uintptr
|
||||
// All entries in the dictionary are pointers. They all point to static data, though, so we
|
||||
// treat them as uintptrs so the GC doesn't need to keep track of them.
|
||||
d := ir.NewConvExpr(pos, ir.OCONVNOP, types.Types[types.TUNSAFEPTR], dict)
|
||||
d.SetTypecheck(1)
|
||||
d = ir.NewConvExpr(pos, ir.OCONVNOP, types.NewArray(types.Types[types.TUINTPTR], int64(size)).PtrTo(), d)
|
||||
d.SetTypecheck(1)
|
||||
|
||||
// Load entry i out of the dictionary.
|
||||
deref := ir.NewStarExpr(pos, d)
|
||||
typed(d.Type().Elem(), deref)
|
||||
idx := ir.NewConstExpr(constant.MakeUint64(uint64(i)), dict) // TODO: what to set orig to?
|
||||
typed(types.Types[types.TUINTPTR], idx)
|
||||
r := ir.NewIndexExpr(pos, deref, idx)
|
||||
typed(types.Types[types.TUINTPTR], r)
|
||||
return r
|
||||
}
|
||||
|
||||
// getDictionaryType returns a *runtime._type from the dictionary corresponding to the input type.
|
||||
// The input type must be a type parameter (TODO: or a local derived type).
|
||||
func (subst *subster) getDictionaryType(pos src.XPos, t *types.Type) ir.Node {
|
||||
|
|
@ -898,21 +980,10 @@ func (subst *subster) getDictionaryType(pos src.XPos, t *types.Type) ir.Node {
|
|||
base.Fatalf(fmt.Sprintf("couldn't find type param %+v", t))
|
||||
}
|
||||
|
||||
// Convert dictionary to *[N]uintptr
|
||||
// All entries in the dictionary are pointers. They all point to static data, though, so we
|
||||
// treat them as uintptrs so the GC doesn't need to keep track of them.
|
||||
d := ir.NewConvExpr(pos, ir.OCONVNOP, types.Types[types.TUNSAFEPTR], subst.dictionary)
|
||||
d.SetTypecheck(1)
|
||||
d = ir.NewConvExpr(pos, ir.OCONVNOP, types.NewArray(types.Types[types.TUINTPTR], int64(len(tparams))).PtrTo(), d)
|
||||
d.SetTypecheck(1)
|
||||
|
||||
// Load entry i out of the dictionary.
|
||||
deref := ir.NewStarExpr(pos, d)
|
||||
typed(d.Type().Elem(), deref)
|
||||
idx := ir.NewConstExpr(constant.MakeUint64(uint64(i)), subst.dictionary) // TODO: what to set orig to?
|
||||
typed(types.Types[types.TUINTPTR], idx)
|
||||
r := ir.NewIndexExpr(pos, deref, idx)
|
||||
typed(types.Types[types.TUINT8].PtrTo(), r) // standard typing of a *runtime._type in the compiler is *byte
|
||||
r := getDictionaryEntry(pos, subst.info.dictParam, i, len(tparams))
|
||||
// change type of retrieved dictionary entry to *byte, which is the
|
||||
// standard typing of a *runtime._type in the compiler
|
||||
typed(types.Types[types.TUINT8].PtrTo(), r)
|
||||
return r
|
||||
}
|
||||
|
||||
|
|
@ -957,6 +1028,18 @@ func (subst *subster) node(n ir.Node) ir.Node {
|
|||
m.SetType(subst.ts.Typ(x.Type()))
|
||||
}
|
||||
}
|
||||
|
||||
for i, de := range subst.info.gfInfo.subDictCalls {
|
||||
if de == x {
|
||||
// Remember the dictionary entry associated with this
|
||||
// node in the instantiated function
|
||||
// TODO: make sure this remains correct with respect to the
|
||||
// transformations below.
|
||||
subst.info.dictEntryMap[m] = subst.info.startSubDict + i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
ir.EditChildren(m, edit)
|
||||
|
||||
m.SetTypecheck(1)
|
||||
|
|
@ -1109,7 +1192,26 @@ func (subst *subster) node(n ir.Node) ir.Node {
|
|||
ir.CurFunc = newfn
|
||||
subst.newf = newfn
|
||||
newfn.Dcl = subst.namelist(oldfn.Dcl)
|
||||
newfn.ClosureVars = subst.namelist(oldfn.ClosureVars)
|
||||
|
||||
// Make a closure variable for the dictionary of the
|
||||
// containing function.
|
||||
cdict := ir.CaptureName(oldfn.Pos(), newfn, subst.info.dictParam)
|
||||
typed(types.Types[types.TUINTPTR], cdict)
|
||||
ir.FinishCaptureNames(oldfn.Pos(), saveNewf, newfn)
|
||||
newfn.ClosureVars = append(newfn.ClosureVars, subst.namelist(oldfn.ClosureVars)...)
|
||||
|
||||
// Create inst info for the instantiated closure. The dict
|
||||
// param is the closure variable for the dictionary of the
|
||||
// outer function. Since the dictionary is shared, use the
|
||||
// same entries for startSubDict, dictLen, dictEntryMap.
|
||||
cinfo := &instInfo{
|
||||
fun: newfn,
|
||||
dictParam: cdict,
|
||||
startSubDict: subst.info.startSubDict,
|
||||
dictLen: subst.info.dictLen,
|
||||
dictEntryMap: subst.info.dictEntryMap,
|
||||
}
|
||||
subst.g.instInfoMap[newfn.Nname.Sym()] = cinfo
|
||||
|
||||
typed(subst.ts.Typ(oldfn.Nname.Type()), newfn.Nname)
|
||||
typed(newfn.Nname.Type(), newfn.OClosure)
|
||||
|
|
@ -1257,7 +1359,7 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool)
|
|||
|
||||
// Initialize the dictionary, if we haven't yet already.
|
||||
if lsym := sym.Linksym(); len(lsym.P) == 0 {
|
||||
infoPrint("Creating dictionary %v\n", sym.Name)
|
||||
infoPrint("=== Creating dictionary %v\n", sym.Name)
|
||||
off := 0
|
||||
// Emit an entry for each targ (concrete type or gcshape).
|
||||
for _, t := range targs {
|
||||
|
|
@ -1279,7 +1381,8 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool)
|
|||
// Emit an entry for each subdictionary (after substituting targs)
|
||||
for _, n := range info.subDictCalls {
|
||||
var sym *types.Sym
|
||||
if n.Op() == ir.OCALL {
|
||||
switch n.Op() {
|
||||
case ir.OCALL:
|
||||
call := n.(*ir.CallExpr)
|
||||
if call.X.Op() == ir.OXDOT {
|
||||
subtargs := deref(call.X.(*ir.SelectorExpr).X.Type()).RParams()
|
||||
|
|
@ -1304,11 +1407,9 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool)
|
|||
subtargs[i] = subst.Typ(t)
|
||||
}
|
||||
sym = g.getDictionarySym(nameNode, subtargs, isMeth)
|
||||
// TODO: This can actually be a static
|
||||
// main dictionary, if all of the subtargs
|
||||
// are concrete types (!HasTParam)
|
||||
}
|
||||
} else if n.Op() == ir.OFUNCINST {
|
||||
|
||||
case ir.OFUNCINST:
|
||||
inst := n.(*ir.InstExpr)
|
||||
nameNode := inst.X.(*ir.Name)
|
||||
subtargs := typecheck.TypesOf(inst.Targs)
|
||||
|
|
@ -1316,10 +1417,8 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool)
|
|||
subtargs[i] = subst.Typ(t)
|
||||
}
|
||||
sym = g.getDictionarySym(nameNode, subtargs, false)
|
||||
// TODO: This can actually be a static
|
||||
// main dictionary, if all of the subtargs
|
||||
// are concrete types (!HasTParam)
|
||||
} else if n.Op() == ir.OXDOT {
|
||||
|
||||
case ir.OXDOT:
|
||||
selExpr := n.(*ir.SelectorExpr)
|
||||
subtargs := selExpr.X.Type().RParams()
|
||||
s2targs := make([]*types.Type, len(subtargs))
|
||||
|
|
@ -1328,14 +1427,16 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool)
|
|||
}
|
||||
nameNode := selExpr.Selection.Nname.(*ir.Name)
|
||||
sym = g.getDictionarySym(nameNode, s2targs, true)
|
||||
|
||||
default:
|
||||
assert(false)
|
||||
}
|
||||
// TODO: handle closure cases that need sub-dictionaries, get rid of conditional
|
||||
if sym != nil {
|
||||
off = objw.SymPtr(lsym, off, sym.Linksym(), 0)
|
||||
infoPrint(" - Subdict %v\n", sym.Name)
|
||||
}
|
||||
|
||||
off = objw.SymPtr(lsym, off, sym.Linksym(), 0)
|
||||
infoPrint(" - Subdict %v\n", sym.Name)
|
||||
}
|
||||
objw.Global(lsym, int32(off), obj.DUPOK|obj.RODATA)
|
||||
infoPrint("=== Done dictionary\n")
|
||||
|
||||
// Add any new, fully instantiated types seen during the substitution to g.instTypeList.
|
||||
g.instTypeList = append(g.instTypeList, subst.InstTypeList...)
|
||||
|
|
@ -1363,6 +1464,26 @@ func (g *irgen) getDictionaryValue(gf *ir.Name, targs []*types.Type, isMeth bool
|
|||
return np
|
||||
}
|
||||
|
||||
// hasTParamNodes returns true if the type of any node in targs has a typeparam.
|
||||
func hasTParamNodes(targs []ir.Node) bool {
|
||||
for _, n := range targs {
|
||||
if n.Type().HasTParam() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// hasTParamNodes returns true if any type in targs has a typeparam.
|
||||
func hasTParamTypes(targs []*types.Type) bool {
|
||||
for _, t := range targs {
|
||||
if t.HasTParam() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// getGfInfo get information for a generic function - type params, derived generic
|
||||
// types, and subdictionaries.
|
||||
func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo {
|
||||
|
|
@ -1377,8 +1498,9 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo {
|
|||
if recv != nil {
|
||||
info.tparams = deref(recv.Type).RParams()
|
||||
} else {
|
||||
info.tparams = make([]*types.Type, len(gn.Type().TParams().FieldSlice()))
|
||||
for i, f := range gn.Type().TParams().FieldSlice() {
|
||||
tparams := gn.Type().TParams().FieldSlice()
|
||||
info.tparams = make([]*types.Type, len(tparams))
|
||||
for i, f := range tparams {
|
||||
info.tparams[i] = f.Type
|
||||
}
|
||||
}
|
||||
|
|
@ -1387,23 +1509,28 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo {
|
|||
}
|
||||
|
||||
if infoPrintMode {
|
||||
fmt.Printf(">>> Info for %v\n", gn)
|
||||
fmt.Printf(">>> GfInfo for %v\n", gn)
|
||||
for _, t := range info.tparams {
|
||||
fmt.Printf(" Typeparam %v\n", t)
|
||||
}
|
||||
for _, t := range info.derivedTypes {
|
||||
fmt.Printf(" Derived type %v\n", t)
|
||||
}
|
||||
}
|
||||
|
||||
for _, stmt := range gf.Body {
|
||||
ir.Visit(stmt, func(n ir.Node) {
|
||||
if n.Op() == ir.OFUNCINST && !n.(*ir.InstExpr).Implicit() {
|
||||
var visitFunc func(ir.Node)
|
||||
visitFunc = func(n ir.Node) {
|
||||
if n.Op() == ir.OFUNCINST && !n.(*ir.InstExpr).Implicit() {
|
||||
if hasTParamNodes(n.(*ir.InstExpr).Targs) {
|
||||
infoPrint(" Closure&subdictionary required at generic function value %v\n", n.(*ir.InstExpr).X)
|
||||
info.subDictCalls = append(info.subDictCalls, n)
|
||||
} else if n.Op() == ir.OXDOT && !n.(*ir.SelectorExpr).Implicit() &&
|
||||
n.(*ir.SelectorExpr).Selection != nil &&
|
||||
len(n.(*ir.SelectorExpr).X.Type().RParams()) > 0 {
|
||||
}
|
||||
} else if n.Op() == ir.OXDOT && !n.(*ir.SelectorExpr).Implicit() &&
|
||||
n.(*ir.SelectorExpr).Selection != nil &&
|
||||
len(n.(*ir.SelectorExpr).X.Type().RParams()) > 0 {
|
||||
if n.(*ir.SelectorExpr).X.Op() == ir.OTYPE {
|
||||
infoPrint(" Closure&subdictionary required at generic meth expr %v\n", n)
|
||||
} else {
|
||||
infoPrint(" Closure&subdictionary required at generic meth value %v\n", n)
|
||||
}
|
||||
if hasTParamTypes(deref(n.(*ir.SelectorExpr).X.Type()).RParams()) {
|
||||
if n.(*ir.SelectorExpr).X.Op() == ir.OTYPE {
|
||||
infoPrint(" Closure&subdictionary required at generic meth expr %v\n", n)
|
||||
} else {
|
||||
|
|
@ -1411,40 +1538,43 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo {
|
|||
}
|
||||
info.subDictCalls = append(info.subDictCalls, n)
|
||||
}
|
||||
if n.Op() == ir.OCALL && n.(*ir.CallExpr).X.Op() == ir.OFUNCINST {
|
||||
infoPrint(" Subdictionary at generic function call: %v - %v\n", n.(*ir.CallExpr).X.(*ir.InstExpr).X, n)
|
||||
n.(*ir.CallExpr).X.(*ir.InstExpr).SetImplicit(true)
|
||||
}
|
||||
if n.Op() == ir.OCALL && n.(*ir.CallExpr).X.Op() == ir.OFUNCINST {
|
||||
n.(*ir.CallExpr).X.(*ir.InstExpr).SetImplicit(true)
|
||||
if hasTParamNodes(n.(*ir.CallExpr).X.(*ir.InstExpr).Targs) {
|
||||
infoPrint(" Subdictionary at generic function/method call: %v - %v\n", n.(*ir.CallExpr).X.(*ir.InstExpr).X, n)
|
||||
info.subDictCalls = append(info.subDictCalls, n)
|
||||
}
|
||||
if n.Op() == ir.OCALL && n.(*ir.CallExpr).X.Op() == ir.OXDOT &&
|
||||
n.(*ir.CallExpr).X.(*ir.SelectorExpr).Selection != nil &&
|
||||
len(deref(n.(*ir.CallExpr).X.(*ir.SelectorExpr).X.Type()).RParams()) > 0 {
|
||||
}
|
||||
if n.Op() == ir.OCALL && n.(*ir.CallExpr).X.Op() == ir.OXDOT &&
|
||||
n.(*ir.CallExpr).X.(*ir.SelectorExpr).Selection != nil &&
|
||||
len(deref(n.(*ir.CallExpr).X.(*ir.SelectorExpr).X.Type()).RParams()) > 0 {
|
||||
n.(*ir.CallExpr).X.(*ir.SelectorExpr).SetImplicit(true)
|
||||
if hasTParamTypes(deref(n.(*ir.CallExpr).X.(*ir.SelectorExpr).X.Type()).RParams()) {
|
||||
infoPrint(" Subdictionary at generic method call: %v\n", n)
|
||||
n.(*ir.CallExpr).X.(*ir.SelectorExpr).SetImplicit(true)
|
||||
info.subDictCalls = append(info.subDictCalls, n)
|
||||
}
|
||||
if n.Op() == ir.OCLOSURE {
|
||||
oldfn := n.(*ir.ClosureExpr).Func
|
||||
needDict := false
|
||||
if oldfn.Nname.Type().HasTParam() {
|
||||
needDict = true
|
||||
infoPrint(" Subdictionary for closure that has generic params: %v\n", oldfn)
|
||||
} else {
|
||||
for _, cv := range oldfn.ClosureVars {
|
||||
if cv.Type().HasTParam() {
|
||||
needDict = true
|
||||
infoPrint(" Subdictionary for closure that has generic capture: %v\n", oldfn)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if needDict {
|
||||
info.subDictCalls = append(info.subDictCalls, n)
|
||||
}
|
||||
}
|
||||
if n.Op() == ir.OCLOSURE {
|
||||
// Visit the closure body and add all relevant entries to the
|
||||
// dictionary of the outer function (closure will just use
|
||||
// the dictionary of the outer function).
|
||||
for _, n1 := range n.(*ir.ClosureExpr).Func.Body {
|
||||
ir.Visit(n1, visitFunc)
|
||||
}
|
||||
}
|
||||
|
||||
addType(&info, n, n.Type())
|
||||
})
|
||||
addType(&info, n, n.Type())
|
||||
}
|
||||
|
||||
for _, stmt := range gf.Body {
|
||||
ir.Visit(stmt, visitFunc)
|
||||
}
|
||||
if infoPrintMode {
|
||||
for _, t := range info.derivedTypes {
|
||||
fmt.Printf(" Derived type %v\n", t)
|
||||
}
|
||||
fmt.Printf(">>> Done Gfinfo\n")
|
||||
}
|
||||
g.gfInfoMap[gn.Sym()] = &info
|
||||
return &info
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue