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: case types.TINTER:
for _, f := range t.FieldSlice() { for _, f := range t.AllMethods().Slice() {
if types.IsExported(f.Sym.Name) { if types.IsExported(f.Sym.Name) {
p.markType(f.Type) 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. // TODO(mdempsky): Move to package types.
func method(typ *types.Type, index int) *types.Field { func method(typ *types.Type, index int) *types.Field {
if typ.IsInterface() { if typ.IsInterface() {
return typ.Field(index) return typ.AllMethods().Index(index)
} }
return types.ReceiverBaseType(typ).Methods().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() { for i, f := range t.Methods().Slice() {
t2 := subst.typ(f.Type) t2 := subst.typ(f.Type)
if (t2 != f.Type || f.Nname != nil) && newfields == nil { 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++ { for j := 0; j < i; j++ {
newfields[j] = t.Methods().Slice()[j] newfields[j] = t.Methods().Index(j)
} }
} }
if newfields != nil { if newfields != nil {

View file

@ -568,7 +568,7 @@ func transformMethodExpr(n *ir.SelectorExpr) (res ir.Node) {
// Compute the method set for t. // Compute the method set for t.
var ms *types.Fields var ms *types.Fields
if t.IsInterface() { if t.IsInterface() {
ms = t.Fields() ms = t.AllMethods()
} else { } else {
mt := types.ReceiverBaseType(t) mt := types.ReceiverBaseType(t)
typecheck.CalcMethods(mt) 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. // imethods returns the methods of the interface type t, sorted by name.
func imethods(t *types.Type) []*typeSig { func imethods(t *types.Type) []*typeSig {
var methods []*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 { if f.Type.Kind() != types.TFUNC || f.Sym == nil {
continue continue
} }

View file

@ -221,7 +221,7 @@ func CalcMethods(t *types.Type) {
ms = append(ms, t.Methods().Slice()...) ms = append(ms, t.Methods().Slice()...)
sort.Sort(types.MethodsByName(ms)) 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. // 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 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 { if f.Embedded == 0 || f.Sym == nil {
continue continue
} }
@ -619,7 +625,7 @@ func expand0(t *types.Type) {
} }
if u.IsInterface() { if u.IsInterface() {
for _, f := range u.Fields().Slice() { for _, f := range u.AllMethods().Slice() {
if f.Sym.Uniq() { if f.Sym.Uniq() {
continue continue
} }
@ -658,7 +664,13 @@ func expand1(t *types.Type, top bool) {
} }
if u.IsStruct() || u.IsInterface() { 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 { if f.Embedded == 0 {
continue continue
} }
@ -708,8 +720,8 @@ func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool
if t.IsInterface() { if t.IsInterface() {
i := 0 i := 0
tms := t.Fields().Slice() tms := t.AllMethods().Slice()
for _, im := range iface.Fields().Slice() { for _, im := range iface.AllMethods().Slice() {
for i < len(tms) && tms[i].Sym != im.Sym { for i < len(tms) && tms[i].Sym != im.Sym {
i++ i++
} }
@ -738,7 +750,7 @@ func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool
tms = t.AllMethods().Slice() tms = t.AllMethods().Slice()
} }
i := 0 i := 0
for _, im := range iface.Fields().Slice() { for _, im := range iface.AllMethods().Slice() {
if im.Broke() { if im.Broke() {
continue continue
} }
@ -806,7 +818,13 @@ func lookdot0(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool)
c := 0 c := 0
if u.IsStruct() || u.IsInterface() { 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 f.Sym == s || (ignorecase && f.IsMethod() && strings.EqualFold(f.Sym.Name, s.Name)) {
if save != nil { if save != nil {
*save = f *save = f

View file

@ -1103,7 +1103,7 @@ func typecheckMethodExpr(n *ir.SelectorExpr) (res ir.Node) {
// Compute the method set for t. // Compute the method set for t.
var ms *types.Fields var ms *types.Fields
if t.IsInterface() { if t.IsInterface() {
ms = t.Fields() ms = t.AllMethods()
} else { } else {
mt := types.ReceiverBaseType(t) mt := types.ReceiverBaseType(t)
if mt == nil { if mt == nil {
@ -1170,8 +1170,10 @@ func Lookdot(n *ir.SelectorExpr, t *types.Type, dostrcmp int) *types.Field {
types.CalcSize(t) types.CalcSize(t)
var f1 *types.Field var f1 *types.Field
if t.IsStruct() || t.IsInterface() { if t.IsStruct() {
f1 = Lookdot1(n, s, t, t.Fields(), dostrcmp) f1 = Lookdot1(n, s, t, t.Fields(), dostrcmp)
} else if t.IsInterface() {
f1 = Lookdot1(n, s, t, t.AllMethods(), dostrcmp)
} }
var f2 *types.Field 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 break
} }
b.WriteString("interface {") b.WriteString("interface {")
for i, f := range t.Fields().Slice() { for i, f := range t.AllMethods().Slice() {
if i != 0 { if i != 0 {
b.WriteByte(';') 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) tconv2(b, f.Type, 'S', mode, visited)
} }
if t.NumFields() != 0 { if t.AllMethods().Len() != 0 {
b.WriteByte(' ') b.WriteByte(' ')
} }
b.WriteByte('}') b.WriteByte('}')

View file

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

View file

@ -119,7 +119,7 @@ func expandiface(t *Type) {
// Embedded interface: duplicate all methods // Embedded interface: duplicate all methods
// (including broken ones, if any) and add to t's // (including broken ones, if any) and add to t's
// method set. // 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. // Use m.Pos rather than t1.Pos to preserve embedding position.
f := NewField(m.Pos, t1.Sym, t1.Type) f := NewField(m.Pos, t1.Sym, t1.Type)
addMethod(f, false) addMethod(f, false)
@ -135,9 +135,7 @@ func expandiface(t *Type) {
m.Offset = int64(i) * int64(PtrSize) m.Offset = int64(i) * int64(PtrSize)
} }
// Access fields directly to avoid recursively calling CalcSize t.SetAllMethods(methods)
// within Type.Fields().
t.Extra.(*Interface).Fields.Set(methods)
} }
func calcStructOffset(errtype *Type, t *Type, o int64, flag int) int64 { 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}, {Forward{}, 20, 32},
{Func{}, 28, 48}, {Func{}, 28, 48},
{Struct{}, 16, 32}, {Struct{}, 16, 32},
{Interface{}, 8, 16}, {Interface{}, 4, 8},
{Chan{}, 8, 16}, {Chan{}, 8, 16},
{Array{}, 12, 16}, {Array{}, 12, 16},
{FuncArgs{}, 4, 8}, {FuncArgs{}, 4, 8},

View file

@ -368,8 +368,7 @@ func (t *Type) StructType() *Struct {
// Interface contains Type fields specific to interface types. // Interface contains Type fields specific to interface types.
type Interface struct { type Interface struct {
Fields Fields pkg *Pkg
pkg *Pkg
} }
// Ptr contains Type fields specific to pointer types. // 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 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 { func (t *Type) Methods() *Fields {
// TODO(mdempsky): Validate t?
return &t.methods 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 { 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 return &t.allMethods
} }
func (t *Type) Fields() *Fields { // SetAllMethods sets the set of all methods (including embedding) for type t.
switch t.kind { // Use this method instead of t.AllMethods().Set(), which might call CalcSize() on
case TSTRUCT: // an uninitialized interface type.
return &t.Extra.(*Struct).fields func (t *Type) SetAllMethods(fs []*Field) {
case TINTER: t.allMethods.Set(fs)
CalcSize(t)
return &t.Extra.(*Interface).Fields
}
base.Fatalf("Fields: type %v does not have fields", t)
return nil
} }
// 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 { func (t *Type) Field(i int) *Field {
return t.Fields().Slice()[i] return t.Fields().Slice()[i]
} }
// FieldSlice returns a slice of containing all fields/methods of // FieldSlice returns a slice of containing all fields of
// struct/interface type t. // a struct type t.
func (t *Type) FieldSlice() []*Field { func (t *Type) FieldSlice() []*Field {
return t.Fields().Slice() 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) { func (t *Type) SetFields(fields []*Field) {
// If we've calculated the width of t before, // If we've calculated the width of t before,
// then some other type such as a function signature // then some other type such as a function signature
@ -981,6 +989,7 @@ func (t *Type) SetFields(fields []*Field) {
t.Fields().Set(fields) t.Fields().Set(fields)
} }
// SetInterface sets the base methods of an interface type t.
func (t *Type) SetInterface(methods []*Field) { func (t *Type) SetInterface(methods []*Field) {
t.wantEtype(TINTER) t.wantEtype(TINTER)
t.Methods().Set(methods) t.Methods().Set(methods)
@ -1231,8 +1240,8 @@ func (t *Type) cmp(x *Type) Cmp {
return CMPeq return CMPeq
case TINTER: case TINTER:
tfs := t.FieldSlice() tfs := t.AllMethods().Slice()
xfs := x.FieldSlice() xfs := x.AllMethods().Slice()
for i := 0; i < len(tfs) && i < len(xfs); i++ { for i := 0; i < len(tfs) && i < len(xfs); i++ {
t1, x1 := tfs[i], xfs[i] t1, x1 := tfs[i], xfs[i]
if c := t1.Sym.cmpsym(x1.Sym); c != CMPeq { 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. // IsEmptyInterface reports whether t is an empty interface type.
func (t *Type) IsEmptyInterface() bool { 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. // IsScalar reports whether 't' is a scalar Go type, e.g.