1
0
mirror of https://github.com/golang/go synced 2024-11-17 13:54:46 -07:00

cmd/compile: allow methods on shape types (but no bodies)

In a previous change, I was too aggressive in substInstType() in not
generating methods for shape types during import. We do actually want to
generate the method nodes - we just don't want to generate method bodies
(which we would never use). We may need the method nodes for checking
types later in the compile (especially with inlining).

So, we do generate method nodes for shape types during import. In
order to avoid the name collision we previously had, we now add
".nofunc." to the method nodes for shape types (during import and in the
type substituter). We do that by passing in a 'isMethodNode' arg to
MakeInstSym. We keep the normal name (without ".nofunc") for any other
method nodes, and for the instantiated functions that help with
implementing the methods of fully-instantiated types. The ".nofunc"
names will never appear in the executable, since we don't generate any
method bodies for the method nodes of shape types.

Change-Id: I3e57e328691214140ca5f48d32011552d2a0d45d
Reviewed-on: https://go-review.googlesource.com/c/go/+/352470
Trust: Dan Scales <danscales@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
Dan Scales 2021-09-22 20:20:09 -07:00
parent 964ea8c648
commit dfd875d015
4 changed files with 19 additions and 13 deletions

View File

@ -626,7 +626,7 @@ func (g *irgen) getInstantiation(nameNode *ir.Name, shapes []*types.Type, isMeth
shapes = s1
}
sym := typecheck.MakeFuncInstSym(nameNode.Sym(), shapes, isMeth)
sym := typecheck.MakeFuncInstSym(nameNode.Sym(), shapes, false, isMeth)
info := g.instInfoMap[sym]
if info == nil {
// If instantiation doesn't exist yet, create it and add

View File

@ -1927,7 +1927,7 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy
}
targs = targs2
sym := typecheck.MakeFuncInstSym(ir.MethodSym(methodrcvr, method.Sym), targs, true)
sym := typecheck.MakeFuncInstSym(ir.MethodSym(methodrcvr, method.Sym), targs, false, true)
if sym.Def == nil {
// Currently we make sure that we have all the instantiations
// we need by generating them all in ../noder/stencil.go:instantiateMethods

View File

@ -1867,11 +1867,6 @@ func substInstType(t *types.Type, baseType *types.Type, targs []*types.Type) {
}
t.SetUnderlying(subst.Typ(baseType.Underlying()))
if t.HasShape() && !t.IsInterface() {
// Concrete shape types have no methods.
return
}
newfields := make([]*types.Field, baseType.Methods().Len())
for i, f := range baseType.Methods().Slice() {
if !f.IsMethod() || types.IsInterfaceMethod(f.Type) {
@ -1895,7 +1890,7 @@ func substInstType(t *types.Type, baseType *types.Type, targs []*types.Type) {
}
t2 := msubst.Typ(f.Type)
oldsym := f.Nname.Sym()
newsym := MakeFuncInstSym(oldsym, targs, true)
newsym := MakeFuncInstSym(oldsym, targs, true, true)
var nname *ir.Name
if newsym.Def != nil {
nname = newsym.Def.(*ir.Name)

View File

@ -962,8 +962,8 @@ func makeInstName1(name string, targs []*types.Type, hasBrackets bool) string {
}
// MakeFuncInstSym makes the unique sym for a stenciled generic function or method,
// based on the name of the function fnsym and the targs. It replaces any
// existing bracket type list in the name. MakeInstName asserts that fnsym has
// based on the name of the function gf and the targs. It replaces any
// existing bracket type list in the name. MakeInstName asserts that gf has
// brackets in its name if and only if hasBrackets is true.
//
// Names of declared generic functions have no brackets originally, so hasBrackets
@ -973,8 +973,19 @@ func makeInstName1(name string, targs []*types.Type, hasBrackets bool) string {
//
// The standard naming is something like: 'genFn[int,bool]' for functions and
// '(*genType[int,bool]).methodName' for methods
func MakeFuncInstSym(gf *types.Sym, targs []*types.Type, hasBrackets bool) *types.Sym {
return gf.Pkg.Lookup(makeInstName1(gf.Name, targs, hasBrackets))
//
// isMethodNode specifies if the name of a method node is being generated (as opposed
// to a name of an instantiation of generic function or name of the shape-based
// function that helps implement a method of an instantiated type). For method nodes
// on shape types, we prepend "nofunc.", because method nodes for shape types will
// have no body, and we want to avoid a name conflict with the shape-based function
// that helps implement the same method for fully-instantiated types.
func MakeFuncInstSym(gf *types.Sym, targs []*types.Type, isMethodNode, hasBrackets bool) *types.Sym {
nm := makeInstName1(gf.Name, targs, hasBrackets)
if targs[0].HasShape() && isMethodNode {
nm = "nofunc." + nm
}
return gf.Pkg.Lookup(nm)
}
func MakeDictSym(gf *types.Sym, targs []*types.Type, hasBrackets bool) *types.Sym {
@ -1262,7 +1273,7 @@ func (ts *Tsubster) typ1(t *types.Type) *types.Type {
for i, f := range t.Methods().Slice() {
t2 := ts.typ1(f.Type)
oldsym := f.Nname.Sym()
newsym := MakeFuncInstSym(oldsym, ts.Targs, true)
newsym := MakeFuncInstSym(oldsym, ts.Targs, true, true)
var nname *ir.Name
if newsym.Def != nil {
nname = newsym.Def.(*ir.Name)