aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Scales <danscales@google.com>2021-04-02 16:52:58 -0700
committerDan Scales <danscales@google.com>2021-04-05 15:30:15 +0000
commita4b8241d97fb180e1b9cb41c4828345c931d1aaf (patch)
treec38279cd1a5493824af9384b7cd8765cea58a63b
parent6ed045b365731e59fcae48de48f1aea7a6304eb3 (diff)
downloadgo-a4b8241d97fb180e1b9cb41c4828345c931d1aaf.tar.gz
go-a4b8241d97fb180e1b9cb41c4828345c931d1aaf.zip
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>
-rw-r--r--src/cmd/compile/internal/gc/export.go2
-rw-r--r--src/cmd/compile/internal/noder/helpers.go2
-rw-r--r--src/cmd/compile/internal/noder/stencil.go4
-rw-r--r--src/cmd/compile/internal/noder/transform.go2
-rw-r--r--src/cmd/compile/internal/reflectdata/reflect.go2
-rw-r--r--src/cmd/compile/internal/typecheck/subr.go34
-rw-r--r--src/cmd/compile/internal/typecheck/typecheck.go6
-rw-r--r--src/cmd/compile/internal/types/fmt.go4
-rw-r--r--src/cmd/compile/internal/types/identity.go6
-rw-r--r--src/cmd/compile/internal/types/size.go6
-rw-r--r--src/cmd/compile/internal/types/sizeof_test.go2
-rw-r--r--src/cmd/compile/internal/types/type.go49
12 files changed, 73 insertions, 46 deletions
diff --git a/src/cmd/compile/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go
index 4d8221f53b..2137f1d196 100644
--- a/src/cmd/compile/internal/gc/export.go
+++ b/src/cmd/compile/internal/gc/export.go
@@ -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)
}
diff --git a/src/cmd/compile/internal/noder/helpers.go b/src/cmd/compile/internal/noder/helpers.go
index 6320b30e50..9da0e49300 100644
--- a/src/cmd/compile/internal/noder/helpers.go
+++ b/src/cmd/compile/internal/noder/helpers.go
@@ -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)
}
diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go
index 4db688571e..0d84db9993 100644
--- a/src/cmd/compile/internal/noder/stencil.go
+++ b/src/cmd/compile/internal/noder/stencil.go
@@ -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 {
diff --git a/src/cmd/compile/internal/noder/transform.go b/src/cmd/compile/internal/noder/transform.go
index 021d3a9fa7..ffe35d5874 100644
--- a/src/cmd/compile/internal/noder/transform.go
+++ b/src/cmd/compile/internal/noder/transform.go
@@ -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)
diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go
index c1cded826c..3a31e3c951 100644
--- a/src/cmd/compile/internal/reflectdata/reflect.go
+++ b/src/cmd/compile/internal/reflectdata/reflect.go
@@ -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
}
diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go
index daf5cd72a2..76c565ebee 100644
--- a/src/cmd/compile/internal/typecheck/subr.go
+++ b/src/cmd/compile/internal/typecheck/subr.go
@@ -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
diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go
index 54f7cd9efa..ab493e0caa 100644
--- a/src/cmd/compile/internal/typecheck/typecheck.go
+++ b/src/cmd/compile/internal/typecheck/typecheck.go
@@ -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
diff --git a/src/cmd/compile/internal/types/fmt.go b/src/cmd/compile/internal/types/fmt.go
index e29c826bb7..b538ea8054 100644
--- a/src/cmd/compile/internal/types/fmt.go
+++ b/src/cmd/compile/internal/types/fmt.go
@@ -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('}')
diff --git a/src/cmd/compile/internal/types/identity.go b/src/cmd/compile/internal/types/identity.go
index 9bc636d7ff..dde9f51856 100644
--- a/src/cmd/compile/internal/types/identity.go
+++ b/src/cmd/compile/internal/types/identity.go
@@ -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
}
diff --git a/src/cmd/compile/internal/types/size.go b/src/cmd/compile/internal/types/size.go
index a75429f0ab..f0e695ab96 100644
--- a/src/cmd/compile/internal/types/size.go
+++ b/src/cmd/compile/internal/types/size.go
@@ -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 {
diff --git a/src/cmd/compile/internal/types/sizeof_test.go b/src/cmd/compile/internal/types/sizeof_test.go
index f80de937be..4c3ef69346 100644
--- a/src/cmd/compile/internal/types/sizeof_test.go
+++ b/src/cmd/compile/internal/types/sizeof_test.go
@@ -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},
diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go
index 762cdd3258..969195b850 100644
--- a/src/cmd/compile/internal/types/type.go
+++ b/src/cmd/compile/internal/types/type.go
@@ -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.