cmd/compile: get rid of Fields in types.Interface, use allMethods in types.Type instead

Confusingly, the set of all methods of an interface is currently set in
Fields field of types.Interface. This is true, even though there is
already an allMethods field (and AllMethods method) of types.Type.
Change so the set of all methods of an interface are stored in
Type.allMethods, and Interface.Fields is removed. Update the comments
for Methods and AllMethods.

Change-Id: Ibc32bafae86831cba62606b079a855690612c759
Reviewed-on: https://go-review.googlesource.com/c/go/+/307209
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Dan Scales <danscales@google.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Dan Scales 2021-04-02 16:52:58 -07:00
parent 6ed045b365
commit a4b8241d97
12 changed files with 74 additions and 47 deletions

View file

@ -152,7 +152,7 @@ func (p *exporter) markType(t *types.Type) {
}
case types.TINTER:
for _, f := range t.FieldSlice() {
for _, f := range t.AllMethods().Slice() {
if types.IsExported(f.Sym.Name) {
p.markType(f.Type)
}

View file

@ -259,7 +259,7 @@ func dot(pos src.XPos, typ *types.Type, op ir.Op, x ir.Node, selection *types.Fi
// TODO(mdempsky): Move to package types.
func method(typ *types.Type, index int) *types.Field {
if typ.IsInterface() {
return typ.Field(index)
return typ.AllMethods().Index(index)
}
return types.ReceiverBaseType(typ).Methods().Index(index)
}

View file

@ -625,9 +625,9 @@ func (subst *subster) tinter(t *types.Type) *types.Type {
for i, f := range t.Methods().Slice() {
t2 := subst.typ(f.Type)
if (t2 != f.Type || f.Nname != nil) && newfields == nil {
newfields = make([]*types.Field, t.NumFields())
newfields = make([]*types.Field, t.Methods().Len())
for j := 0; j < i; j++ {
newfields[j] = t.Methods().Slice()[j]
newfields[j] = t.Methods().Index(j)
}
}
if newfields != nil {

View file

@ -568,7 +568,7 @@ func transformMethodExpr(n *ir.SelectorExpr) (res ir.Node) {
// Compute the method set for t.
var ms *types.Fields
if t.IsInterface() {
ms = t.Fields()
ms = t.AllMethods()
} else {
mt := types.ReceiverBaseType(t)
typecheck.CalcMethods(mt)

View file

@ -364,7 +364,7 @@ func methods(t *types.Type) []*typeSig {
// imethods returns the methods of the interface type t, sorted by name.
func imethods(t *types.Type) []*typeSig {
var methods []*typeSig
for _, f := range t.Fields().Slice() {
for _, f := range t.AllMethods().Slice() {
if f.Type.Kind() != types.TFUNC || f.Sym == nil {
continue
}

View file

@ -221,7 +221,7 @@ func CalcMethods(t *types.Type) {
ms = append(ms, t.Methods().Slice()...)
sort.Sort(types.MethodsByName(ms))
t.AllMethods().Set(ms)
t.SetAllMethods(ms)
}
// adddot1 returns the number of fields or methods named s at depth d in Type t.
@ -257,7 +257,13 @@ func adddot1(s *types.Sym, t *types.Type, d int, save **types.Field, ignorecase
return c, false
}
for _, f := range u.Fields().Slice() {
var fields *types.Fields
if u.IsStruct() {
fields = u.Fields()
} else {
fields = u.AllMethods()
}
for _, f := range fields.Slice() {
if f.Embedded == 0 || f.Sym == nil {
continue
}
@ -619,7 +625,7 @@ func expand0(t *types.Type) {
}
if u.IsInterface() {
for _, f := range u.Fields().Slice() {
for _, f := range u.AllMethods().Slice() {
if f.Sym.Uniq() {
continue
}
@ -658,7 +664,13 @@ func expand1(t *types.Type, top bool) {
}
if u.IsStruct() || u.IsInterface() {
for _, f := range u.Fields().Slice() {
var fields *types.Fields
if u.IsStruct() {
fields = u.Fields()
} else {
fields = u.AllMethods()
}
for _, f := range fields.Slice() {
if f.Embedded == 0 {
continue
}
@ -708,8 +720,8 @@ func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool
if t.IsInterface() {
i := 0
tms := t.Fields().Slice()
for _, im := range iface.Fields().Slice() {
tms := t.AllMethods().Slice()
for _, im := range iface.AllMethods().Slice() {
for i < len(tms) && tms[i].Sym != im.Sym {
i++
}
@ -738,7 +750,7 @@ func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool
tms = t.AllMethods().Slice()
}
i := 0
for _, im := range iface.Fields().Slice() {
for _, im := range iface.AllMethods().Slice() {
if im.Broke() {
continue
}
@ -806,7 +818,13 @@ func lookdot0(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool)
c := 0
if u.IsStruct() || u.IsInterface() {
for _, f := range u.Fields().Slice() {
var fields *types.Fields
if u.IsStruct() {
fields = u.Fields()
} else {
fields = u.AllMethods()
}
for _, f := range fields.Slice() {
if f.Sym == s || (ignorecase && f.IsMethod() && strings.EqualFold(f.Sym.Name, s.Name)) {
if save != nil {
*save = f

View file

@ -1103,7 +1103,7 @@ func typecheckMethodExpr(n *ir.SelectorExpr) (res ir.Node) {
// Compute the method set for t.
var ms *types.Fields
if t.IsInterface() {
ms = t.Fields()
ms = t.AllMethods()
} else {
mt := types.ReceiverBaseType(t)
if mt == nil {
@ -1170,8 +1170,10 @@ func Lookdot(n *ir.SelectorExpr, t *types.Type, dostrcmp int) *types.Field {
types.CalcSize(t)
var f1 *types.Field
if t.IsStruct() || t.IsInterface() {
if t.IsStruct() {
f1 = Lookdot1(n, s, t, t.Fields(), dostrcmp)
} else if t.IsInterface() {
f1 = Lookdot1(n, s, t, t.AllMethods(), dostrcmp)
}
var f2 *types.Field

View file

@ -442,7 +442,7 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type
break
}
b.WriteString("interface {")
for i, f := range t.Fields().Slice() {
for i, f := range t.AllMethods().Slice() {
if i != 0 {
b.WriteByte(';')
}
@ -462,7 +462,7 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type
}
tconv2(b, f.Type, 'S', mode, visited)
}
if t.NumFields() != 0 {
if t.AllMethods().Len() != 0 {
b.WriteByte(' ')
}
b.WriteByte('}')

View file

@ -61,11 +61,11 @@ func identical(t1, t2 *Type, cmpTags bool, assumedEqual map[typePair]struct{}) b
return true
case TINTER:
if t1.NumFields() != t2.NumFields() {
if t1.AllMethods().Len() != t2.AllMethods().Len() {
return false
}
for i, f1 := range t1.FieldSlice() {
f2 := t2.Field(i)
for i, f1 := range t1.AllMethods().Slice() {
f2 := t2.AllMethods().Index(i)
if f1.Sym != f2.Sym || !identical(f1.Type, f2.Type, cmpTags, assumedEqual) {
return false
}

View file

@ -119,7 +119,7 @@ func expandiface(t *Type) {
// Embedded interface: duplicate all methods
// (including broken ones, if any) and add to t's
// method set.
for _, t1 := range m.Type.Fields().Slice() {
for _, t1 := range m.Type.AllMethods().Slice() {
// Use m.Pos rather than t1.Pos to preserve embedding position.
f := NewField(m.Pos, t1.Sym, t1.Type)
addMethod(f, false)
@ -135,9 +135,7 @@ func expandiface(t *Type) {
m.Offset = int64(i) * int64(PtrSize)
}
// Access fields directly to avoid recursively calling CalcSize
// within Type.Fields().
t.Extra.(*Interface).Fields.Set(methods)
t.SetAllMethods(methods)
}
func calcStructOffset(errtype *Type, t *Type, o int64, flag int) int64 {

View file

@ -26,7 +26,7 @@ func TestSizeof(t *testing.T) {
{Forward{}, 20, 32},
{Func{}, 28, 48},
{Struct{}, 16, 32},
{Interface{}, 8, 16},
{Interface{}, 4, 8},
{Chan{}, 8, 16},
{Array{}, 12, 16},
{FuncArgs{}, 4, 8},

View file

@ -368,8 +368,7 @@ func (t *Type) StructType() *Struct {
// Interface contains Type fields specific to interface types.
type Interface struct {
Fields Fields
pkg *Pkg
pkg *Pkg
}
// Ptr contains Type fields specific to pointer types.
@ -922,40 +921,49 @@ func (t *Type) IsFuncArgStruct() bool {
return t.kind == TSTRUCT && t.Extra.(*Struct).Funarg != FunargNone
}
// Methods returns a pointer to the base methods (excluding embedding) for type t.
// These can either be concrete methods (for non-interface types) or interface
// methods (for interface types).
func (t *Type) Methods() *Fields {
// TODO(mdempsky): Validate t?
return &t.methods
}
// AllMethods returns a pointer to all the methods (including embedding) for type t.
// For an interface type, this is the set of methods that are typically iterated over.
func (t *Type) AllMethods() *Fields {
// TODO(mdempsky): Validate t?
if t.kind == TINTER {
// Calculate the full method set of an interface type on the fly
// now, if not done yet.
CalcSize(t)
}
return &t.allMethods
}
func (t *Type) Fields() *Fields {
switch t.kind {
case TSTRUCT:
return &t.Extra.(*Struct).fields
case TINTER:
CalcSize(t)
return &t.Extra.(*Interface).Fields
}
base.Fatalf("Fields: type %v does not have fields", t)
return nil
// SetAllMethods sets the set of all methods (including embedding) for type t.
// Use this method instead of t.AllMethods().Set(), which might call CalcSize() on
// an uninitialized interface type.
func (t *Type) SetAllMethods(fs []*Field) {
t.allMethods.Set(fs)
}
// Field returns the i'th field/method of struct/interface type t.
// Fields returns the fields of struct type t.
func (t *Type) Fields() *Fields {
t.wantEtype(TSTRUCT)
return &t.Extra.(*Struct).fields
}
// Field returns the i'th field of struct type t.
func (t *Type) Field(i int) *Field {
return t.Fields().Slice()[i]
}
// FieldSlice returns a slice of containing all fields/methods of
// struct/interface type t.
// FieldSlice returns a slice of containing all fields of
// a struct type t.
func (t *Type) FieldSlice() []*Field {
return t.Fields().Slice()
}
// SetFields sets struct/interface type t's fields/methods to fields.
// SetFields sets struct type t's fields to fields.
func (t *Type) SetFields(fields []*Field) {
// If we've calculated the width of t before,
// then some other type such as a function signature
@ -981,6 +989,7 @@ func (t *Type) SetFields(fields []*Field) {
t.Fields().Set(fields)
}
// SetInterface sets the base methods of an interface type t.
func (t *Type) SetInterface(methods []*Field) {
t.wantEtype(TINTER)
t.Methods().Set(methods)
@ -1231,8 +1240,8 @@ func (t *Type) cmp(x *Type) Cmp {
return CMPeq
case TINTER:
tfs := t.FieldSlice()
xfs := x.FieldSlice()
tfs := t.AllMethods().Slice()
xfs := x.AllMethods().Slice()
for i := 0; i < len(tfs) && i < len(xfs); i++ {
t1, x1 := tfs[i], xfs[i]
if c := t1.Sym.cmpsym(x1.Sym); c != CMPeq {
@ -1420,7 +1429,7 @@ func (t *Type) IsInterface() bool {
// IsEmptyInterface reports whether t is an empty interface type.
func (t *Type) IsEmptyInterface() bool {
return t.IsInterface() && t.NumFields() == 0
return t.IsInterface() && t.AllMethods().Len() == 0
}
// IsScalar reports whether 't' is a scalar Go type, e.g.