]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: get rid of Fields in types.Interface, use allMethods in types.Type instead
authorDan Scales <danscales@google.com>
Fri, 2 Apr 2021 23:52:58 +0000 (16:52 -0700)
committerDan Scales <danscales@google.com>
Mon, 5 Apr 2021 15:30:15 +0000 (15:30 +0000)
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>
12 files changed:
src/cmd/compile/internal/gc/export.go
src/cmd/compile/internal/noder/helpers.go
src/cmd/compile/internal/noder/stencil.go
src/cmd/compile/internal/noder/transform.go
src/cmd/compile/internal/reflectdata/reflect.go
src/cmd/compile/internal/typecheck/subr.go
src/cmd/compile/internal/typecheck/typecheck.go
src/cmd/compile/internal/types/fmt.go
src/cmd/compile/internal/types/identity.go
src/cmd/compile/internal/types/size.go
src/cmd/compile/internal/types/sizeof_test.go
src/cmd/compile/internal/types/type.go

index 4d8221f53bab1777de99b3c2c747b59f673149eb..2137f1d1961abf8987383d0cd835459fb37fc2c5 100644 (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)
                        }
index 6320b30e5044e506cae059935e4cd2d634baf46a..9da0e493007a0687899eb59fe64f2eaa03d95e0c 100644 (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)
 }
index 4db688571e338d5a995d599ff80a2a4f2235522c..0d84db999395015822670852c6224f14d47b7ce0 100644 (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 {
index 021d3a9fa78c397810fc1cb1638f6b4e71980872..ffe35d58742523562ece2f6a19a3900155d1333d 100644 (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)
index c1cded826c225cecba2d7422008faa18cf3511a4..3a31e3c951c3795e40f8fd84f64345047c42bdfa 100644 (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
                }
index daf5cd72a27ebe137df78819109e2286fb3d51cc..76c565ebee127ca42128ec9060269cafca1f540b 100644 (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
index 54f7cd9efa3a9c38fc619fbf605b7669437bb6e1..ab493e0caa48dd84940cbe4aa750c9d22399a065 100644 (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
index e29c826bb7a766b3b06eb366ff69571b25bd50e0..b538ea805429df5dadbe1060d75f77942cfc7cbd 100644 (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('}')
index 9bc636d7ffe41b84c49e8f56833bf5ead52f5d87..dde9f5185687ad6869d0961f85928df97e8a133b 100644 (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
                        }
index a75429f0abadb8dc1c80ce944221b6253f79098a..f0e695ab964ac532dbeb3ad2bfdcae2e1e8479c2 100644 (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 {
index f80de937befb8bc808c7709ef2874a760f19bf9a..4c3ef693467091a7369ca5413998aac2fa164d72 100644 (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},
index 762cdd32584f4b7900a1a380cae61135c309f4ab..969195b850d96a3a8335d071147638ce6da24047 100644 (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
 }
 
+// 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)
+}
+
+// Fields returns the fields of struct type t.
 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
+       t.wantEtype(TSTRUCT)
+       return &t.Extra.(*Struct).fields
 }
 
-// Field returns the i'th field/method of struct/interface type t.
+// 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.