n := Nod(ODCLFIELD, newname(msym), nil)
n.Type = t
- var d *Field // last found
for f, it := IterMethods(pa); f != nil; f = it.Next() {
- d = f
if msym.Name != f.Sym.Name {
continue
}
Fatalf("imported method name %v in wrong package %s\n", Sconv(f.Sym, FmtSign), tpkg.Name)
}
- if d == nil {
- pa.Method = f
- } else {
- d.Down = f
- }
+ pa.Methods().Append(f)
}
func funccompile(n *Node) {
case TINTER:
var buf bytes.Buffer
buf.WriteString("interface {")
- for t1, it := IterFields(t); t1 != nil; t1 = it.Next() {
+ for i, f := range t.Fields().Slice() {
+ if i != 0 {
+ buf.WriteString(";")
+ }
buf.WriteString(" ")
switch {
- case t1.Sym == nil:
+ case f.Sym == nil:
// Check first that a symbol is defined for this type.
// Wrong interface definitions may have types lacking a symbol.
break
- case exportname(t1.Sym.Name):
- buf.WriteString(Sconv(t1.Sym, FmtShort))
+ case exportname(f.Sym.Name):
+ buf.WriteString(Sconv(f.Sym, FmtShort))
default:
- buf.WriteString(Sconv(t1.Sym, FmtUnsigned))
- }
- buf.WriteString(Tconv(t1.Type, FmtShort))
- if t1.Down != nil {
- buf.WriteString(";")
+ buf.WriteString(Sconv(f.Sym, FmtUnsigned))
}
+ buf.WriteString(Tconv(f.Type, FmtShort))
}
- if t.Fields != nil {
+ if t.NumFields() != 0 {
buf.WriteString(" ")
}
buf.WriteString("}")
var buf bytes.Buffer
if t.Funarg {
buf.WriteString("(")
+ var flag1 FmtFlag
if fmtmode == FTypeId || fmtmode == FErr { // no argument names on function signature, and no "noescape"/"nosplit" tags
- for t1, it := IterFields(t); t1 != nil; t1 = it.Next() {
- buf.WriteString(Fldconv(t1, FmtShort))
- if t1.Down != nil {
- buf.WriteString(", ")
- }
- }
- } else {
- for t1, it := IterFields(t); t1 != nil; t1 = it.Next() {
- buf.WriteString(Fldconv(t1, 0))
- if t1.Down != nil {
- buf.WriteString(", ")
- }
+ flag1 = FmtShort
+ }
+ for i, f := range t.Fields().Slice() {
+ if i != 0 {
+ buf.WriteString(", ")
}
+ buf.WriteString(Fldconv(f, flag1))
}
buf.WriteString(")")
} else {
buf.WriteString("struct {")
- for t1, it := IterFields(t); t1 != nil; t1 = it.Next() {
- buf.WriteString(" ")
- buf.WriteString(Fldconv(t1, FmtLong))
- if t1.Down != nil {
+ for i, f := range t.Fields().Slice() {
+ if i != 0 {
buf.WriteString(";")
}
+ buf.WriteString(" ")
+ buf.WriteString(Fldconv(f, FmtLong))
}
- if t.Fields != nil {
+ if t.NumFields() != 0 {
buf.WriteString(" ")
}
buf.WriteString("}")
// make list of methods for t,
// generating code if necessary.
var ms []*Sig
- for f, it2 := IterAllMethods(mt); f != nil; f = it2.Next() {
+ for _, f := range mt.AllMethods().Slice() {
if f.Type.Etype != TFUNC || f.Type.Thistuple == 0 {
Fatalf("non-method on %v method %v %v\n", mt, f.Sym, f)
}
// the actual methods.
type Symlink struct {
field *Field
- link *Symlink
- good bool
followptr bool
}
-var slist *Symlink
+var slist []Symlink
func expand0(t *Type, followptr bool) {
u := t
}
if u.Etype == TINTER {
- var sl *Symlink
for f, it := IterFields(u); f != nil; f = it.Next() {
if f.Sym.Flags&SymUniq != 0 {
continue
}
f.Sym.Flags |= SymUniq
- sl = new(Symlink)
- sl.field = f
- sl.link = slist
- sl.followptr = followptr
- slist = sl
+ slist = append(slist, Symlink{field: f, followptr: followptr})
}
return
u = methtype(t, 0)
if u != nil {
- var sl *Symlink
for f, it := IterMethods(u); f != nil; f = it.Next() {
if f.Sym.Flags&SymUniq != 0 {
continue
}
f.Sym.Flags |= SymUniq
- sl = new(Symlink)
- sl.field = f
- sl.link = slist
- sl.followptr = followptr
- slist = sl
+ slist = append(slist, Symlink{field: f, followptr: followptr})
}
}
}
}
func expandmeth(t *Type) {
- if t == nil || t.Xmethod != nil {
+ if t == nil || t.AllMethods().Len() != 0 {
return
}
}
// generate all reachable methods
- slist = nil
-
+ slist = slist[:0]
expand1(t, true, false)
// check each method to be uniquely reachable
- for sl := slist; sl != nil; sl = sl.link {
+ var ms []*Field
+ for i, sl := range slist {
+ slist[i].field = nil
sl.field.Sym.Flags &^= SymUniq
+
var f *Field
if path, _ := dotpath(sl.field.Sym, t, &f, false); path == nil {
continue
}
+
// dotpath may have dug out arbitrary fields, we only want methods.
- if f.Type.Etype == TFUNC && f.Type.Thistuple > 0 {
- sl.good = true
- sl.field = f
+ if f.Type.Etype != TFUNC || f.Type.Thistuple == 0 {
+ continue
}
+
+ // add it to the base type method list
+ f = f.Copy()
+ f.Embedded = 1 // needs a trampoline
+ if sl.followptr {
+ f.Embedded = 2
+ }
+ ms = append(ms, f)
}
for f, it := IterMethods(t); f != nil; f = it.Next() {
f.Sym.Flags &^= SymUniq
}
- t.Xmethod = t.Method
- for sl := slist; sl != nil; sl = sl.link {
- if sl.good {
- // add it to the base type method list
- f := sl.field.Copy()
- f.Embedded = 1 // needs a trampoline
- if sl.followptr {
- f.Embedded = 2
- }
- f.Down = t.Xmethod
- t.Xmethod = f
- }
- }
+ ms = append(ms, t.Methods().Slice()...)
+ t.AllMethods().Set(ms)
}
// Given funarg struct list, return list of ODCLFIELD Node fn args.
Intuple int
Outnamed bool
- Method *Field
- Xmethod *Field
+ methods Fields
+ allMethods Fields
Sym *Sym
Vargen int32 // unique name for OTYPE/ONAME
Width int64
// TSTRUCT
- Fields *Field // first struct field
+ fields Fields
Down *Type // key type in TMAP; next struct in Funarg TSTRUCT
Type *Type // field type
Width int64 // TODO(mdempsky): Rename to offset.
Note *string // literal string annotation
- Down *Field // next struct field
+}
+
+// Fields is a pointer to a slice of *Field.
+// This saves space in Types that do not have fields or methods
+// compared to a simple slice of *Field.
+type Fields struct {
+ s *[]*Field
+}
+
+// Len returns the number of entries in f.
+func (f *Fields) Len() int {
+ if f.s == nil {
+ return 0
+ }
+ return len(*f.s)
+}
+
+// Slice returns the entries in f as a slice.
+// Changes to the slice entries will be reflected in f.
+func (f *Fields) Slice() []*Field {
+ if f.s == nil {
+ return nil
+ }
+ return *f.s
+}
+
+// Set sets f to a slice.
+// This takes ownership of the slice.
+func (f *Fields) Set(s []*Field) {
+ if len(s) != 0 {
+ f.s = &s
+ } else {
+ f.s = nil
+ }
+}
+
+// Append appends entries to f.
+func (f *Fields) Append(s ...*Field) {
+ if f.s == nil {
+ f.s = new([]*Field)
+ }
+ *f.s = append(*f.s, s...)
}
// typ returns a new Type of the specified kind.
// Iter provides an abstraction for iterating across struct fields and
// interface methods.
type Iter struct {
- x *Field
+ s []*Field
}
// IterFields returns the first field or method in struct or interface type t
// and an Iter value to continue iterating across the rest.
func IterFields(t *Type) (*Field, Iter) {
- if t.Etype != TSTRUCT && t.Etype != TINTER {
- Fatalf("IterFields: type %v does not have fields", t)
- }
- return RawIter(t.Fields)
+ return t.Fields().Iter()
}
// IterMethods returns the first method in type t's method set
// and an Iter value to continue iterating across the rest.
// IterMethods does not include promoted methods.
func IterMethods(t *Type) (*Field, Iter) {
- // TODO(mdempsky): Validate t?
- return RawIter(t.Method)
-}
-
-// IterAllMethods returns the first (possibly promoted) method in type t's
-// method set and an Iter value to continue iterating across the rest.
-func IterAllMethods(t *Type) (*Field, Iter) {
- // TODO(mdempsky): Validate t?
- return RawIter(t.Xmethod)
+ return t.Methods().Iter()
}
-// RawIter returns field t and an Iter value to continue iterating across
-// its successor fields. Most code should instead use one of the IterXXX
-// functions above.
-func RawIter(t *Field) (*Field, Iter) {
- i := Iter{x: t}
+// Iter returns the first field in fs and an Iter value to continue iterating
+// across its successor fields.
+// Deprecated: New code should use Slice instead.
+func (fs *Fields) Iter() (*Field, Iter) {
+ i := Iter{s: fs.Slice()}
f := i.Next()
return f, i
}
// Next returns the next field or method, if any.
func (i *Iter) Next() *Field {
- if i.x == nil {
+ if len(i.s) == 0 {
return nil
}
- f := i.x
- i.x = f.Down
+ f := i.s[0]
+ i.s = i.s[1:]
return f
}
return t.Down
}
+func (t *Type) Methods() *Fields {
+ // TODO(mdempsky): Validate t?
+ return &t.methods
+}
+
+func (t *Type) AllMethods() *Fields {
+ // TODO(mdempsky): Validate t?
+ return &t.allMethods
+}
+
+func (t *Type) Fields() *Fields {
+ if t.Etype != TSTRUCT && t.Etype != TINTER {
+ Fatalf("Fields: type %v does not have fields", t)
+ }
+ return &t.fields
+}
+
// Field returns the i'th field/method of struct/interface type t.
func (t *Type) Field(i int) *Field {
- // TODO: store fields in a slice so we can
- // look them up by index in constant time.
- for f, it := IterFields(t); f != nil; f = it.Next() {
- if i == 0 {
- return f
- }
- i--
- }
- panic("not enough fields")
+ return t.Fields().Slice()[i]
}
// FieldSlice returns a slice of containing all fields/methods of
// struct/interface type t.
func (t *Type) FieldSlice() []*Field {
- var s []*Field
- for f, it := IterFields(t); f != nil; f = it.Next() {
- s = append(s, f)
- }
- return s
+ return t.Fields().Slice()
}
// SetFields sets struct/interface type t's fields/methods to fields.
func (t *Type) SetFields(fields []*Field) {
- if t.Etype != TSTRUCT && t.Etype != TINTER {
- Fatalf("SetFields: type %v does not have fields", t)
- }
- var next *Field
- for i := len(fields) - 1; i >= 0; i-- {
- fields[i].Down = next
- next = fields[i]
- }
- t.Fields = next
+ t.Fields().Set(fields)
}
func (t *Type) Size() int64 {
}
func (t *Type) NumFields() int {
- n := 0
- for f, it := IterFields(t); f != nil; f = it.Next() {
- n++
- }
- return n
+ return t.Fields().Len()
}
func (t *Type) FieldType(i int) ssa.Type {
return t.Field(i).Type
return true
}
-func lookdot1(errnode *Node, s *Sym, t *Type, f *Field, dostrcmp int) *Field {
+func lookdot1(errnode *Node, s *Sym, t *Type, fs *Fields, dostrcmp int) *Field {
var r *Field
- for f, it := RawIter(f); f != nil; f = it.Next() {
+ for _, f := range fs.Slice() {
if dostrcmp != 0 && f.Sym.Name == s.Name {
return f
}
s := n.Right.Sym
if t.Etype == TINTER {
- f1 := lookdot1(n, s, t, t.Fields, dostrcmp)
+ f1 := lookdot1(n, s, t, t.Fields(), dostrcmp)
if f1 == nil {
return false
}
}
expandmeth(mt)
- f2 := lookdot1(n, s, mt, mt.Xmethod, dostrcmp)
+ f2 := lookdot1(n, s, mt, mt.AllMethods(), dostrcmp)
if f2 == nil {
return false
}
dowidth(t)
var f1 *Field
if t.Etype == TSTRUCT || t.Etype == TINTER {
- f1 = lookdot1(n, s, t, t.Fields, dostrcmp)
+ f1 = lookdot1(n, s, t, t.Fields(), dostrcmp)
}
var f2 *Field
if mt != nil {
// Use f2->method, not f2->xmethod: adddot has
// already inserted all the necessary embedded dots.
- f2 = lookdot1(n, s, mt, mt.Method, dostrcmp)
+ f2 = lookdot1(n, s, mt, mt.Methods(), dostrcmp)
}
}
}
}
- f := lookdot1(nil, s, t, t.Fields, 0)
+ f := lookdot1(nil, s, t, t.Fields(), 0)
if f == nil {
Yyerror("unknown %v field '%v' in struct literal", t, s)
continue
if n.Name != nil {
t.Vargen = n.Name.Vargen
}
- t.Method = nil
- t.Xmethod = nil
+ t.methods = Fields{}
+ t.allMethods = Fields{}
t.Nod = nil
t.Printed = false
t.Deferwidth = false