[dev.regabi] cmd/compile: add Interface, Signature, and Struct constructors

This CL adds the remaining constructors needed to abstract away
construction of Types, and updates the compiler to use them
throughout. There's now just a couple uses within test cases to
remove.

While at it, I also replace the Func.Outnamed field with a simple
helper function, which reduces the size of function types somewhat.

Passes toolstash/buildall.

Change-Id: If1aa1095c98ae34b00380d0b3531bd63c10ce885
Reviewed-on: https://go-review.googlesource.com/c/go/+/274713
Trust: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
This commit is contained in:
Matthew Dempsky 2020-12-01 13:07:35 -08:00
parent 15085f8974
commit 77a71e0057
9 changed files with 144 additions and 162 deletions

View file

@ -369,7 +369,7 @@ func funchdr(fn *ir.Func) {
types.Markdcl()
if fn.Nname != nil && fn.Nname.Ntype != nil {
if fn.Nname.Ntype != nil {
funcargs(fn.Nname.Ntype.(*ir.FuncType))
} else {
funcargs2(fn.Type())
@ -510,27 +510,6 @@ func checkembeddedtype(t *types.Type) {
}
}
func structfield(n *ir.Field) *types.Field {
lno := base.Pos
base.Pos = n.Pos
if n.Ntype != nil {
n.Ntype = typecheckNtype(n.Ntype)
n.Type = n.Ntype.Type()
n.Ntype = nil
}
f := types.NewField(n.Pos, n.Sym, n.Type)
if n.Embedded {
checkembeddedtype(n.Type)
f.Embedded = 1
}
f.Note = n.Note
base.Pos = lno
return f
}
// checkdupfields emits errors for duplicately named fields or methods in
// a list of struct or interface types.
func checkdupfields(what string, fss ...[]*types.Field) {
@ -552,95 +531,49 @@ func checkdupfields(what string, fss ...[]*types.Field) {
// convert a parsed id/type list into
// a type for struct/interface/arglist
func tostruct(l []*ir.Field) *types.Type {
t := types.New(types.TSTRUCT)
fields := make([]*types.Field, len(l))
for i, n := range l {
f := structfield(n)
if f.Broke() {
t.SetBroke(true)
}
fields[i] = f
}
t.SetFields(fields)
checkdupfields("field", t.FieldSlice())
if !t.Broke() {
checkwidth(t)
}
return t
}
func tofunargs(l []*ir.Field, funarg types.Funarg) *types.Type {
t := types.New(types.TSTRUCT)
t.StructType().Funarg = funarg
fields := make([]*types.Field, len(l))
for i, n := range l {
f := structfield(n)
f.SetIsDDD(n.IsDDD)
if n.Decl != nil {
n.Decl.SetType(f.Type)
f.Nname = n.Decl
}
if f.Broke() {
t.SetBroke(true)
}
fields[i] = f
}
t.SetFields(fields)
return t
}
func tofunargsfield(fields []*types.Field, funarg types.Funarg) *types.Type {
t := types.New(types.TSTRUCT)
t.StructType().Funarg = funarg
t.SetFields(fields)
return t
}
func interfacefield(n *ir.Field) *types.Field {
lno := base.Pos
base.Pos = n.Pos
if n.Note != "" {
base.Errorf("interface method cannot have annotation")
fields := make([]*types.Field, len(l))
for i, n := range l {
base.Pos = n.Pos
if n.Ntype != nil {
n.Type = typecheckNtype(n.Ntype).Type()
n.Ntype = nil
}
f := types.NewField(n.Pos, n.Sym, n.Type)
if n.Embedded {
checkembeddedtype(n.Type)
f.Embedded = 1
}
f.Note = n.Note
fields[i] = f
}
// MethodSpec = MethodName Signature | InterfaceTypeName .
//
// If Sym != nil, then Sym is MethodName and Left is Signature.
// Otherwise, Left is InterfaceTypeName.
if n.Ntype != nil {
n.Ntype = typecheckNtype(n.Ntype)
n.Type = n.Ntype.Type()
n.Ntype = nil
}
f := types.NewField(n.Pos, n.Sym, n.Type)
checkdupfields("field", fields)
base.Pos = lno
return f
return types.NewStruct(fields)
}
func tointerface(l []*ir.Field) *types.Type {
if len(l) == 0 {
func tointerface(nmethods []*ir.Field) *types.Type {
if len(nmethods) == 0 {
return types.Types[types.TINTER]
}
t := types.New(types.TINTER)
var fields []*types.Field
for _, n := range l {
f := interfacefield(n)
if f.Broke() {
t.SetBroke(true)
lno := base.Pos
methods := make([]*types.Field, len(nmethods))
for i, n := range nmethods {
base.Pos = n.Pos
if n.Ntype != nil {
n.Type = typecheckNtype(n.Ntype).Type()
n.Ntype = nil
}
fields = append(fields, f)
methods[i] = types.NewField(n.Pos, n.Sym, n.Type)
}
t.SetInterface(fields)
return t
base.Pos = lno
return types.NewInterface(methods)
}
func fakeRecv() *ir.Field {
@ -659,42 +592,47 @@ func isifacemethod(f *types.Type) bool {
}
// turn a parsed function declaration into a type
func functype(this *ir.Field, in, out []*ir.Field) *types.Type {
t := types.New(types.TFUNC)
func functype(nrecv *ir.Field, nparams, nresults []*ir.Field) *types.Type {
funarg := func(n *ir.Field) *types.Field {
lno := base.Pos
base.Pos = n.Pos
var rcvr []*ir.Field
if this != nil {
rcvr = []*ir.Field{this}
if n.Ntype != nil {
n.Type = typecheckNtype(n.Ntype).Type()
n.Ntype = nil
}
f := types.NewField(n.Pos, n.Sym, n.Type)
f.SetIsDDD(n.IsDDD)
if n.Decl != nil {
n.Decl.SetType(f.Type)
f.Nname = n.Decl
}
base.Pos = lno
return f
}
funargs := func(nn []*ir.Field) []*types.Field {
res := make([]*types.Field, len(nn))
for i, n := range nn {
res[i] = funarg(n)
}
return res
}
t.FuncType().Receiver = tofunargs(rcvr, types.FunargRcvr)
t.FuncType().Params = tofunargs(in, types.FunargParams)
t.FuncType().Results = tofunargs(out, types.FunargResults)
var recv *types.Field
if nrecv != nil {
recv = funarg(nrecv)
}
t := types.NewSignature(recv, funargs(nparams), funargs(nresults))
checkdupfields("argument", t.Recvs().FieldSlice(), t.Params().FieldSlice(), t.Results().FieldSlice())
if t.Recvs().Broke() || t.Results().Broke() || t.Params().Broke() {
t.SetBroke(true)
}
t.FuncType().Outnamed = t.NumResults() > 0 && ir.OrigSym(t.Results().Field(0).Sym) != nil
return t
}
func functypefield(this *types.Field, in, out []*types.Field) *types.Type {
t := types.New(types.TFUNC)
var rcvr []*types.Field
if this != nil {
rcvr = []*types.Field{this}
}
t.FuncType().Receiver = tofunargsfield(rcvr, types.FunargRcvr)
t.FuncType().Params = tofunargsfield(in, types.FunargParams)
t.FuncType().Results = tofunargsfield(out, types.FunargResults)
t.FuncType().Outnamed = t.NumResults() > 0 && ir.OrigSym(t.Results().Field(0).Sym) != nil
return t
func hasNamedResults(fn *ir.Func) bool {
typ := fn.Type()
return typ.NumResults() > 0 && ir.OrigSym(typ.Results().Field(0).Sym) != nil
}
// methodSym returns the method symbol representing a method name

View file

@ -545,9 +545,8 @@ func (r *importReader) typ1() *types.Type {
fs[i] = f
}
t := types.New(types.TSTRUCT)
t := types.NewStruct(fs)
t.SetPkg(r.currPkg)
t.SetFields(fs)
return t
case interfaceType:
@ -570,9 +569,8 @@ func (r *importReader) typ1() *types.Type {
methods[i] = types.NewField(pos, sym, typ)
}
t := types.New(types.TINTER)
t := types.NewInterface(append(embeddeds, methods...))
t.SetPkg(r.currPkg)
t.SetInterface(append(embeddeds, methods...))
// Ensure we expand the interface in the frontend (#25055).
checkwidth(t)
@ -590,7 +588,7 @@ func (r *importReader) signature(recv *types.Field) *types.Type {
if n := len(params); n > 0 {
params[n-1].SetIsDDD(r.bool())
}
t := functypefield(recv, params, results)
t := types.NewSignature(recv, params, results)
t.SetPkg(r.currPkg)
return t
}

View file

@ -7,23 +7,22 @@ package gc
import (
"cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/src"
"reflect"
"sort"
"testing"
)
func typeWithoutPointers() *types.Type {
t := types.New(types.TSTRUCT)
f := &types.Field{Type: types.New(types.TINT)}
t.SetFields([]*types.Field{f})
return t
return types.NewStruct([]*types.Field{
types.NewField(src.NoXPos, nil, types.New(types.TINT)),
})
}
func typeWithPointers() *types.Type {
t := types.New(types.TSTRUCT)
f := &types.Field{Type: types.NewPtr(types.New(types.TINT))}
t.SetFields([]*types.Field{f})
return t
return types.NewStruct([]*types.Field{
types.NewField(src.NoXPos, nil, types.NewPtr(types.New(types.TINT))),
})
}
func markUsed(n *ir.Name) *ir.Name {

View file

@ -126,9 +126,8 @@ func bmap(t *types.Type) *types.Type {
field = append(field, overflow)
// link up fields
bucket := types.New(types.TSTRUCT)
bucket := types.NewStruct(field[:])
bucket.SetNoalg(true)
bucket.SetFields(field[:])
dowidth(bucket)
// Check invariants that map code depends on.
@ -221,9 +220,8 @@ func hmap(t *types.Type) *types.Type {
makefield("extra", types.Types[types.TUNSAFEPTR]),
}
hmap := types.New(types.TSTRUCT)
hmap := types.NewStruct(fields)
hmap.SetNoalg(true)
hmap.SetFields(fields)
dowidth(hmap)
// The size of hmap should be 48 bytes on 64 bit
@ -285,9 +283,8 @@ func hiter(t *types.Type) *types.Type {
}
// build iterator struct holding the above fields
hiter := types.New(types.TSTRUCT)
hiter := types.NewStruct(fields)
hiter.SetNoalg(true)
hiter.SetFields(fields)
dowidth(hiter)
if hiter.Width != int64(12*Widthptr) {
base.Fatalf("hash_iter size not correct %d %d", hiter.Width, 12*Widthptr)
@ -332,9 +329,8 @@ func deferstruct(stksize int64) *types.Type {
}
// build struct holding the above fields
s := types.New(types.TSTRUCT)
s := types.NewStruct(fields)
s.SetNoalg(true)
s.SetFields(fields)
s.Width = widstruct(s, s, 0, 1)
s.Align = uint8(Widthptr)
return s

View file

@ -2021,7 +2021,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n
}
if Curfn.Type().FuncType().Outnamed && n.List().Len() == 0 {
if hasNamedResults(Curfn) && n.List().Len() == 0 {
break
}
typecheckaste(ir.ORETURN, nil, false, Curfn.Type().Results(), n.List(), func() string { return "return argument" })

View file

@ -104,7 +104,7 @@ func initUniverse() {
}
types.Types[types.TANY] = types.New(types.TANY)
types.Types[types.TINTER] = types.New(types.TINTER) // empty interface
types.Types[types.TINTER] = types.NewInterface(nil)
defBasic := func(kind types.Kind, pkg *types.Pkg, name string) *types.Type {
sym := pkg.Lookup(name)
@ -325,15 +325,11 @@ func initUniverse() {
}
func makeErrorInterface() *types.Type {
sig := functypefield(fakeRecvField(), nil, []*types.Field{
sig := types.NewSignature(fakeRecvField(), nil, []*types.Field{
types.NewField(src.NoXPos, nil, types.Types[types.TSTRING]),
})
method := types.NewField(src.NoXPos, lookup("Error"), sig)
t := types.New(types.TINTER)
t.SetInterface([]*types.Field{method})
return t
return types.NewInterface([]*types.Field{method})
}
// finishUniverse makes the universe block visible within the current package.

View file

@ -274,7 +274,7 @@ func walkstmt(n ir.Node) ir.Node {
if n.List().Len() == 0 {
break
}
if (Curfn.Type().FuncType().Outnamed && n.List().Len() > 1) || paramoutheap(Curfn) {
if (hasNamedResults(Curfn) && n.List().Len() > 1) || paramoutheap(Curfn) {
// assign to the function out parameters,
// so that reorder3 can fix up conflicts
var rl []ir.Node

View file

@ -24,7 +24,7 @@ func TestSizeof(t *testing.T) {
{Type{}, 56, 96},
{Map{}, 20, 40},
{Forward{}, 20, 32},
{Func{}, 28, 48},
{Func{}, 24, 40},
{Struct{}, 16, 32},
{Interface{}, 8, 16},
{Chan{}, 8, 16},

View file

@ -285,8 +285,6 @@ type Func struct {
// It gets calculated via a temporary TFUNCARGS type.
// Note that TFUNC's Width is Widthptr.
Argwid int64
Outnamed bool
}
// FuncType returns t's extra func-specific fields.
@ -1618,3 +1616,60 @@ func NewBasic(kind Kind, obj Object) *Type {
t.nod = obj
return t
}
// NewInterface returns a new interface for the given methods and
// embedded types. Embedded types are specified as fields with no Sym.
func NewInterface(methods []*Field) *Type {
t := New(TINTER)
t.SetInterface(methods)
if anyBroke(methods) {
t.SetBroke(true)
}
return t
}
// NewSignature returns a new function type for the given receiver,
// parameters, and results, any of which may be nil.
func NewSignature(recv *Field, params, results []*Field) *Type {
var recvs []*Field
if recv != nil {
recvs = []*Field{recv}
}
t := New(TFUNC)
ft := t.FuncType()
funargs := func(fields []*Field, funarg Funarg) *Type {
s := NewStruct(fields)
s.StructType().Funarg = funarg
if s.Broke() {
t.SetBroke(true)
}
return s
}
ft.Receiver = funargs(recvs, FunargRcvr)
ft.Params = funargs(params, FunargParams)
ft.Results = funargs(results, FunargResults)
return t
}
// NewStruct returns a new struct with the given fields.
func NewStruct(fields []*Field) *Type {
t := New(TSTRUCT)
t.SetFields(fields)
if anyBroke(fields) {
t.SetBroke(true)
}
return t
}
func anyBroke(fields []*Field) bool {
for _, f := range fields {
if f.Broke() {
return true
}
}
return false
}