mirror of
https://github.com/golang/go
synced 2024-09-15 22:20:06 +00:00
[dev.typeparams] cmd/compile: fix getDictionarySym for methods references, write out sub-dictionaries
For method references (only), selectorExpr() now computes n.Selection, which is the generic method that is selected. This allows us to compute as needed the proper sub-dictionary for method reference. Also cleans up some code for distinguishing method references from references to a field that has a function value (especially in the presence of embedded fields). Change-Id: I9c5b789c15537ff48c70ca7a6444aa0420178a3a Reviewed-on: https://go-review.googlesource.com/c/go/+/332095 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
0e0b80cb56
commit
9ba294e15b
|
@ -206,6 +206,30 @@ func (g *irgen) selectorExpr(pos src.XPos, typ types2.Type, expr *syntax.Selecto
|
||||||
// only be fully transformed once it has an instantiated type.
|
// only be fully transformed once it has an instantiated type.
|
||||||
n := ir.NewSelectorExpr(pos, ir.OXDOT, x, typecheck.Lookup(expr.Sel.Value))
|
n := ir.NewSelectorExpr(pos, ir.OXDOT, x, typecheck.Lookup(expr.Sel.Value))
|
||||||
typed(g.typ(typ), n)
|
typed(g.typ(typ), n)
|
||||||
|
|
||||||
|
// Fill in n.Selection for a generic method reference, even though we
|
||||||
|
// won't use it directly, since it is useful for analysis.
|
||||||
|
// Specifically do not fill in for fields or interfaces methods, so
|
||||||
|
// n.Selection being non-nil means a method reference, rather than an
|
||||||
|
// interface reference or reference to a field with a function value.
|
||||||
|
obj2 := g.info.Selections[expr].Obj()
|
||||||
|
sig := types2.AsSignature(obj2.Type())
|
||||||
|
if sig == nil || sig.Recv() == nil {
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
// recvType is the type of the last embedded field. Because of the
|
||||||
|
// way methods are imported, g.obj(obj2) doesn't work across
|
||||||
|
// packages, so we have to lookup the method via the receiver type.
|
||||||
|
recvType := deref2(sig.Recv().Type())
|
||||||
|
if types2.AsInterface(recvType.Underlying()) != nil {
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
index := g.info.Selections[expr].Index()
|
||||||
|
last := index[len(index)-1]
|
||||||
|
recvObj := types2.AsNamed(recvType).Obj()
|
||||||
|
recv := g.pkg(recvObj.Pkg()).Lookup(recvObj.Name()).Def
|
||||||
|
n.Selection = recv.Type().Methods().Index(last)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,10 +332,7 @@ func (g *irgen) selectorExpr(pos src.XPos, typ types2.Type, expr *syntax.Selecto
|
||||||
|
|
||||||
// getTargs gets the targs associated with the receiver of a selected method
|
// getTargs gets the targs associated with the receiver of a selected method
|
||||||
func getTargs(selinfo *types2.Selection) []types2.Type {
|
func getTargs(selinfo *types2.Selection) []types2.Type {
|
||||||
r := selinfo.Recv()
|
r := deref2(selinfo.Recv())
|
||||||
if p := types2.AsPointer(r); p != nil {
|
|
||||||
r = p.Elem()
|
|
||||||
}
|
|
||||||
n := types2.AsNamed(r)
|
n := types2.AsNamed(r)
|
||||||
if n == nil {
|
if n == nil {
|
||||||
base.Fatalf("Incorrect type for selinfo %v", selinfo)
|
base.Fatalf("Incorrect type for selinfo %v", selinfo)
|
||||||
|
|
|
@ -1282,14 +1282,15 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool)
|
||||||
if n.Op() == ir.OCALL {
|
if n.Op() == ir.OCALL {
|
||||||
call := n.(*ir.CallExpr)
|
call := n.(*ir.CallExpr)
|
||||||
if call.X.Op() == ir.OXDOT {
|
if call.X.Op() == ir.OXDOT {
|
||||||
subtargs := deref(n.(*ir.CallExpr).X.(*ir.SelectorExpr).X.Type()).RParams()
|
subtargs := deref(call.X.(*ir.SelectorExpr).X.Type()).RParams()
|
||||||
s2targs := make([]*types.Type, len(subtargs))
|
s2targs := make([]*types.Type, len(subtargs))
|
||||||
for i, t := range subtargs {
|
for i, t := range subtargs {
|
||||||
s2targs[i] = subst.Typ(t)
|
s2targs[i] = subst.Typ(t)
|
||||||
}
|
}
|
||||||
sym = typecheck.MakeDictName(ir.MethodSym(call.X.(*ir.SelectorExpr).X.Type(), call.X.(*ir.SelectorExpr).Sel), s2targs, true)
|
nameNode := call.X.(*ir.SelectorExpr).Selection.Nname.(*ir.Name)
|
||||||
|
sym = g.getDictionarySym(nameNode, s2targs, true)
|
||||||
} else {
|
} else {
|
||||||
inst := n.(*ir.CallExpr).X.(*ir.InstExpr)
|
inst := call.X.(*ir.InstExpr)
|
||||||
var nameNode *ir.Name
|
var nameNode *ir.Name
|
||||||
var meth *ir.SelectorExpr
|
var meth *ir.SelectorExpr
|
||||||
var isMeth bool
|
var isMeth bool
|
||||||
|
@ -1325,14 +1326,12 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool)
|
||||||
for i, t := range subtargs {
|
for i, t := range subtargs {
|
||||||
s2targs[i] = subst.Typ(t)
|
s2targs[i] = subst.Typ(t)
|
||||||
}
|
}
|
||||||
sym = typecheck.MakeDictName(ir.MethodSym(selExpr.X.Type(), selExpr.Sel), s2targs, true)
|
nameNode := selExpr.Selection.Nname.(*ir.Name)
|
||||||
|
sym = g.getDictionarySym(nameNode, s2targs, true)
|
||||||
}
|
}
|
||||||
// TODO: handle closure cases that need sub-dictionaries, get rid of conditional
|
// TODO: handle closure cases that need sub-dictionaries, get rid of conditional
|
||||||
if sym != nil {
|
if sym != nil {
|
||||||
// TODO: uncomment once we're sure all the
|
off = objw.SymPtr(lsym, off, sym.Linksym(), 0)
|
||||||
// subdictionaries are created correctly.
|
|
||||||
// Methods above aren't yet generating dictionaries recursively yet.
|
|
||||||
//off = objw.SymPtr(lsym, off, sym.Linksym(), 0)
|
|
||||||
infoPrint(" - Subdict %v\n", sym.Name)
|
infoPrint(" - Subdict %v\n", sym.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1403,18 +1402,14 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo {
|
||||||
infoPrint(" Closure&subdictionary required at generic function value %v\n", n.(*ir.InstExpr).X)
|
infoPrint(" Closure&subdictionary required at generic function value %v\n", n.(*ir.InstExpr).X)
|
||||||
info.subDictCalls = append(info.subDictCalls, n)
|
info.subDictCalls = append(info.subDictCalls, n)
|
||||||
} else if n.Op() == ir.OXDOT && !n.(*ir.SelectorExpr).Implicit() &&
|
} else if n.Op() == ir.OXDOT && !n.(*ir.SelectorExpr).Implicit() &&
|
||||||
!n.(*ir.SelectorExpr).X.Type().IsInterface() &&
|
n.(*ir.SelectorExpr).Selection != nil &&
|
||||||
len(n.(*ir.SelectorExpr).X.Type().RParams()) > 0 {
|
len(n.(*ir.SelectorExpr).X.Type().RParams()) > 0 {
|
||||||
// Fix this - doesn't account for embedded fields, etc.
|
if n.(*ir.SelectorExpr).X.Op() == ir.OTYPE {
|
||||||
field := typecheck.Lookdot1(n.(*ir.SelectorExpr), n.(*ir.SelectorExpr).Sel, n.(*ir.SelectorExpr).X.Type(), n.(*ir.SelectorExpr).X.Type().Fields(), 0)
|
infoPrint(" Closure&subdictionary required at generic meth expr %v\n", n)
|
||||||
if field == nil {
|
} else {
|
||||||
if n.(*ir.SelectorExpr).X.Op() == ir.OTYPE {
|
infoPrint(" Closure&subdictionary required at generic meth value %v\n", n)
|
||||||
infoPrint(" Closure&subdictionary required at generic meth expr %v\n", n)
|
|
||||||
} else {
|
|
||||||
infoPrint(" Closure&subdictionary required at generic meth value %v\n", n)
|
|
||||||
}
|
|
||||||
info.subDictCalls = append(info.subDictCalls, n)
|
|
||||||
}
|
}
|
||||||
|
info.subDictCalls = append(info.subDictCalls, n)
|
||||||
}
|
}
|
||||||
if n.Op() == ir.OCALL && n.(*ir.CallExpr).X.Op() == ir.OFUNCINST {
|
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)
|
infoPrint(" Subdictionary at generic function call: %v - %v\n", n.(*ir.CallExpr).X.(*ir.InstExpr).X, n)
|
||||||
|
@ -1422,7 +1417,7 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo {
|
||||||
info.subDictCalls = append(info.subDictCalls, n)
|
info.subDictCalls = append(info.subDictCalls, n)
|
||||||
}
|
}
|
||||||
if n.Op() == ir.OCALL && n.(*ir.CallExpr).X.Op() == ir.OXDOT &&
|
if n.Op() == ir.OCALL && n.(*ir.CallExpr).X.Op() == ir.OXDOT &&
|
||||||
!n.(*ir.CallExpr).X.(*ir.SelectorExpr).X.Type().IsInterface() &&
|
n.(*ir.CallExpr).X.(*ir.SelectorExpr).Selection != nil &&
|
||||||
len(deref(n.(*ir.CallExpr).X.(*ir.SelectorExpr).X.Type()).RParams()) > 0 {
|
len(deref(n.(*ir.CallExpr).X.(*ir.SelectorExpr).X.Type()).RParams()) > 0 {
|
||||||
infoPrint(" Subdictionary at generic method call: %v\n", n)
|
infoPrint(" Subdictionary at generic method call: %v\n", n)
|
||||||
n.(*ir.CallExpr).X.(*ir.SelectorExpr).SetImplicit(true)
|
n.(*ir.CallExpr).X.(*ir.SelectorExpr).SetImplicit(true)
|
||||||
|
|
|
@ -278,11 +278,7 @@ func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) {
|
||||||
methods := make([]*types.Field, typ.NumMethods())
|
methods := make([]*types.Field, typ.NumMethods())
|
||||||
for i := range methods {
|
for i := range methods {
|
||||||
m := typ.Method(i)
|
m := typ.Method(i)
|
||||||
recvType := types2.AsSignature(m.Type()).Recv().Type()
|
recvType := deref2(types2.AsSignature(m.Type()).Recv().Type())
|
||||||
ptr := types2.AsPointer(recvType)
|
|
||||||
if ptr != nil {
|
|
||||||
recvType = ptr.Elem()
|
|
||||||
}
|
|
||||||
var meth *ir.Name
|
var meth *ir.Name
|
||||||
if m.Pkg() != g.self {
|
if m.Pkg() != g.self {
|
||||||
// Imported methods cannot be loaded by name (what
|
// Imported methods cannot be loaded by name (what
|
||||||
|
@ -471,3 +467,11 @@ var dirs = [...]types.ChanDir{
|
||||||
types2.SendOnly: types.Csend,
|
types2.SendOnly: types.Csend,
|
||||||
types2.RecvOnly: types.Crecv,
|
types2.RecvOnly: types.Crecv,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// deref2 does a single deref of types2 type t, if it is a pointer type.
|
||||||
|
func deref2(t types2.Type) types2.Type {
|
||||||
|
if ptr := types2.AsPointer(t); ptr != nil {
|
||||||
|
t = ptr.Elem()
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue