mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.typeparams] cmd/compile: simplify targ's type
Make the base type of targ a *types.Type instead of an ir.Node containing a type. Also move makeInstName to typecheck, so it can later be used by reflectdata for making wrappers. Change-Id: If148beaa972e5112ead2771d6e32d73f16ca30c1 Reviewed-on: https://go-review.googlesource.com/c/go/+/321209 Trust: Keith Randall <khr@golang.org> Trust: Dan Scales <danscales@google.com> Run-TryBot: Keith Randall <khr@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Dan Scales <danscales@google.com>
This commit is contained in:
parent
c2966ae272
commit
701bd60646
3 changed files with 70 additions and 55 deletions
|
|
@ -166,12 +166,8 @@ func (g *irgen) instantiateMethods() {
|
||||||
baseSym := typ.Sym().Pkg.Lookup(genericTypeName(typ.Sym()))
|
baseSym := typ.Sym().Pkg.Lookup(genericTypeName(typ.Sym()))
|
||||||
baseType := baseSym.Def.(*ir.Name).Type()
|
baseType := baseSym.Def.(*ir.Name).Type()
|
||||||
for j, m := range typ.Methods().Slice() {
|
for j, m := range typ.Methods().Slice() {
|
||||||
targs := make([]ir.Node, len(typ.RParams()))
|
|
||||||
for k, targ := range typ.RParams() {
|
|
||||||
targs[k] = ir.TypeNode(targ)
|
|
||||||
}
|
|
||||||
baseNname := baseType.Methods().Slice()[j].Nname.(*ir.Name)
|
baseNname := baseType.Methods().Slice()[j].Nname.(*ir.Name)
|
||||||
f := g.getInstantiation(baseNname, targs, true)
|
f := g.getInstantiation(baseNname, typ.RParams(), true)
|
||||||
m.Nname = f.Nname
|
m.Nname = f.Nname
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -190,17 +186,17 @@ func genericTypeName(sym *types.Sym) string {
|
||||||
// InstExpr node inst.
|
// InstExpr node inst.
|
||||||
func (g *irgen) getInstantiationForNode(inst *ir.InstExpr) *ir.Func {
|
func (g *irgen) getInstantiationForNode(inst *ir.InstExpr) *ir.Func {
|
||||||
if meth, ok := inst.X.(*ir.SelectorExpr); ok {
|
if meth, ok := inst.X.(*ir.SelectorExpr); ok {
|
||||||
return g.getInstantiation(meth.Selection.Nname.(*ir.Name), inst.Targs, true)
|
return g.getInstantiation(meth.Selection.Nname.(*ir.Name), typecheck.TypesOf(inst.Targs), true)
|
||||||
} else {
|
} else {
|
||||||
return g.getInstantiation(inst.X.(*ir.Name), inst.Targs, false)
|
return g.getInstantiation(inst.X.(*ir.Name), typecheck.TypesOf(inst.Targs), false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// getInstantiation gets the instantiantion of the function or method nameNode
|
// getInstantiation gets the instantiantion of the function or method nameNode
|
||||||
// with the type arguments targs. If the instantiated function is not already
|
// with the type arguments targs. If the instantiated function is not already
|
||||||
// cached, then it calls genericSubst to create the new instantiation.
|
// cached, then it calls genericSubst to create the new instantiation.
|
||||||
func (g *irgen) getInstantiation(nameNode *ir.Name, targs []ir.Node, isMeth bool) *ir.Func {
|
func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth bool) *ir.Func {
|
||||||
sym := makeInstName(nameNode.Sym(), targs, isMeth)
|
sym := typecheck.MakeInstName(nameNode.Sym(), targs, isMeth)
|
||||||
st := g.target.Stencils[sym]
|
st := g.target.Stencils[sym]
|
||||||
if st == nil {
|
if st == nil {
|
||||||
// If instantiation doesn't exist yet, create it and add
|
// If instantiation doesn't exist yet, create it and add
|
||||||
|
|
@ -215,45 +211,6 @@ func (g *irgen) getInstantiation(nameNode *ir.Name, targs []ir.Node, isMeth bool
|
||||||
return st
|
return st
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeInstName makes the unique name for a stenciled generic function or method,
|
|
||||||
// based on the name of the function fy=nsym and the targs. It replaces any
|
|
||||||
// existing bracket type list in the name. makeInstName asserts that fnsym has
|
|
||||||
// brackets in its name if and only if hasBrackets is true.
|
|
||||||
// TODO(danscales): remove the assertions and the hasBrackets argument later.
|
|
||||||
//
|
|
||||||
// Names of declared generic functions have no brackets originally, so hasBrackets
|
|
||||||
// should be false. Names of generic methods already have brackets, since the new
|
|
||||||
// type parameter is specified in the generic type of the receiver (e.g. func
|
|
||||||
// (func (v *value[T]).set(...) { ... } has the original name (*value[T]).set.
|
|
||||||
//
|
|
||||||
// The standard naming is something like: 'genFn[int,bool]' for functions and
|
|
||||||
// '(*genType[int,bool]).methodName' for methods
|
|
||||||
func makeInstName(fnsym *types.Sym, targs []ir.Node, hasBrackets bool) *types.Sym {
|
|
||||||
b := bytes.NewBufferString("")
|
|
||||||
name := fnsym.Name
|
|
||||||
i := strings.Index(name, "[")
|
|
||||||
assert(hasBrackets == (i >= 0))
|
|
||||||
if i >= 0 {
|
|
||||||
b.WriteString(name[0:i])
|
|
||||||
} else {
|
|
||||||
b.WriteString(name)
|
|
||||||
}
|
|
||||||
b.WriteString("[")
|
|
||||||
for i, targ := range targs {
|
|
||||||
if i > 0 {
|
|
||||||
b.WriteString(",")
|
|
||||||
}
|
|
||||||
b.WriteString(targ.Type().String())
|
|
||||||
}
|
|
||||||
b.WriteString("]")
|
|
||||||
if i >= 0 {
|
|
||||||
i2 := strings.Index(name[i:], "]")
|
|
||||||
assert(i2 >= 0)
|
|
||||||
b.WriteString(name[i+i2+1:])
|
|
||||||
}
|
|
||||||
return typecheck.Lookup(b.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Struct containing info needed for doing the substitution as we create the
|
// Struct containing info needed for doing the substitution as we create the
|
||||||
// instantiation of a generic function with specified type arguments.
|
// instantiation of a generic function with specified type arguments.
|
||||||
type subster struct {
|
type subster struct {
|
||||||
|
|
@ -261,7 +218,7 @@ type subster struct {
|
||||||
isMethod bool // If a method is being instantiated
|
isMethod bool // If a method is being instantiated
|
||||||
newf *ir.Func // Func node for the new stenciled function
|
newf *ir.Func // Func node for the new stenciled function
|
||||||
tparams []*types.Field
|
tparams []*types.Field
|
||||||
targs []ir.Node
|
targs []*types.Type
|
||||||
// The substitution map from name nodes in the generic function to the
|
// The substitution map from name nodes in the generic function to the
|
||||||
// name nodes in the new stenciled function.
|
// name nodes in the new stenciled function.
|
||||||
vars map[*ir.Name]*ir.Name
|
vars map[*ir.Name]*ir.Name
|
||||||
|
|
@ -273,7 +230,7 @@ type subster struct {
|
||||||
// function type where the receiver becomes the first parameter. Otherwise the
|
// function type where the receiver becomes the first parameter. Otherwise the
|
||||||
// instantiated method would still need to be transformed by later compiler
|
// instantiated method would still need to be transformed by later compiler
|
||||||
// phases.
|
// phases.
|
||||||
func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []ir.Node, isMethod bool) *ir.Func {
|
func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []*types.Type, isMethod bool) *ir.Func {
|
||||||
var tparams []*types.Field
|
var tparams []*types.Field
|
||||||
if isMethod {
|
if isMethod {
|
||||||
// Get the type params from the method receiver (after skipping
|
// Get the type params from the method receiver (after skipping
|
||||||
|
|
@ -545,7 +502,7 @@ func (subst *subster) node(n ir.Node) ir.Node {
|
||||||
m.(*ir.ClosureExpr).Func = newfn
|
m.(*ir.ClosureExpr).Func = newfn
|
||||||
// Closure name can already have brackets, if it derives
|
// Closure name can already have brackets, if it derives
|
||||||
// from a generic method
|
// from a generic method
|
||||||
newsym := makeInstName(oldfn.Nname.Sym(), subst.targs, subst.isMethod)
|
newsym := typecheck.MakeInstName(oldfn.Nname.Sym(), subst.targs, subst.isMethod)
|
||||||
newfn.Nname = ir.NewNameAt(oldfn.Nname.Pos(), newsym)
|
newfn.Nname = ir.NewNameAt(oldfn.Nname.Pos(), newsym)
|
||||||
newfn.Nname.Func = newfn
|
newfn.Nname.Func = newfn
|
||||||
newfn.Nname.Defn = newfn
|
newfn.Nname.Defn = newfn
|
||||||
|
|
@ -704,7 +661,7 @@ func (subst *subster) typ(t *types.Type) *types.Type {
|
||||||
if t.Kind() == types.TTYPEPARAM {
|
if t.Kind() == types.TTYPEPARAM {
|
||||||
for i, tp := range subst.tparams {
|
for i, tp := range subst.tparams {
|
||||||
if tp.Type == t {
|
if tp.Type == t {
|
||||||
return subst.targs[i].Type()
|
return subst.targs[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If t is a simple typeparam T, then t has the name/symbol 'T'
|
// If t is a simple typeparam T, then t has the name/symbol 'T'
|
||||||
|
|
@ -872,7 +829,7 @@ func (subst *subster) typ(t *types.Type) *types.Type {
|
||||||
for i, f := range t.Methods().Slice() {
|
for i, f := range t.Methods().Slice() {
|
||||||
t2 := subst.typ(f.Type)
|
t2 := subst.typ(f.Type)
|
||||||
oldsym := f.Nname.Sym()
|
oldsym := f.Nname.Sym()
|
||||||
newsym := makeInstName(oldsym, subst.targs, true)
|
newsym := typecheck.MakeInstName(oldsym, subst.targs, true)
|
||||||
var nname *ir.Name
|
var nname *ir.Name
|
||||||
if newsym.Def != nil {
|
if newsym.Def != nil {
|
||||||
nname = newsym.Def.(*ir.Name)
|
nname = newsym.Def.(*ir.Name)
|
||||||
|
|
|
||||||
|
|
@ -240,9 +240,9 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
|
||||||
// and for actually generating the methods for instantiated types.
|
// and for actually generating the methods for instantiated types.
|
||||||
func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) {
|
func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) {
|
||||||
if typ.NumMethods() != 0 {
|
if typ.NumMethods() != 0 {
|
||||||
targs := make([]ir.Node, len(typ.TArgs()))
|
targs := make([]*types.Type, len(typ.TArgs()))
|
||||||
for i, targ := range typ.TArgs() {
|
for i, targ := range typ.TArgs() {
|
||||||
targs[i] = ir.TypeNode(g.typ1(targ))
|
targs[i] = g.typ1(targ)
|
||||||
}
|
}
|
||||||
|
|
||||||
methods := make([]*types.Field, typ.NumMethods())
|
methods := make([]*types.Field, typ.NumMethods())
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
package typecheck
|
package typecheck
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
@ -874,3 +875,60 @@ var slist []symlink
|
||||||
type symlink struct {
|
type symlink struct {
|
||||||
field *types.Field
|
field *types.Field
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TypesOf converts a list of nodes to a list
|
||||||
|
// of types of those nodes.
|
||||||
|
func TypesOf(x []ir.Node) []*types.Type {
|
||||||
|
r := make([]*types.Type, len(x))
|
||||||
|
for i, n := range x {
|
||||||
|
r[i] = n.Type()
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeInstName makes the unique name for a stenciled generic function or method,
|
||||||
|
// based on the name of the function fy=nsym and the targs. It replaces any
|
||||||
|
// existing bracket type list in the name. makeInstName asserts that fnsym has
|
||||||
|
// brackets in its name if and only if hasBrackets is true.
|
||||||
|
// TODO(danscales): remove the assertions and the hasBrackets argument later.
|
||||||
|
//
|
||||||
|
// Names of declared generic functions have no brackets originally, so hasBrackets
|
||||||
|
// should be false. Names of generic methods already have brackets, since the new
|
||||||
|
// type parameter is specified in the generic type of the receiver (e.g. func
|
||||||
|
// (func (v *value[T]).set(...) { ... } has the original name (*value[T]).set.
|
||||||
|
//
|
||||||
|
// The standard naming is something like: 'genFn[int,bool]' for functions and
|
||||||
|
// '(*genType[int,bool]).methodName' for methods
|
||||||
|
func MakeInstName(fnsym *types.Sym, targs []*types.Type, hasBrackets bool) *types.Sym {
|
||||||
|
b := bytes.NewBufferString("")
|
||||||
|
name := fnsym.Name
|
||||||
|
i := strings.Index(name, "[")
|
||||||
|
assert(hasBrackets == (i >= 0))
|
||||||
|
if i >= 0 {
|
||||||
|
b.WriteString(name[0:i])
|
||||||
|
} else {
|
||||||
|
b.WriteString(name)
|
||||||
|
}
|
||||||
|
b.WriteString("[")
|
||||||
|
for i, targ := range targs {
|
||||||
|
if i > 0 {
|
||||||
|
b.WriteString(",")
|
||||||
|
}
|
||||||
|
b.WriteString(targ.String())
|
||||||
|
}
|
||||||
|
b.WriteString("]")
|
||||||
|
if i >= 0 {
|
||||||
|
i2 := strings.Index(name[i:], "]")
|
||||||
|
assert(i2 >= 0)
|
||||||
|
b.WriteString(name[i+i2+1:])
|
||||||
|
}
|
||||||
|
return Lookup(b.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// For catching problems as we add more features
|
||||||
|
// TODO(danscales): remove assertions or replace with base.FatalfAt()
|
||||||
|
func assert(p bool) {
|
||||||
|
if !p {
|
||||||
|
panic("assertion failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue