mirror of
https://github.com/golang/go
synced 2024-11-22 20:40:03 -07:00
[dev.typeparams] cmd/compile: dictionary/shape cleanup
- Removed gcshapeType - we're going with more granular shapes for now, and gradually coarsening later if needed. - Put in early return in getDictionarySym(), so the entire rest of the function can be un-indented by one level. - Removed some duplicated infoprint calls, and fixed one infoprint message in getGfInfo. Change-Id: I13acce8fdabdb21e903275b53ff78a1e6a378de2 Reviewed-on: https://go-review.googlesource.com/c/go/+/339901 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
3cdf8b429e
commit
5dcb5e2cea
@ -8,7 +8,6 @@
|
|||||||
package noder
|
package noder
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"cmd/compile/internal/base"
|
"cmd/compile/internal/base"
|
||||||
"cmd/compile/internal/ir"
|
"cmd/compile/internal/ir"
|
||||||
"cmd/compile/internal/objw"
|
"cmd/compile/internal/objw"
|
||||||
@ -19,7 +18,6 @@ import (
|
|||||||
"cmd/internal/src"
|
"cmd/internal/src"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/constant"
|
"go/constant"
|
||||||
"strconv"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Enable extra consistency checks.
|
// Enable extra consistency checks.
|
||||||
@ -536,220 +534,6 @@ func (g *irgen) getDictOrSubdict(declInfo *instInfo, n ir.Node, nameNode *ir.Nam
|
|||||||
return dict, usingSubdict
|
return dict, usingSubdict
|
||||||
}
|
}
|
||||||
|
|
||||||
func addGcType(fl []*types.Field, t *types.Type) []*types.Field {
|
|
||||||
return append(fl, types.NewField(base.Pos, typecheck.Lookup("F"+strconv.Itoa(len(fl))), t))
|
|
||||||
}
|
|
||||||
|
|
||||||
const INTTYPE = types.TINT64 // XX fix for 32-bit arch
|
|
||||||
const UINTTYPE = types.TUINT64 // XX fix for 32-bit arch
|
|
||||||
const INTSTRING = "i8" // XX fix for 32-bit arch
|
|
||||||
const UINTSTRING = "u8" // XX fix for 32-bit arch
|
|
||||||
|
|
||||||
// accumGcshape adds fields to fl resulting from the GCshape transformation of
|
|
||||||
// type t. The string associated with the GCshape transformation of t is added to
|
|
||||||
// buf. fieldSym is the sym of the field associated with type t, if it is in a
|
|
||||||
// struct. fieldSym could be used to have special naming for blank fields, etc.
|
|
||||||
func accumGcshape(fl []*types.Field, buf *bytes.Buffer, t *types.Type, fieldSym *types.Sym) []*types.Field {
|
|
||||||
// t.Kind() is already the kind of the underlying type, so no need to
|
|
||||||
// reference t.Underlying() to reference the underlying type.
|
|
||||||
assert(t.Kind() == t.Underlying().Kind())
|
|
||||||
|
|
||||||
switch t.Kind() {
|
|
||||||
case types.TINT8:
|
|
||||||
fl = addGcType(fl, types.Types[types.TINT8])
|
|
||||||
buf.WriteString("i1")
|
|
||||||
|
|
||||||
case types.TUINT8:
|
|
||||||
fl = addGcType(fl, types.Types[types.TUINT8])
|
|
||||||
buf.WriteString("u1")
|
|
||||||
|
|
||||||
case types.TINT16:
|
|
||||||
fl = addGcType(fl, types.Types[types.TINT16])
|
|
||||||
buf.WriteString("i2")
|
|
||||||
|
|
||||||
case types.TUINT16:
|
|
||||||
fl = addGcType(fl, types.Types[types.TUINT16])
|
|
||||||
buf.WriteString("u2")
|
|
||||||
|
|
||||||
case types.TINT32:
|
|
||||||
fl = addGcType(fl, types.Types[types.TINT32])
|
|
||||||
buf.WriteString("i4")
|
|
||||||
|
|
||||||
case types.TUINT32:
|
|
||||||
fl = addGcType(fl, types.Types[types.TUINT32])
|
|
||||||
buf.WriteString("u4")
|
|
||||||
|
|
||||||
case types.TINT64:
|
|
||||||
fl = addGcType(fl, types.Types[types.TINT64])
|
|
||||||
buf.WriteString("i8")
|
|
||||||
|
|
||||||
case types.TUINT64:
|
|
||||||
fl = addGcType(fl, types.Types[types.TUINT64])
|
|
||||||
buf.WriteString("u8")
|
|
||||||
|
|
||||||
case types.TINT:
|
|
||||||
fl = addGcType(fl, types.Types[INTTYPE])
|
|
||||||
buf.WriteString(INTSTRING)
|
|
||||||
|
|
||||||
case types.TUINT, types.TUINTPTR:
|
|
||||||
fl = addGcType(fl, types.Types[UINTTYPE])
|
|
||||||
buf.WriteString(UINTSTRING)
|
|
||||||
|
|
||||||
case types.TCOMPLEX64:
|
|
||||||
fl = addGcType(fl, types.Types[types.TFLOAT32])
|
|
||||||
fl = addGcType(fl, types.Types[types.TFLOAT32])
|
|
||||||
buf.WriteString("f4")
|
|
||||||
buf.WriteString("f4")
|
|
||||||
|
|
||||||
case types.TCOMPLEX128:
|
|
||||||
fl = addGcType(fl, types.Types[types.TFLOAT64])
|
|
||||||
fl = addGcType(fl, types.Types[types.TFLOAT64])
|
|
||||||
buf.WriteString("f8")
|
|
||||||
buf.WriteString("f8")
|
|
||||||
|
|
||||||
case types.TFLOAT32:
|
|
||||||
fl = addGcType(fl, types.Types[types.TFLOAT32])
|
|
||||||
buf.WriteString("f4")
|
|
||||||
|
|
||||||
case types.TFLOAT64:
|
|
||||||
fl = addGcType(fl, types.Types[types.TFLOAT64])
|
|
||||||
buf.WriteString("f8")
|
|
||||||
|
|
||||||
case types.TBOOL:
|
|
||||||
fl = addGcType(fl, types.Types[types.TINT8])
|
|
||||||
buf.WriteString("i1")
|
|
||||||
|
|
||||||
case types.TPTR:
|
|
||||||
fl = addGcType(fl, types.Types[types.TUNSAFEPTR])
|
|
||||||
buf.WriteString("p")
|
|
||||||
|
|
||||||
case types.TFUNC:
|
|
||||||
fl = addGcType(fl, types.Types[types.TUNSAFEPTR])
|
|
||||||
buf.WriteString("p")
|
|
||||||
|
|
||||||
case types.TSLICE:
|
|
||||||
fl = addGcType(fl, types.Types[types.TUNSAFEPTR])
|
|
||||||
fl = addGcType(fl, types.Types[INTTYPE])
|
|
||||||
fl = addGcType(fl, types.Types[INTTYPE])
|
|
||||||
buf.WriteString("p")
|
|
||||||
buf.WriteString(INTSTRING)
|
|
||||||
buf.WriteString(INTSTRING)
|
|
||||||
|
|
||||||
case types.TARRAY:
|
|
||||||
n := t.NumElem()
|
|
||||||
if n == 1 {
|
|
||||||
fl = accumGcshape(fl, buf, t.Elem(), nil)
|
|
||||||
} else if n > 0 {
|
|
||||||
// Represent an array with more than one element as its
|
|
||||||
// unique type, since it must be treated differently for
|
|
||||||
// regabi.
|
|
||||||
fl = addGcType(fl, t)
|
|
||||||
buf.WriteByte('[')
|
|
||||||
buf.WriteString(strconv.Itoa(int(n)))
|
|
||||||
buf.WriteString("](")
|
|
||||||
var ignore []*types.Field
|
|
||||||
// But to determine its gcshape name, we must call
|
|
||||||
// accumGcShape() on t.Elem().
|
|
||||||
accumGcshape(ignore, buf, t.Elem(), nil)
|
|
||||||
buf.WriteByte(')')
|
|
||||||
}
|
|
||||||
|
|
||||||
case types.TSTRUCT:
|
|
||||||
nfields := t.NumFields()
|
|
||||||
for i, f := range t.Fields().Slice() {
|
|
||||||
fl = accumGcshape(fl, buf, f.Type, f.Sym)
|
|
||||||
|
|
||||||
// Check if we need to add an alignment field.
|
|
||||||
var pad int64
|
|
||||||
if i < nfields-1 {
|
|
||||||
pad = t.Field(i+1).Offset - f.Offset - f.Type.Width
|
|
||||||
} else {
|
|
||||||
pad = t.Width - f.Offset - f.Type.Width
|
|
||||||
}
|
|
||||||
if pad > 0 {
|
|
||||||
// There is padding between fields or at end of
|
|
||||||
// struct. Add an alignment field.
|
|
||||||
fl = addGcType(fl, types.NewArray(types.Types[types.TUINT8], pad))
|
|
||||||
buf.WriteString("a")
|
|
||||||
buf.WriteString(strconv.Itoa(int(pad)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case types.TCHAN:
|
|
||||||
fl = addGcType(fl, types.Types[types.TUNSAFEPTR])
|
|
||||||
buf.WriteString("p")
|
|
||||||
|
|
||||||
case types.TMAP:
|
|
||||||
fl = addGcType(fl, types.Types[types.TUNSAFEPTR])
|
|
||||||
buf.WriteString("p")
|
|
||||||
|
|
||||||
case types.TINTER:
|
|
||||||
fl = addGcType(fl, types.Types[types.TUNSAFEPTR])
|
|
||||||
fl = addGcType(fl, types.Types[types.TUNSAFEPTR])
|
|
||||||
buf.WriteString("pp")
|
|
||||||
|
|
||||||
case types.TFORW, types.TANY:
|
|
||||||
assert(false)
|
|
||||||
|
|
||||||
case types.TSTRING:
|
|
||||||
fl = addGcType(fl, types.Types[types.TUNSAFEPTR])
|
|
||||||
fl = addGcType(fl, types.Types[INTTYPE])
|
|
||||||
buf.WriteString("p")
|
|
||||||
buf.WriteString(INTSTRING)
|
|
||||||
|
|
||||||
case types.TUNSAFEPTR:
|
|
||||||
fl = addGcType(fl, types.Types[types.TUNSAFEPTR])
|
|
||||||
buf.WriteString("p")
|
|
||||||
|
|
||||||
default: // Everything TTYPEPARAM and below in list of Kinds
|
|
||||||
assert(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
return fl
|
|
||||||
}
|
|
||||||
|
|
||||||
// gcshapeType returns the GCshape type and name corresponding to type t.
|
|
||||||
func gcshapeType(t *types.Type) (*types.Type, string) {
|
|
||||||
var fl []*types.Field
|
|
||||||
buf := bytes.NewBufferString("")
|
|
||||||
|
|
||||||
// Call CallSize so type sizes and field offsets are available.
|
|
||||||
types.CalcSize(t)
|
|
||||||
|
|
||||||
instType := t.Sym() != nil && t.IsFullyInstantiated()
|
|
||||||
if instType {
|
|
||||||
// We distinguish the gcshape of all top-level instantiated type from
|
|
||||||
// normal concrete types, even if they have the exact same underlying
|
|
||||||
// "shape", because in a function instantiation, any method call on
|
|
||||||
// this type arg will be a generic method call (requiring a
|
|
||||||
// dictionary), rather than a direct method call on the underlying
|
|
||||||
// type (no dictionary). So, we add the instshape prefix to the
|
|
||||||
// normal gcshape name, and will make it a defined type with that
|
|
||||||
// name below.
|
|
||||||
buf.WriteString("instshape-")
|
|
||||||
}
|
|
||||||
fl = accumGcshape(fl, buf, t, nil)
|
|
||||||
|
|
||||||
// TODO: Should gcshapes be in a global package, so we don't have to
|
|
||||||
// duplicate in each package? Or at least in the specified source package
|
|
||||||
// of a function/method instantiation?
|
|
||||||
gcshape := types.NewStruct(types.LocalPkg, fl)
|
|
||||||
gcname := buf.String()
|
|
||||||
if instType {
|
|
||||||
// Lookup or create type with name 'gcname' (with instshape prefix).
|
|
||||||
newsym := t.Sym().Pkg.Lookup(gcname)
|
|
||||||
if newsym.Def != nil {
|
|
||||||
gcshape = newsym.Def.Type()
|
|
||||||
} else {
|
|
||||||
newt := typecheck.NewIncompleteNamedType(t.Pos(), newsym)
|
|
||||||
newt.SetUnderlying(gcshape.Underlying())
|
|
||||||
gcshape = newt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert(gcshape.Size() == t.Size())
|
|
||||||
return gcshape, buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkFetchBody checks if a generic body can be fetched, but hasn't been loaded
|
// checkFetchBody checks if a generic body can be fetched, but hasn't been loaded
|
||||||
// yet. If so, it imports the body.
|
// yet. If so, it imports the body.
|
||||||
func checkFetchBody(nameNode *ir.Name) {
|
func checkFetchBody(nameNode *ir.Name) {
|
||||||
@ -1521,131 +1305,135 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool)
|
|||||||
sym := typecheck.MakeDictName(gf.Sym(), targs, isMeth)
|
sym := typecheck.MakeDictName(gf.Sym(), targs, isMeth)
|
||||||
|
|
||||||
// Initialize the dictionary, if we haven't yet already.
|
// Initialize the dictionary, if we haven't yet already.
|
||||||
if lsym := sym.Linksym(); len(lsym.P) == 0 {
|
lsym := sym.Linksym()
|
||||||
info := g.getGfInfo(gf)
|
if len(lsym.P) > 0 {
|
||||||
|
// We already started creating this dictionary and its lsym.
|
||||||
|
return sym
|
||||||
|
}
|
||||||
|
|
||||||
infoPrint("=== Creating dictionary %v\n", sym.Name)
|
info := g.getGfInfo(gf)
|
||||||
off := 0
|
|
||||||
// Emit an entry for each targ (concrete type or gcshape).
|
infoPrint("=== Creating dictionary %v\n", sym.Name)
|
||||||
for _, t := range targs {
|
off := 0
|
||||||
infoPrint(" * %v\n", t)
|
// Emit an entry for each targ (concrete type or gcshape).
|
||||||
s := reflectdata.TypeLinksym(t)
|
for _, t := range targs {
|
||||||
off = objw.SymPtr(lsym, off, s, 0)
|
infoPrint(" * %v\n", t)
|
||||||
markTypeUsed(t, lsym)
|
s := reflectdata.TypeLinksym(t)
|
||||||
}
|
off = objw.SymPtr(lsym, off, s, 0)
|
||||||
subst := typecheck.Tsubster{
|
markTypeUsed(t, lsym)
|
||||||
Tparams: info.tparams,
|
}
|
||||||
Targs: targs,
|
subst := typecheck.Tsubster{
|
||||||
}
|
Tparams: info.tparams,
|
||||||
// Emit an entry for each derived type (after substituting targs)
|
Targs: targs,
|
||||||
for _, t := range info.derivedTypes {
|
}
|
||||||
ts := subst.Typ(t)
|
// Emit an entry for each derived type (after substituting targs)
|
||||||
infoPrint(" - %v\n", ts)
|
for _, t := range info.derivedTypes {
|
||||||
s := reflectdata.TypeLinksym(ts)
|
ts := subst.Typ(t)
|
||||||
off = objw.SymPtr(lsym, off, s, 0)
|
infoPrint(" - %v\n", ts)
|
||||||
markTypeUsed(ts, lsym)
|
s := reflectdata.TypeLinksym(ts)
|
||||||
}
|
off = objw.SymPtr(lsym, off, s, 0)
|
||||||
// Emit an entry for each subdictionary (after substituting targs)
|
markTypeUsed(ts, lsym)
|
||||||
for _, n := range info.subDictCalls {
|
}
|
||||||
var sym *types.Sym
|
// Emit an entry for each subdictionary (after substituting targs)
|
||||||
switch n.Op() {
|
for _, n := range info.subDictCalls {
|
||||||
case ir.OCALL:
|
var sym *types.Sym
|
||||||
call := n.(*ir.CallExpr)
|
switch n.Op() {
|
||||||
if call.X.Op() == ir.OXDOT {
|
case ir.OCALL:
|
||||||
var nameNode *ir.Name
|
call := n.(*ir.CallExpr)
|
||||||
se := call.X.(*ir.SelectorExpr)
|
if call.X.Op() == ir.OXDOT {
|
||||||
if types.IsInterfaceMethod(se.Selection.Type) {
|
var nameNode *ir.Name
|
||||||
// This is a method call enabled by a type bound.
|
se := call.X.(*ir.SelectorExpr)
|
||||||
tmpse := ir.NewSelectorExpr(base.Pos, ir.OXDOT, se.X, se.Sel)
|
if types.IsInterfaceMethod(se.Selection.Type) {
|
||||||
tmpse = typecheck.AddImplicitDots(tmpse)
|
// This is a method call enabled by a type bound.
|
||||||
tparam := tmpse.X.Type()
|
tmpse := ir.NewSelectorExpr(base.Pos, ir.OXDOT, se.X, se.Sel)
|
||||||
assert(tparam.IsTypeParam())
|
tmpse = typecheck.AddImplicitDots(tmpse)
|
||||||
recvType := targs[tparam.Index()]
|
tparam := tmpse.X.Type()
|
||||||
if recvType.IsInterface() || len(recvType.RParams()) == 0 {
|
assert(tparam.IsTypeParam())
|
||||||
// No sub-dictionary entry is
|
recvType := targs[tparam.Index()]
|
||||||
// actually needed, since the
|
if recvType.IsInterface() || len(recvType.RParams()) == 0 {
|
||||||
// type arg is not an
|
// No sub-dictionary entry is
|
||||||
// instantiated type that
|
// actually needed, since the
|
||||||
// will have generic methods.
|
// type arg is not an
|
||||||
break
|
// instantiated type that
|
||||||
}
|
// will have generic methods.
|
||||||
// This is a method call for an
|
break
|
||||||
// instantiated type, so we need a
|
|
||||||
// sub-dictionary.
|
|
||||||
targs := recvType.RParams()
|
|
||||||
genRecvType := recvType.OrigSym.Def.Type()
|
|
||||||
nameNode = typecheck.Lookdot1(call.X, se.Sel, genRecvType, genRecvType.Methods(), 1).Nname.(*ir.Name)
|
|
||||||
sym = g.getDictionarySym(nameNode, targs, true)
|
|
||||||
} else {
|
|
||||||
// This is the case of a normal
|
|
||||||
// method call on a generic type.
|
|
||||||
nameNode = call.X.(*ir.SelectorExpr).Selection.Nname.(*ir.Name)
|
|
||||||
subtargs := deref(call.X.(*ir.SelectorExpr).X.Type()).RParams()
|
|
||||||
s2targs := make([]*types.Type, len(subtargs))
|
|
||||||
for i, t := range subtargs {
|
|
||||||
s2targs[i] = subst.Typ(t)
|
|
||||||
}
|
|
||||||
sym = g.getDictionarySym(nameNode, s2targs, true)
|
|
||||||
}
|
}
|
||||||
|
// This is a method call for an
|
||||||
|
// instantiated type, so we need a
|
||||||
|
// sub-dictionary.
|
||||||
|
targs := recvType.RParams()
|
||||||
|
genRecvType := recvType.OrigSym.Def.Type()
|
||||||
|
nameNode = typecheck.Lookdot1(call.X, se.Sel, genRecvType, genRecvType.Methods(), 1).Nname.(*ir.Name)
|
||||||
|
sym = g.getDictionarySym(nameNode, targs, true)
|
||||||
} else {
|
} else {
|
||||||
inst := call.X.(*ir.InstExpr)
|
// This is the case of a normal
|
||||||
var nameNode *ir.Name
|
// method call on a generic type.
|
||||||
var meth *ir.SelectorExpr
|
nameNode = call.X.(*ir.SelectorExpr).Selection.Nname.(*ir.Name)
|
||||||
var isMeth bool
|
subtargs := deref(call.X.(*ir.SelectorExpr).X.Type()).RParams()
|
||||||
if meth, isMeth = inst.X.(*ir.SelectorExpr); isMeth {
|
s2targs := make([]*types.Type, len(subtargs))
|
||||||
nameNode = meth.Selection.Nname.(*ir.Name)
|
|
||||||
} else {
|
|
||||||
nameNode = inst.X.(*ir.Name)
|
|
||||||
}
|
|
||||||
subtargs := typecheck.TypesOf(inst.Targs)
|
|
||||||
for i, t := range subtargs {
|
for i, t := range subtargs {
|
||||||
subtargs[i] = subst.Typ(t)
|
s2targs[i] = subst.Typ(t)
|
||||||
}
|
}
|
||||||
sym = g.getDictionarySym(nameNode, subtargs, isMeth)
|
sym = g.getDictionarySym(nameNode, s2targs, true)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inst := call.X.(*ir.InstExpr)
|
||||||
|
var nameNode *ir.Name
|
||||||
|
var meth *ir.SelectorExpr
|
||||||
|
var isMeth bool
|
||||||
|
if meth, isMeth = inst.X.(*ir.SelectorExpr); isMeth {
|
||||||
|
nameNode = meth.Selection.Nname.(*ir.Name)
|
||||||
|
} else {
|
||||||
|
nameNode = inst.X.(*ir.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
case ir.OFUNCINST:
|
|
||||||
inst := n.(*ir.InstExpr)
|
|
||||||
nameNode := inst.X.(*ir.Name)
|
|
||||||
subtargs := typecheck.TypesOf(inst.Targs)
|
subtargs := typecheck.TypesOf(inst.Targs)
|
||||||
for i, t := range subtargs {
|
for i, t := range subtargs {
|
||||||
subtargs[i] = subst.Typ(t)
|
subtargs[i] = subst.Typ(t)
|
||||||
}
|
}
|
||||||
sym = g.getDictionarySym(nameNode, subtargs, false)
|
sym = g.getDictionarySym(nameNode, subtargs, isMeth)
|
||||||
|
|
||||||
case ir.OXDOT:
|
|
||||||
selExpr := n.(*ir.SelectorExpr)
|
|
||||||
subtargs := deref(selExpr.X.Type()).RParams()
|
|
||||||
s2targs := make([]*types.Type, len(subtargs))
|
|
||||||
for i, t := range subtargs {
|
|
||||||
s2targs[i] = subst.Typ(t)
|
|
||||||
}
|
|
||||||
nameNode := selExpr.Selection.Nname.(*ir.Name)
|
|
||||||
sym = g.getDictionarySym(nameNode, s2targs, true)
|
|
||||||
|
|
||||||
default:
|
|
||||||
assert(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if sym == nil {
|
case ir.OFUNCINST:
|
||||||
// Unused sub-dictionary entry, just emit 0.
|
inst := n.(*ir.InstExpr)
|
||||||
off = objw.Uintptr(lsym, off, 0)
|
nameNode := inst.X.(*ir.Name)
|
||||||
infoPrint(" - Unused subdict entry\n")
|
subtargs := typecheck.TypesOf(inst.Targs)
|
||||||
} else {
|
for i, t := range subtargs {
|
||||||
off = objw.SymPtr(lsym, off, sym.Linksym(), 0)
|
subtargs[i] = subst.Typ(t)
|
||||||
infoPrint(" - Subdict %v\n", sym.Name)
|
|
||||||
}
|
}
|
||||||
|
sym = g.getDictionarySym(nameNode, subtargs, false)
|
||||||
|
|
||||||
|
case ir.OXDOT:
|
||||||
|
selExpr := n.(*ir.SelectorExpr)
|
||||||
|
subtargs := deref(selExpr.X.Type()).RParams()
|
||||||
|
s2targs := make([]*types.Type, len(subtargs))
|
||||||
|
for i, t := range subtargs {
|
||||||
|
s2targs[i] = subst.Typ(t)
|
||||||
|
}
|
||||||
|
nameNode := selExpr.Selection.Nname.(*ir.Name)
|
||||||
|
sym = g.getDictionarySym(nameNode, s2targs, true)
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
delay := &delayInfo{
|
if sym == nil {
|
||||||
gf: gf,
|
// Unused sub-dictionary entry, just emit 0.
|
||||||
targs: targs,
|
off = objw.Uintptr(lsym, off, 0)
|
||||||
sym: sym,
|
infoPrint(" - Unused subdict entry\n")
|
||||||
off: off,
|
} else {
|
||||||
|
off = objw.SymPtr(lsym, off, sym.Linksym(), 0)
|
||||||
|
infoPrint(" - Subdict %v\n", sym.Name)
|
||||||
}
|
}
|
||||||
g.dictSymsToFinalize = append(g.dictSymsToFinalize, delay)
|
|
||||||
g.instTypeList = append(g.instTypeList, subst.InstTypeList...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delay := &delayInfo{
|
||||||
|
gf: gf,
|
||||||
|
targs: targs,
|
||||||
|
sym: sym,
|
||||||
|
off: off,
|
||||||
|
}
|
||||||
|
g.dictSymsToFinalize = append(g.dictSymsToFinalize, delay)
|
||||||
|
g.instTypeList = append(g.instTypeList, subst.InstTypeList...)
|
||||||
return sym
|
return sym
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1805,11 +1593,6 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo {
|
|||||||
} else if n.Op() == ir.OXDOT && !n.(*ir.SelectorExpr).Implicit() &&
|
} else if n.Op() == ir.OXDOT && !n.(*ir.SelectorExpr).Implicit() &&
|
||||||
n.(*ir.SelectorExpr).Selection != nil &&
|
n.(*ir.SelectorExpr).Selection != nil &&
|
||||||
len(deref(n.(*ir.SelectorExpr).X.Type()).RParams()) > 0 {
|
len(deref(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 hasTParamTypes(deref(n.(*ir.SelectorExpr).X.Type()).RParams()) {
|
||||||
if n.(*ir.SelectorExpr).X.Op() == ir.OTYPE {
|
if n.(*ir.SelectorExpr).X.Op() == ir.OTYPE {
|
||||||
infoPrint(" Closure&subdictionary required at generic meth expr %v\n", n)
|
infoPrint(" Closure&subdictionary required at generic meth expr %v\n", n)
|
||||||
@ -1849,7 +1632,7 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo {
|
|||||||
info.itabConvs = append(info.itabConvs, n)
|
info.itabConvs = append(info.itabConvs, n)
|
||||||
}
|
}
|
||||||
if n.Op() == ir.OXDOT && n.(*ir.SelectorExpr).X.Type().IsTypeParam() {
|
if n.Op() == ir.OXDOT && n.(*ir.SelectorExpr).X.Type().IsTypeParam() {
|
||||||
infoPrint(" Itab for interface conv: %v\n", n)
|
infoPrint(" Itab for bound call: %v\n", n)
|
||||||
info.itabConvs = append(info.itabConvs, n)
|
info.itabConvs = append(info.itabConvs, n)
|
||||||
}
|
}
|
||||||
if (n.Op() == ir.ODOTTYPE || n.Op() == ir.ODOTTYPE2) && !n.(*ir.TypeAssertExpr).Type().IsInterface() && !n.(*ir.TypeAssertExpr).X.Type().IsEmptyInterface() {
|
if (n.Op() == ir.ODOTTYPE || n.Op() == ir.ODOTTYPE2) && !n.(*ir.TypeAssertExpr).Type().IsInterface() && !n.(*ir.TypeAssertExpr).X.Type().IsEmptyInterface() {
|
||||||
|
Loading…
Reference in New Issue
Block a user