1
0
mirror of https://github.com/golang/go synced 2024-10-02 00:28:33 -06:00

cmd/compile: replace TFIELD kind with separate Field type

Allows removing a bunch of unnecessary fields.

Passes toolstash/buildall.

Change-Id: Iec2492920e1c3ef352a9bf4296c74a55d9cc9ad6
Reviewed-on: https://go-review.googlesource.com/20677
Reviewed-by: Robert Griesemer <gri@golang.org>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Matthew Dempsky 2016-03-14 01:20:49 -07:00
parent 2a46b08a02
commit 2e9369067b
22 changed files with 295 additions and 292 deletions

View File

@ -550,7 +550,7 @@ func eqmemfunc(size int64, t *Type) (fn *Node, needsize bool) {
// size is the length in bytes of the memory included in the run. // size is the length in bytes of the memory included in the run.
// next is the index just after the end of the memory run. // next is the index just after the end of the memory run.
// TODO(mdempsky): Eliminate fields parameter once struct fields are kept in slices. // TODO(mdempsky): Eliminate fields parameter once struct fields are kept in slices.
func memrun(t *Type, fields []*Type, start int) (size int64, next int) { func memrun(t *Type, fields []*Field, start int) (size int64, next int) {
next = start next = start
for { for {
next++ next++
@ -573,7 +573,7 @@ func memrun(t *Type, fields []*Type, start int) (size int64, next int) {
// ispaddedfield reports whether the i'th field of struct type t is followed // ispaddedfield reports whether the i'th field of struct type t is followed
// by padding. The caller is responsible for providing t.FieldSlice() as fields. // by padding. The caller is responsible for providing t.FieldSlice() as fields.
// TODO(mdempsky): Eliminate fields parameter once struct fields are kept in slices. // TODO(mdempsky): Eliminate fields parameter once struct fields are kept in slices.
func ispaddedfield(t *Type, fields []*Type, i int) bool { func ispaddedfield(t *Type, fields []*Field, i int) bool {
if t.Etype != TSTRUCT { if t.Etype != TSTRUCT {
Fatalf("ispaddedfield called non-struct %v", t) Fatalf("ispaddedfield called non-struct %v", t)
} }

View File

@ -20,9 +20,6 @@ func Rnd(o int64, r int64) int64 {
func offmod(t *Type) { func offmod(t *Type) {
o := int32(0) o := int32(0)
for f, it := IterFields(t); f != nil; f = it.Next() { for f, it := IterFields(t); f != nil; f = it.Next() {
if f.Etype != TFIELD {
Fatalf("offmod: not TFIELD: %v", Tconv(f, obj.FmtLong))
}
f.Width = int64(o) f.Width = int64(o)
o += int32(Widthptr) o += int32(Widthptr)
if int64(o) >= Thearch.MAXWIDTH { if int64(o) >= Thearch.MAXWIDTH {
@ -41,9 +38,6 @@ func widstruct(errtype *Type, t *Type, o int64, flag int) int64 {
lastzero := int64(0) lastzero := int64(0)
var w int64 var w int64
for f, it := IterFields(t); f != nil; f = it.Next() { for f, it := IterFields(t); f != nil; f = it.Next() {
if f.Etype != TFIELD {
Fatalf("widstruct: not TFIELD: %v", Tconv(f, obj.FmtLong))
}
if f.Type == nil { if f.Type == nil {
// broken field, just skip it so that other valid fields // broken field, just skip it so that other valid fields
// get a width. // get a width.

View File

@ -433,10 +433,6 @@ func (p *exporter) typ(t *Type) {
// pick off named types // pick off named types
if sym := t.Sym; sym != nil { if sym := t.Sym; sym != nil {
// Fields should be exported by p.field().
if t.Etype == TFIELD {
Fatalf("exporter: printing a field/parameter with wrong function")
}
// Predeclared types should have been found in the type map. // Predeclared types should have been found in the type map.
if t.Orig == t { if t.Orig == t {
Fatalf("exporter: predeclared type missing from type map?") Fatalf("exporter: predeclared type missing from type map?")
@ -464,7 +460,7 @@ func (p *exporter) typ(t *Type) {
// sort methods for reproducible export format // sort methods for reproducible export format
// TODO(gri) Determine if they are already sorted // TODO(gri) Determine if they are already sorted
// in which case we can drop this step. // in which case we can drop this step.
var methods []*Type var methods []*Field
for m, it := IterMethods(t); m != nil; m = it.Next() { for m, it := IterMethods(t); m != nil; m = it.Next() {
methods = append(methods, m) methods = append(methods, m)
} }
@ -566,11 +562,7 @@ func (p *exporter) fieldList(t *Type) {
} }
} }
func (p *exporter) field(f *Type) { func (p *exporter) field(f *Field) {
if f.Etype != TFIELD {
Fatalf("exporter: field expected")
}
p.fieldName(f) p.fieldName(f)
p.typ(f.Type) p.typ(f.Type)
p.note(f.Note) p.note(f.Note)
@ -599,11 +591,7 @@ func (p *exporter) methodList(t *Type) {
} }
} }
func (p *exporter) method(m *Type) { func (p *exporter) method(m *Field) {
if m.Etype != TFIELD {
Fatalf("exporter: method expected")
}
p.fieldName(m) p.fieldName(m)
// TODO(gri) For functions signatures, we use p.typ() to export // TODO(gri) For functions signatures, we use p.typ() to export
// so we could share the same type with multiple functions. Do // so we could share the same type with multiple functions. Do
@ -614,13 +602,13 @@ func (p *exporter) method(m *Type) {
// fieldName is like qualifiedName but it doesn't record the package // fieldName is like qualifiedName but it doesn't record the package
// for blank (_) or exported names. // for blank (_) or exported names.
func (p *exporter) fieldName(t *Type) { func (p *exporter) fieldName(t *Field) {
sym := t.Sym sym := t.Sym
var name string var name string
if t.Embedded == 0 { if t.Embedded == 0 {
name = sym.Name name = sym.Name
} else if bname := basetypeName(t); bname != "" && !exportname(bname) { } else if bname := basetypeName(t.Type); bname != "" && !exportname(bname) {
// anonymous field with unexported base type name: use "?" as field name // anonymous field with unexported base type name: use "?" as field name
// (bname != "" per spec, but we are conservative in case of errors) // (bname != "" per spec, but we are conservative in case of errors)
name = "?" name = "?"
@ -661,10 +649,7 @@ func (p *exporter) paramList(params *Type) {
} }
} }
func (p *exporter) param(q *Type, n int) { func (p *exporter) param(q *Field, n int) {
if q.Etype != TFIELD {
Fatalf("exporter: parameter expected")
}
t := q.Type t := q.Type
if q.Isddd { if q.Isddd {
// create a fake type to encode ... just for the p.typ call // create a fake type to encode ... just for the p.typ call
@ -685,7 +670,7 @@ func (p *exporter) param(q *Type, n int) {
p.note(q.Note) p.note(q.Note)
} }
func parName(q *Type) string { func parName(q *Field) string {
if q.Sym == nil { if q.Sym == nil {
return "" return ""
} }

View File

@ -2225,9 +2225,9 @@ func stkof(n *Node) int64 {
t = t.Type t = t.Type
} }
t = t.Results().Field(0) f := t.Results().Field(0)
if t != nil { if f != nil {
return t.Width + Ctxt.FixedFrameSize() return f.Width + Ctxt.FixedFrameSize()
} }
} }

View File

@ -297,13 +297,13 @@ func transformclosure(xfunc *Node) {
f := xfunc.Func.Nname f := xfunc.Func.Nname
// We are going to insert captured variables before input args. // We are going to insert captured variables before input args.
var params []*Type var params []*Field
var decls []*Node var decls []*Node
for _, v := range func_.Func.Cvars.Slice() { for _, v := range func_.Func.Cvars.Slice() {
if v.Op == OXXX { if v.Op == OXXX {
continue continue
} }
fld := typ(TFIELD) fld := newField()
fld.Funarg = true fld.Funarg = true
if v.Name.Byval { if v.Name.Byval {
// If v is captured by value, we merely downgrade it to PPARAM. // If v is captured by value, we merely downgrade it to PPARAM.

View File

@ -744,7 +744,7 @@ func checkembeddedtype(t *Type) {
} }
} }
func structfield(n *Node) *Type { func structfield(n *Node) *Field {
lno := lineno lno := lineno
lineno = n.Lineno lineno = n.Lineno
@ -752,7 +752,7 @@ func structfield(n *Node) *Type {
Fatalf("structfield: oops %v\n", n) Fatalf("structfield: oops %v\n", n)
} }
f := typ(TFIELD) f := newField()
f.Isddd = n.Isddd f.Isddd = n.Isddd
if n.Right != nil { if n.Right != nil {
@ -832,7 +832,7 @@ func tostruct0(t *Type, l []*Node) {
Fatalf("struct expected") Fatalf("struct expected")
} }
var fields []*Type var fields []*Field
for _, n := range l { for _, n := range l {
fields = append(fields, structfield(n)) fields = append(fields, structfield(n))
} }
@ -855,7 +855,7 @@ func tofunargs(l []*Node) *Type {
t := typ(TSTRUCT) t := typ(TSTRUCT)
t.Funarg = true t.Funarg = true
var fields []*Type var fields []*Field
for _, n := range l { for _, n := range l {
f := structfield(n) f := structfield(n)
f.Funarg = true f.Funarg = true
@ -878,7 +878,7 @@ func tofunargs(l []*Node) *Type {
return t return t
} }
func interfacefield(n *Node) *Type { func interfacefield(n *Node) *Field {
lno := lineno lno := lineno
lineno = n.Lineno lineno = n.Lineno
@ -890,7 +890,7 @@ func interfacefield(n *Node) *Type {
Yyerror("interface method cannot have annotation") Yyerror("interface method cannot have annotation")
} }
f := typ(TFIELD) f := newField()
f.Isddd = n.Isddd f.Isddd = n.Isddd
if n.Right != nil { if n.Right != nil {
@ -956,14 +956,14 @@ func tointerface0(t *Type, l []*Node) *Type {
Fatalf("interface expected") Fatalf("interface expected")
} }
var fields []*Type var fields []*Field
for _, n := range l { for _, n := range l {
f := interfacefield(n) f := interfacefield(n)
if n.Left == nil && f.Type.Etype == TINTER { if n.Left == nil && f.Type.Etype == TINTER {
// embedded interface, inline methods // embedded interface, inline methods
for t1, it := IterFields(f.Type); t1 != nil; t1 = it.Next() { for t1, it := IterFields(f.Type); t1 != nil; t1 = it.Next() {
f = typ(TFIELD) f = newField()
f.Type = t1.Type f.Type = t1.Type
f.Broke = t1.Broke f.Broke = t1.Broke
f.Sym = t1.Sym f.Sym = t1.Sym
@ -1295,15 +1295,15 @@ func addmethod(msym *Sym, t *Type, tpkg *Pkg, local, nointerface bool) {
} }
// get parent type sym // get parent type sym
pa := t.Recv() // ptr to this structure rf := t.Recv() // ptr to this structure
if pa == nil { if rf == nil {
Yyerror("missing receiver") Yyerror("missing receiver")
return return
} }
pa = pa.Type // base type pa := rf.Type // base type
f := methtype(pa, 1) mt := methtype(pa, 1)
if f == nil { if mt == nil {
t = pa t = pa
if t == nil { // rely on typecheck having complained before if t == nil { // rely on typecheck having complained before
return return
@ -1344,7 +1344,7 @@ func addmethod(msym *Sym, t *Type, tpkg *Pkg, local, nointerface bool) {
return return
} }
pa = f pa = mt
if local && !pa.Local { if local && !pa.Local {
Yyerror("cannot define new methods on non-local type %v", pa) Yyerror("cannot define new methods on non-local type %v", pa)
return return
@ -1366,12 +1366,9 @@ func addmethod(msym *Sym, t *Type, tpkg *Pkg, local, nointerface bool) {
n := Nod(ODCLFIELD, newname(msym), nil) n := Nod(ODCLFIELD, newname(msym), nil)
n.Type = t n.Type = t
var d *Type // last found var d *Field // last found
for f, it := IterMethods(pa); f != nil; f = it.Next() { for f, it := IterMethods(pa); f != nil; f = it.Next() {
d = f d = f
if f.Etype != TFIELD {
Fatalf("addmethod: not TFIELD: %v", Tconv(f, obj.FmtLong))
}
if msym.Name != f.Sym.Name { if msym.Name != f.Sym.Name {
continue continue
} }
@ -1381,7 +1378,7 @@ func addmethod(msym *Sym, t *Type, tpkg *Pkg, local, nointerface bool) {
return return
} }
f = structfield(n) f := structfield(n)
f.Nointerface = nointerface f.Nointerface = nointerface
// during import unexported method names should be in the type's package // during import unexported method names should be in the type's package

View File

@ -273,7 +273,7 @@ func dumpexportvar(s *Sym) {
} }
// methodbyname sorts types by symbol name. // methodbyname sorts types by symbol name.
type methodbyname []*Type type methodbyname []*Field
func (x methodbyname) Len() int { return len(x) } func (x methodbyname) Len() int { return len(x) }
func (x methodbyname) Swap(i, j int) { x[i], x[j] = x[j], x[i] } func (x methodbyname) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
@ -283,9 +283,6 @@ func dumpexporttype(t *Type) {
if t == nil { if t == nil {
return return
} }
if t.Etype == TFIELD {
Fatalf("unexpected TFIELD in dumpexporttype")
}
if t.Printed || t == Types[t.Etype] || t == bytetype || t == runetype || t == errortype { if t.Printed || t == Types[t.Etype] || t == bytetype || t == runetype || t == errortype {
return return
} }
@ -315,7 +312,7 @@ func dumpexporttype(t *Type) {
return return
} }
var m []*Type var m []*Field
for f, it := IterMethods(t); f != nil; f = it.Next() { for f, it := IterMethods(t); f != nil; f = it.Next() {
dumpexporttype(f.Type) dumpexporttype(f.Type)
m = append(m, f) m = append(m, f)
@ -334,10 +331,10 @@ func dumpexporttype(t *Type) {
if Debug['l'] < 2 { if Debug['l'] < 2 {
typecheckinl(f.Type.Nname) typecheckinl(f.Type.Nname)
} }
exportf("\tfunc (%v) %v %v { %v }\n", Tconv(f.Type.Recv(), obj.FmtSharp), Sconv(f.Sym, obj.FmtShort|obj.FmtByte|obj.FmtSharp), Tconv(f.Type, obj.FmtShort|obj.FmtSharp), Hconv(f.Type.Nname.Func.Inl, obj.FmtSharp)) exportf("\tfunc %v %v %v { %v }\n", Tconv(f.Type.Recvs(), obj.FmtSharp), Sconv(f.Sym, obj.FmtShort|obj.FmtByte|obj.FmtSharp), Tconv(f.Type, obj.FmtShort|obj.FmtSharp), Hconv(f.Type.Nname.Func.Inl, obj.FmtSharp))
reexportdeplist(f.Type.Nname.Func.Inl) reexportdeplist(f.Type.Nname.Func.Inl)
} else { } else {
exportf("\tfunc (%v) %v %v\n", Tconv(f.Type.Recv(), obj.FmtSharp), Sconv(f.Sym, obj.FmtShort|obj.FmtByte|obj.FmtSharp), Tconv(f.Type, obj.FmtShort|obj.FmtSharp)) exportf("\tfunc %v %v %v\n", Tconv(f.Type.Recvs(), obj.FmtSharp), Sconv(f.Sym, obj.FmtShort|obj.FmtByte|obj.FmtSharp), Tconv(f.Type, obj.FmtShort|obj.FmtSharp))
} }
} }
} }

View File

@ -401,7 +401,6 @@ var etnames = []string{
TMAP: "MAP", TMAP: "MAP",
TINTER: "INTER", TINTER: "INTER",
TFORW: "FORW", TFORW: "FORW",
TFIELD: "FIELD",
TSTRING: "STRING", TSTRING: "STRING",
TUNSAFEPTR: "TUNSAFEPTR", TUNSAFEPTR: "TUNSAFEPTR",
TANY: "ANY", TANY: "ANY",
@ -510,7 +509,7 @@ func typefmt(t *Type, flag int) string {
} }
// Unless the 'l' flag was specified, if the type has a name, just print that name. // Unless the 'l' flag was specified, if the type has a name, just print that name.
if flag&obj.FmtLong == 0 && t.Sym != nil && t.Etype != TFIELD && t != Types[t.Etype] { if flag&obj.FmtLong == 0 && t.Sym != nil && t != Types[t.Etype] {
switch fmtmode { switch fmtmode {
case FTypeId: case FTypeId:
if flag&obj.FmtShort != 0 { if flag&obj.FmtShort != 0 {
@ -664,14 +663,14 @@ func typefmt(t *Type, flag int) string {
buf.WriteString("(") buf.WriteString("(")
if fmtmode == FTypeId || fmtmode == FErr { // no argument names on function signature, and no "noescape"/"nosplit" tags 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() { for t1, it := IterFields(t); t1 != nil; t1 = it.Next() {
buf.WriteString(Tconv(t1, obj.FmtShort)) buf.WriteString(Fldconv(t1, obj.FmtShort))
if t1.Down != nil { if t1.Down != nil {
buf.WriteString(", ") buf.WriteString(", ")
} }
} }
} else { } else {
for t1, it := IterFields(t); t1 != nil; t1 = it.Next() { for t1, it := IterFields(t); t1 != nil; t1 = it.Next() {
buf.WriteString(Tconv(t1, 0)) buf.WriteString(Fldconv(t1, 0))
if t1.Down != nil { if t1.Down != nil {
buf.WriteString(", ") buf.WriteString(", ")
} }
@ -682,7 +681,7 @@ func typefmt(t *Type, flag int) string {
buf.WriteString("struct {") buf.WriteString("struct {")
for t1, it := IterFields(t); t1 != nil; t1 = it.Next() { for t1, it := IterFields(t); t1 != nil; t1 = it.Next() {
buf.WriteString(" ") buf.WriteString(" ")
buf.WriteString(Tconv(t1, obj.FmtLong)) buf.WriteString(Fldconv(t1, obj.FmtLong))
if t1.Down != nil { if t1.Down != nil {
buf.WriteString(";") buf.WriteString(";")
} }
@ -694,72 +693,6 @@ func typefmt(t *Type, flag int) string {
} }
return buf.String() return buf.String()
case TFIELD:
var name string
if flag&obj.FmtShort == 0 {
s := t.Sym
// Take the name from the original, lest we substituted it with ~r%d or ~b%d.
// ~r%d is a (formerly) unnamed result.
if (fmtmode == FErr || fmtmode == FExp) && t.Nname != nil {
if t.Nname.Orig != nil {
s = t.Nname.Orig.Sym
if s != nil && s.Name[0] == '~' {
if s.Name[1] == 'r' { // originally an unnamed result
s = nil
} else if s.Name[1] == 'b' { // originally the blank identifier _
s = Lookup("_")
}
}
} else {
s = nil
}
}
if s != nil && t.Embedded == 0 {
if t.Funarg {
name = Nconv(t.Nname, 0)
} else if flag&obj.FmtLong != 0 {
name = Sconv(s, obj.FmtShort|obj.FmtByte) // qualify non-exported names (used on structs, not on funarg)
} else {
name = Sconv(s, 0)
}
} else if fmtmode == FExp {
// TODO(rsc) this breaks on the eliding of unused arguments in the backend
// when this is fixed, the special case in dcl.go checkarglist can go.
//if(t->funarg)
// fmtstrcpy(fp, "_ ");
//else
if t.Embedded != 0 && s.Pkg != nil && len(s.Pkg.Path) > 0 {
name = fmt.Sprintf("@%q.?", s.Pkg.Path)
} else {
name = "?"
}
}
}
var typ string
if t.Isddd {
typ = "..." + Tconv(t.Type.Type, 0)
} else {
typ = Tconv(t.Type, 0)
}
str := typ
if name != "" {
str = name + " " + typ
}
// The fmtbody flag is intended to suppress escape analysis annotations
// when printing a function type used in a function body.
// (The escape analysis tags do not apply to func vars.)
// But it must not suppress struct field tags.
// See golang.org/issue/13777 and golang.org/issue/14331.
if flag&obj.FmtShort == 0 && (!fmtbody || !t.Funarg) && t.Note != nil {
str += " " + strconv.Quote(*t.Note)
}
return str
case TFORW: case TFORW:
if t.Sym != nil { if t.Sym != nil {
return fmt.Sprintf("undefined %v", t.Sym) return fmt.Sprintf("undefined %v", t.Sym)
@ -1627,6 +1560,95 @@ func (t *Type) String() string {
return Tconv(t, 0) return Tconv(t, 0)
} }
func Fldconv(f *Field, flag int) string {
if f == nil {
return "<T>"
}
sf := flag
sm, sb := setfmode(&flag)
if fmtmode == FTypeId && (sf&obj.FmtUnsigned != 0) {
fmtpkgpfx++
}
if fmtpkgpfx != 0 {
flag |= obj.FmtUnsigned
}
var name string
if flag&obj.FmtShort == 0 {
s := f.Sym
// Take the name from the original, lest we substituted it with ~r%d or ~b%d.
// ~r%d is a (formerly) unnamed result.
if (fmtmode == FErr || fmtmode == FExp) && f.Nname != nil {
if f.Nname.Orig != nil {
s = f.Nname.Orig.Sym
if s != nil && s.Name[0] == '~' {
if s.Name[1] == 'r' { // originally an unnamed result
s = nil
} else if s.Name[1] == 'b' { // originally the blank identifier _
s = Lookup("_")
}
}
} else {
s = nil
}
}
if s != nil && f.Embedded == 0 {
if f.Funarg {
name = Nconv(f.Nname, 0)
} else if flag&obj.FmtLong != 0 {
name = Sconv(s, obj.FmtShort|obj.FmtByte) // qualify non-exported names (used on structs, not on funarg)
} else {
name = Sconv(s, 0)
}
} else if fmtmode == FExp {
// TODO(rsc) this breaks on the eliding of unused arguments in the backend
// when this is fixed, the special case in dcl.go checkarglist can go.
//if(t->funarg)
// fmtstrcpy(fp, "_ ");
//else
if f.Embedded != 0 && s.Pkg != nil && len(s.Pkg.Path) > 0 {
name = fmt.Sprintf("@%q.?", s.Pkg.Path)
} else {
name = "?"
}
}
}
var typ string
if f.Isddd {
typ = "..." + Tconv(f.Type.Type, 0)
} else {
typ = Tconv(f.Type, 0)
}
str := typ
if name != "" {
str = name + " " + typ
}
// The fmtbody flag is intended to suppress escape analysis annotations
// when printing a function type used in a function body.
// (The escape analysis tags do not apply to func vars.)
// But it must not suppress struct field tags.
// See golang.org/issue/13777 and golang.org/issue/14331.
if flag&obj.FmtShort == 0 && (!fmtbody || !f.Funarg) && f.Note != nil {
str += " " + strconv.Quote(*f.Note)
}
if fmtmode == FTypeId && (sf&obj.FmtUnsigned != 0) {
fmtpkgpfx--
}
flag = sf
fmtbody = sb
fmtmode = sm
return str
}
// Fmt "%T": types. // Fmt "%T": types.
// Flags: 'l' print definition, not name // Flags: 'l' print definition, not name
// 'h' omit 'func' and receiver from function types, short type names // 'h' omit 'func' and receiver from function types, short type names

View File

@ -1235,9 +1235,6 @@ func visitComponents(t *Type, startOffset int64, f func(elem *Type, elemOffset i
} }
for field, it := IterFields(t); field != nil; field = it.Next() { for field, it := IterFields(t); field != nil; field = it.Next() {
if field.Etype != TFIELD {
Fatalf("bad struct")
}
if !visitComponents(field.Type, startOffset+field.Width, f) { if !visitComponents(field.Type, startOffset+field.Width, f) {
return false return false
} }

View File

@ -531,11 +531,15 @@ func newplist() *obj.Plist {
// incorrectly) passed a 1; the behavior is exactly // incorrectly) passed a 1; the behavior is exactly
// the same as it is for 1, except that PARAMOUT is // the same as it is for 1, except that PARAMOUT is
// generated instead of PARAM. // generated instead of PARAM.
func nodarg(t *Type, fp int) *Node { func nodarg(t interface{}, fp int) *Node {
var n *Node var n *Node
// entire argument struct, not just one arg switch t := t.(type) {
if t.Etype == TSTRUCT && t.Funarg { case *Type:
// entire argument struct, not just one arg
if t.Etype != TSTRUCT || !t.Funarg {
Fatalf("nodarg: bad type %v", t)
}
n = Nod(ONAME, nil, nil) n = Nod(ONAME, nil, nil)
n.Sym = Lookup(".args") n.Sym = Lookup(".args")
n.Type = t n.Type = t
@ -548,36 +552,31 @@ func nodarg(t *Type, fp int) *Node {
} }
n.Xoffset = first.Width n.Xoffset = first.Width
n.Addable = true n.Addable = true
goto fp case *Field:
} if fp == 1 || fp == -1 {
for _, n := range Curfn.Func.Dcl {
if t.Etype != TFIELD { if (n.Class == PPARAM || n.Class == PPARAMOUT) && !isblanksym(t.Sym) && n.Sym == t.Sym {
Fatalf("nodarg: not field %v", t) return n
} }
if fp == 1 || fp == -1 {
for _, n := range Curfn.Func.Dcl {
if (n.Class == PPARAM || n.Class == PPARAMOUT) && !isblanksym(t.Sym) && n.Sym == t.Sym {
return n
} }
} }
}
n = Nod(ONAME, nil, nil) n = Nod(ONAME, nil, nil)
n.Type = t.Type n.Type = t.Type
n.Sym = t.Sym n.Sym = t.Sym
if t.Width == BADWIDTH {
if t.Width == BADWIDTH { Fatalf("nodarg: offset not computed for %v", t)
Fatalf("nodarg: offset not computed for %v", t) }
n.Xoffset = t.Width
n.Addable = true
n.Orig = t.Nname
default:
panic("unreachable")
} }
n.Xoffset = t.Width
n.Addable = true
n.Orig = t.Nname
// Rewrite argument named _ to __, // Rewrite argument named _ to __,
// or else the assignment to _ will be // or else the assignment to _ will be
// discarded during code generation. // discarded during code generation.
fp:
if isblank(n) { if isblank(n) {
n.Sym = Lookup("__") n.Sym = Lookup("__")
} }

View File

@ -497,7 +497,7 @@ func mkinlcall(np **Node, fn *Node, isddd bool) {
safemode = save_safemode safemode = save_safemode
} }
func tinlvar(t *Type) *Node { func tinlvar(t *Field) *Node {
if t.Nname != nil && !isblank(t.Nname) { if t.Nname != nil && !isblank(t.Nname) {
if t.Nname.Name.Inlvar == nil { if t.Nname.Name.Inlvar == nil {
Fatalf("missing inlvar for %v\n", t.Nname) Fatalf("missing inlvar for %v\n", t.Nname)
@ -852,7 +852,7 @@ func inlvar(var_ *Node) *Node {
} }
// Synthesize a variable to store the inlined function's results in. // Synthesize a variable to store the inlined function's results in.
func retvar(t *Type, i int) *Node { func retvar(t *Field, i int) *Node {
n := newname(Lookupf("~r%d", i)) n := newname(Lookupf("~r%d", i))
n.Type = t.Type n.Type = t.Type
n.Class = PAUTO n.Class = PAUTO

View File

@ -62,8 +62,8 @@ func uncommonSize(t *Type) int { // Sizeof(runtime.uncommontype{})
return 2*Widthptr + 2*Widthint return 2*Widthptr + 2*Widthint
} }
func makefield(name string, t *Type) *Type { func makefield(name string, t *Type) *Field {
f := typ(TFIELD) f := newField()
f.Type = t f.Type = t
f.Sym = nopkg.Lookup(name) f.Sym = nopkg.Lookup(name)
return f return f
@ -91,7 +91,7 @@ func mapbucket(t *Type) *Type {
arr.Type = Types[TUINT8] arr.Type = Types[TUINT8]
arr.Bound = BUCKETSIZE arr.Bound = BUCKETSIZE
field := make([]*Type, 0, 5) field := make([]*Field, 0, 5)
field = append(field, makefield("topbits", arr)) field = append(field, makefield("topbits", arr))
arr = typ(TARRAY) arr = typ(TARRAY)
arr.Type = keytype arr.Type = keytype
@ -162,7 +162,7 @@ func hmap(t *Type) *Type {
} }
bucket := mapbucket(t) bucket := mapbucket(t)
var field [8]*Type var field [8]*Field
field[0] = makefield("count", Types[TINT]) field[0] = makefield("count", Types[TINT])
field[1] = makefield("flags", Types[TUINT8]) field[1] = makefield("flags", Types[TUINT8])
field[2] = makefield("B", Types[TUINT8]) field[2] = makefield("B", Types[TUINT8])
@ -203,7 +203,7 @@ func hiter(t *Type) *Type {
// checkBucket uintptr // checkBucket uintptr
// } // }
// must match ../../../../runtime/hashmap.go:hiter. // must match ../../../../runtime/hashmap.go:hiter.
var field [12]*Type var field [12]*Field
field[0] = makefield("key", Ptrto(t.Key())) field[0] = makefield("key", Ptrto(t.Key()))
field[1] = makefield("val", Ptrto(t.Type)) field[1] = makefield("val", Ptrto(t.Type))
field[2] = makefield("t", Ptrto(Types[TUINT8])) field[2] = makefield("t", Ptrto(Types[TUINT8]))
@ -286,9 +286,6 @@ func methods(t *Type) []*Sig {
// generating code if necessary. // generating code if necessary.
var ms []*Sig var ms []*Sig
for f, it2 := IterAllMethods(mt); f != nil; f = it2.Next() { for f, it2 := IterAllMethods(mt); f != nil; f = it2.Next() {
if f.Etype != TFIELD {
Fatalf("methods: not field %v", f)
}
if f.Type.Etype != TFUNC || f.Type.Thistuple == 0 { if f.Type.Etype != TFUNC || f.Type.Thistuple == 0 {
Fatalf("non-method on %v method %v %v\n", mt, f.Sym, f) Fatalf("non-method on %v method %v %v\n", mt, f.Sym, f)
} }
@ -360,9 +357,6 @@ func methods(t *Type) []*Sig {
func imethods(t *Type) []*Sig { func imethods(t *Type) []*Sig {
var methods []*Sig var methods []*Sig
for f, it := IterFields(t); f != nil; f = it.Next() { for f, it := IterFields(t); f != nil; f = it.Next() {
if f.Etype != TFIELD {
Fatalf("imethods: not field")
}
if f.Type.Etype != TFUNC || f.Sym == nil { if f.Type.Etype != TFUNC || f.Sym == nil {
continue continue
} }
@ -623,9 +617,6 @@ func haspointers(t *Type) bool {
fallthrough fallthrough
default: default:
ret = true ret = true
case TFIELD:
Fatalf("haspointers: unexpected type, %v", t)
} }
t.Haspointers = 1 + uint8(obj.Bool2int(ret)) t.Haspointers = 1 + uint8(obj.Bool2int(ret))
@ -667,7 +658,7 @@ func typeptrdata(t *Type) int64 {
case TSTRUCT: case TSTRUCT:
// Find the last field that has pointers. // Find the last field that has pointers.
var lastPtrField *Type var lastPtrField *Field
for t1, it := IterFields(t); t1 != nil; t1 = it.Next() { for t1, it := IterFields(t); t1 != nil; t1 = it.Next() {
if haspointers(t1.Type) { if haspointers(t1.Type) {
lastPtrField = t1 lastPtrField = t1
@ -800,7 +791,7 @@ func typesym(t *Type) *Sym {
// tracksym returns the symbol for tracking use of field/method f, assumed // tracksym returns the symbol for tracking use of field/method f, assumed
// to be a member of struct/interface type t. // to be a member of struct/interface type t.
func tracksym(t, f *Type) *Sym { func tracksym(t *Type, f *Field) *Sym {
return Pkglookup(Tconv(t, obj.FmtLeft)+"."+f.Sym.Name, trackpkg) return Pkglookup(Tconv(t, obj.FmtLeft)+"."+f.Sym.Name, trackpkg)
} }

View File

@ -869,11 +869,11 @@ func maplit(ctxt int, n *Node, var_ *Node, init *Nodes) {
syma := Lookup("a") syma := Lookup("a")
symb := Lookup("b") symb := Lookup("b")
var fields [2]*Type var fields [2]*Field
fields[0] = typ(TFIELD) fields[0] = newField()
fields[0].Type = tk fields[0].Type = tk
fields[0].Sym = syma fields[0].Sym = syma
fields[1] = typ(TFIELD) fields[1] = newField()
fields[1].Type = tv fields[1].Type = tv
fields[1].Sym = symb fields[1].Sym = symb

View File

@ -27,7 +27,7 @@ func TestSizeof(t *testing.T) {
{Name{}, 52, 80}, {Name{}, 52, 80},
{Node{}, 92, 144}, {Node{}, 92, 144},
{Sym{}, 60, 112}, {Sym{}, 60, 112},
{Type{}, 140, 232}, {Type{}, 132, 224},
} }
for _, tt := range tests { for _, tt := range tests {

View File

@ -3943,9 +3943,6 @@ func fieldIdx(n *Node) int64 {
var i int64 var i int64
for t1, it := IterFields(t); t1 != nil; t1 = it.Next() { for t1, it := IterFields(t); t1 != nil; t1 = it.Next() {
if t1.Etype != TFIELD {
panic("non-TFIELD in TSTRUCT")
}
if t1.Sym != f.Sym { if t1.Sym != f.Sym {
i++ i++
continue continue

View File

@ -388,7 +388,7 @@ func maptype(key *Type, val *Type) *Type {
} }
// methcmp sorts by symbol, then by package path for unexported symbols. // methcmp sorts by symbol, then by package path for unexported symbols.
type methcmp []*Type type methcmp []*Field
func (x methcmp) Len() int { return len(x) } func (x methcmp) Len() int { return len(x) }
func (x methcmp) Swap(i, j int) { x[i], x[j] = x[j], x[i] } func (x methcmp) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
@ -770,17 +770,17 @@ func eqtypenoname(t1 *Type, t2 *Type) bool {
return false return false
} }
t1, i1 := IterFields(t1) f1, i1 := IterFields(t1)
t2, i2 := IterFields(t2) f2, i2 := IterFields(t2)
for { for {
if !Eqtype(t1, t2) { if !Eqtype(f1.Type, f2.Type) {
return false return false
} }
if t1 == nil { if f1 == nil {
return true return true
} }
t1 = i1.Next() f1 = i1.Next()
t2 = i2.Next() f2 = i2.Next()
} }
} }
@ -822,9 +822,8 @@ func assignop(src *Type, dst *Type, why *string) Op {
// 3. dst is an interface type and src implements dst. // 3. dst is an interface type and src implements dst.
if dst.Etype == TINTER && src.Etype != TNIL { if dst.Etype == TINTER && src.Etype != TNIL {
var missing *Type var missing, have *Field
var ptr int var ptr int
var have *Type
if implements(src, dst, &missing, &have, &ptr) { if implements(src, dst, &missing, &have, &ptr) {
return OCONVIFACE return OCONVIFACE
} }
@ -861,9 +860,8 @@ func assignop(src *Type, dst *Type, why *string) Op {
} }
if src.Etype == TINTER && dst.Etype != TBLANK { if src.Etype == TINTER && dst.Etype != TBLANK {
var have *Type var missing, have *Field
var ptr int var ptr int
var missing *Type
if why != nil && implements(dst, src, &missing, &have, &ptr) { if why != nil && implements(dst, src, &missing, &have, &ptr) {
*why = ": need type assertion" *why = ": need type assertion"
} }
@ -1096,7 +1094,7 @@ func substAny(t *Type, types *[]*Type) *Type {
t = (*types)[0] t = (*types)[0]
*types = (*types)[1:] *types = (*types)[1:]
case TPTR32, TPTR64, TCHAN, TARRAY, TFIELD: case TPTR32, TPTR64, TCHAN, TARRAY:
elem := substAny(t.Type, types) elem := substAny(t.Type, types)
if elem != t.Type { if elem != t.Type {
t = t.Copy() t = t.Copy()
@ -1133,24 +1131,35 @@ func substAny(t *Type, types *[]*Type) *Type {
case TSTRUCT: case TSTRUCT:
// nfs only has to be big enough for the builtin functions. // nfs only has to be big enough for the builtin functions.
var nfs [8]*Type var nfs [8]*Field
fields := t.FieldSlice() fields := t.FieldSlice()
changed := false changed := false
for i, f := range fields { for i, f := range fields {
nf := substAny(f, types) nft := substAny(f.Type, types)
if nf != f { if nft != f.Type {
if !changed { nfs[i] = f.Copy()
for j := 0; j < i; j++ { nfs[i].Type = nft
nfs[j] = fields[j].Copy()
}
}
changed = true changed = true
} else if changed {
nf = f.Copy()
} }
nfs[i] = nf
} }
if changed { if changed {
// Above we've initialized nfs with copied fields
// whenever the field type changed. However, because
// we keep fields in a linked list, we can only safely
// share the unmodified tail of the list. We need to
// copy the rest.
tail := true
for i := len(fields) - 1; i >= 0; i-- {
if nfs[i] != nil {
tail = false
} else if tail {
nfs[i] = fields[i]
} else {
nfs[i] = fields[i].Copy()
}
}
t = t.Copy() t = t.Copy()
t.SetFields(nfs[:len(fields)]) t.SetFields(nfs[:len(fields)])
} }
@ -1540,7 +1549,7 @@ func Setmaxarg(t *Type, extra int32) {
// A Dlist stores a pointer to a TFIELD Type embedded within // A Dlist stores a pointer to a TFIELD Type embedded within
// a TSTRUCT or TINTER Type. // a TSTRUCT or TINTER Type.
type Dlist struct { type Dlist struct {
field *Type field *Field
} }
// dotlist is used by adddot1 to record the path of embedded fields // dotlist is used by adddot1 to record the path of embedded fields
@ -1551,7 +1560,7 @@ var dotlist = make([]Dlist, 10)
// lookdot0 returns the number of fields or methods named s associated // lookdot0 returns the number of fields or methods named s associated
// with Type t. If exactly one exists, it will be returned in *save // with Type t. If exactly one exists, it will be returned in *save
// (if save is not nil). // (if save is not nil).
func lookdot0(s *Sym, t *Type, save **Type, ignorecase bool) int { func lookdot0(s *Sym, t *Type, save **Field, ignorecase bool) int {
u := t u := t
if Isptr[u.Etype] { if Isptr[u.Etype] {
u = u.Type u = u.Type
@ -1590,7 +1599,7 @@ func lookdot0(s *Sym, t *Type, save **Type, ignorecase bool) int {
// in reverse order. If none exist, more will indicate whether t contains any // in reverse order. If none exist, more will indicate whether t contains any
// embedded fields at depth d, so callers can decide whether to retry at // embedded fields at depth d, so callers can decide whether to retry at
// a greater depth. // a greater depth.
func adddot1(s *Sym, t *Type, d int, save **Type, ignorecase bool) (c int, more bool) { func adddot1(s *Sym, t *Type, d int, save **Field, ignorecase bool) (c int, more bool) {
if t.Trecur != 0 { if t.Trecur != 0 {
return return
} }
@ -1644,7 +1653,7 @@ out:
// a selection expression x.f, where x is of type t and f is the symbol s. // a selection expression x.f, where x is of type t and f is the symbol s.
// If no such path exists, dotpath returns nil. // If no such path exists, dotpath returns nil.
// If there are multiple shortest paths to the same depth, ambig is true. // If there are multiple shortest paths to the same depth, ambig is true.
func dotpath(s *Sym, t *Type, save **Type, ignorecase bool) (path []Dlist, ambig bool) { func dotpath(s *Sym, t *Type, save **Field, ignorecase bool) (path []Dlist, ambig bool) {
// The embedding of types within structs imposes a tree structure onto // The embedding of types within structs imposes a tree structure onto
// types: structs parent the types they embed, and types parent their // types: structs parent the types they embed, and types parent their
// fields or methods. Our goal here is to find the shortest path to // fields or methods. Our goal here is to find the shortest path to
@ -1713,7 +1722,7 @@ func adddot(n *Node) *Node {
// with unique tasks and they return // with unique tasks and they return
// the actual methods. // the actual methods.
type Symlink struct { type Symlink struct {
field *Type field *Field
link *Symlink link *Symlink
good bool good bool
followptr bool followptr bool
@ -1803,7 +1812,6 @@ func expandmeth(t *Type) {
// mark top-level method symbols // mark top-level method symbols
// so that expand1 doesn't consider them. // so that expand1 doesn't consider them.
var f *Type
for f, it := IterMethods(t); f != nil; f = it.Next() { for f, it := IterMethods(t); f != nil; f = it.Next() {
f.Sym.Flags |= SymUniq f.Sym.Flags |= SymUniq
} }
@ -1816,6 +1824,7 @@ func expandmeth(t *Type) {
// check each method to be uniquely reachable // check each method to be uniquely reachable
for sl := slist; sl != nil; sl = sl.link { for sl := slist; sl != nil; sl = sl.link {
sl.field.Sym.Flags &^= SymUniq sl.field.Sym.Flags &^= SymUniq
var f *Field
if path, _ := dotpath(sl.field.Sym, t, &f, false); path == nil { if path, _ := dotpath(sl.field.Sym, t, &f, false); path == nil {
continue continue
} }
@ -1894,7 +1903,7 @@ func structargs(tl *Type, mustname bool) []*Node {
var genwrapper_linehistdone int = 0 var genwrapper_linehistdone int = 0
func genwrapper(rcvr *Type, method *Type, newnam *Sym, iface int) { func genwrapper(rcvr *Type, method *Field, newnam *Sym, iface int) {
if false && Debug['r'] != 0 { if false && Debug['r'] != 0 {
fmt.Printf("genwrapper rcvrtype=%v method=%v newnam=%v\n", rcvr, method, newnam) fmt.Printf("genwrapper rcvrtype=%v method=%v newnam=%v\n", rcvr, method, newnam)
} }
@ -2045,14 +2054,14 @@ func hashmem(t *Type) *Node {
return n return n
} }
func ifacelookdot(s *Sym, t *Type, followptr *bool, ignorecase bool) *Type { func ifacelookdot(s *Sym, t *Type, followptr *bool, ignorecase bool) *Field {
*followptr = false *followptr = false
if t == nil { if t == nil {
return nil return nil
} }
var m *Type var m *Field
path, ambig := dotpath(s, t, &m, ignorecase) path, ambig := dotpath(s, t, &m, ignorecase)
if path == nil { if path == nil {
if ambig { if ambig {
@ -2076,7 +2085,7 @@ func ifacelookdot(s *Sym, t *Type, followptr *bool, ignorecase bool) *Type {
return m return m
} }
func implements(t *Type, iface *Type, m **Type, samename **Type, ptr *int) bool { func implements(t, iface *Type, m, samename **Field, ptr *int) bool {
t0 := t t0 := t
if t == nil { if t == nil {
return false return false
@ -2114,16 +2123,13 @@ func implements(t *Type, iface *Type, m **Type, samename **Type, ptr *int) bool
if t != nil { if t != nil {
expandmeth(t) expandmeth(t)
} }
var tm *Type
var imtype *Type
var followptr bool
var rcvr *Type
for im, it := IterFields(iface); im != nil; im = it.Next() { for im, it := IterFields(iface); im != nil; im = it.Next() {
if im.Broke { if im.Broke {
continue continue
} }
imtype = methodfunc(im.Type, nil) imtype := methodfunc(im.Type, nil)
tm = ifacelookdot(im.Sym, t, &followptr, false) var followptr bool
tm := ifacelookdot(im.Sym, t, &followptr, false)
if tm == nil || tm.Nointerface || !Eqtype(methodfunc(tm.Type, nil), imtype) { if tm == nil || tm.Nointerface || !Eqtype(methodfunc(tm.Type, nil), imtype) {
if tm == nil { if tm == nil {
tm = ifacelookdot(im.Sym, t, &followptr, true) tm = ifacelookdot(im.Sym, t, &followptr, true)
@ -2136,7 +2142,7 @@ func implements(t *Type, iface *Type, m **Type, samename **Type, ptr *int) bool
// if pointer receiver in method, // if pointer receiver in method,
// the method does not exist for value types. // the method does not exist for value types.
rcvr = tm.Type.Recv().Type rcvr := tm.Type.Recv().Type
if Isptr[rcvr.Etype] && !Isptr[t0.Etype] && !followptr && !isifacemethod(tm.Type) { if Isptr[rcvr.Etype] && !Isptr[t0.Etype] && !followptr && !isifacemethod(tm.Type) {
if false && Debug['r'] != 0 { if false && Debug['r'] != 0 {

View File

@ -146,7 +146,7 @@ func typecheckswitch(n *Node) {
// type switch // type switch
case Etype: case Etype:
var missing, have *Type var missing, have *Field
var ptr int var ptr int
switch { switch {
case n1.Op == OLITERAL && Istype(n1.Type, TNIL): case n1.Op == OLITERAL && Istype(n1.Type, TNIL):

View File

@ -146,7 +146,7 @@ type Param struct {
Stackparam *Node // OPARAM node referring to stack copy of param Stackparam *Node // OPARAM node referring to stack copy of param
// ONAME PPARAM // ONAME PPARAM
Field *Type // TFIELD in arg struct Field *Field // TFIELD in arg struct
// ONAME closure param with PPARAMREF // ONAME closure param with PPARAMREF
Outer *Node // outer PPARAMREF in nested closure Outer *Node // outer PPARAMREF in nested closure

View File

@ -51,7 +51,6 @@ const (
TMAP TMAP
TINTER TINTER
TFORW TFORW
TFIELD
TANY TANY
TSTRING TSTRING
TUNSAFEPTR TUNSAFEPTR
@ -103,17 +102,14 @@ var (
// A Type represents a Go type. // A Type represents a Go type.
type Type struct { type Type struct {
Etype EType Etype EType
Nointerface bool
Noalg bool Noalg bool
Chan uint8 Chan uint8
Trecur uint8 // to detect loops Trecur uint8 // to detect loops
Printed bool Printed bool
Embedded uint8 // TFIELD embedded type Funarg bool // on TSTRUCT and TFIELD
Funarg bool // on TSTRUCT and TFIELD Local bool // created in this file
Local bool // created in this file
Deferwidth bool Deferwidth bool
Broke bool // broken type definition. Broke bool // broken type definition.
Isddd bool // TFIELD is ... argument
Align uint8 Align uint8
Haspointers uint8 // 0 unknown, 1 no, 2 yes Haspointers uint8 // 0 unknown, 1 no, 2 yes
@ -127,8 +123,8 @@ type Type struct {
Intuple int Intuple int
Outnamed bool Outnamed bool
Method *Type Method *Field
Xmethod *Type Xmethod *Field
Sym *Sym Sym *Sym
Vargen int32 // unique name for OTYPE/ONAME Vargen int32 // unique name for OTYPE/ONAME
@ -137,15 +133,13 @@ type Type struct {
Argwid int64 Argwid int64
// most nodes // most nodes
Type *Type // actual type for TFIELD, element type for TARRAY, TCHAN, TMAP, TPTRxx Type *Type // element type for TARRAY, TCHAN, TMAP, TPTRxx
Width int64 // offset in TFIELD, width in all others Width int64
// TSTRUCT // TSTRUCT
Fields *Type // first struct field Fields *Field // first struct field
// TFIELD Down *Type // key type in TMAP; next struct in Funarg TSTRUCT
Down *Type // next struct field, also key type in TMAP
Note *string // literal string annotation
// TARRAY // TARRAY
Bound int64 // negative is slice Bound int64 // negative is slice
@ -163,6 +157,24 @@ type Type struct {
Copyto []*Node Copyto []*Node
} }
// A Field represents a field in a struct or a method in an interface or
// associated with a named type.
type Field struct {
Nointerface bool
Embedded uint8 // embedded field
Funarg bool
Broke bool // broken field definition
Isddd bool // field is ... argument
Sym *Sym
Nname *Node
Type *Type // field type
Width int64 // TODO(mdempsky): Rename to offset.
Note *string // literal string annotation
Down *Field // next struct field
}
// typ returns a new Type of the specified kind. // typ returns a new Type of the specified kind.
func typ(et EType) *Type { func typ(et EType) *Type {
t := &Type{ t := &Type{
@ -174,6 +186,12 @@ func typ(et EType) *Type {
return t return t
} }
func newField() *Field {
return &Field{
Width: BADWIDTH,
}
}
// Copy returns a shallow copy of the Type. // Copy returns a shallow copy of the Type.
func (t *Type) Copy() *Type { func (t *Type) Copy() *Type {
if t == nil { if t == nil {
@ -187,15 +205,20 @@ func (t *Type) Copy() *Type {
return &nt return &nt
} }
func (f *Field) Copy() *Field {
nf := *f
return &nf
}
// Iter provides an abstraction for iterating across struct fields and // Iter provides an abstraction for iterating across struct fields and
// interface methods. // interface methods.
type Iter struct { type Iter struct {
x *Type x *Field
} }
// IterFields returns the first field or method in struct or interface type t // IterFields returns the first field or method in struct or interface type t
// and an Iter value to continue iterating across the rest. // and an Iter value to continue iterating across the rest.
func IterFields(t *Type) (*Type, Iter) { func IterFields(t *Type) (*Field, Iter) {
if t.Etype != TSTRUCT && t.Etype != TINTER { if t.Etype != TSTRUCT && t.Etype != TINTER {
Fatalf("IterFields: type %v does not have fields", t) Fatalf("IterFields: type %v does not have fields", t)
} }
@ -205,14 +228,14 @@ func IterFields(t *Type) (*Type, Iter) {
// IterMethods returns the first method in type t's method set // IterMethods returns the first method in type t's method set
// and an Iter value to continue iterating across the rest. // and an Iter value to continue iterating across the rest.
// IterMethods does not include promoted methods. // IterMethods does not include promoted methods.
func IterMethods(t *Type) (*Type, Iter) { func IterMethods(t *Type) (*Field, Iter) {
// TODO(mdempsky): Validate t? // TODO(mdempsky): Validate t?
return RawIter(t.Method) return RawIter(t.Method)
} }
// IterAllMethods returns the first (possibly promoted) method in type t's // IterAllMethods returns the first (possibly promoted) method in type t's
// method set and an Iter value to continue iterating across the rest. // method set and an Iter value to continue iterating across the rest.
func IterAllMethods(t *Type) (*Type, Iter) { func IterAllMethods(t *Type) (*Field, Iter) {
// TODO(mdempsky): Validate t? // TODO(mdempsky): Validate t?
return RawIter(t.Xmethod) return RawIter(t.Xmethod)
} }
@ -220,23 +243,20 @@ func IterAllMethods(t *Type) (*Type, Iter) {
// RawIter returns field t and an Iter value to continue iterating across // RawIter returns field t and an Iter value to continue iterating across
// its successor fields. Most code should instead use one of the IterXXX // its successor fields. Most code should instead use one of the IterXXX
// functions above. // functions above.
func RawIter(t *Type) (*Type, Iter) { func RawIter(t *Field) (*Field, Iter) {
i := Iter{x: t} i := Iter{x: t}
f := i.Next() f := i.Next()
return f, i return f, i
} }
// Next returns the next field or method, if any. // Next returns the next field or method, if any.
func (i *Iter) Next() *Type { func (i *Iter) Next() *Field {
if i.x == nil { if i.x == nil {
return nil return nil
} }
t := i.x f := i.x
if t.Etype != TFIELD { i.x = f.Down
Fatalf("Iter.Next: type %v is not a field", t) return f
}
i.x = t.Down
return t
} }
func (t *Type) wantEtype(et EType) { func (t *Type) wantEtype(et EType) {
@ -264,7 +284,7 @@ func (t *Type) Recvs() *Type { return *t.RecvsP() }
func (t *Type) Params() *Type { return *t.ParamsP() } func (t *Type) Params() *Type { return *t.ParamsP() }
func (t *Type) Results() *Type { return *t.ResultsP() } func (t *Type) Results() *Type { return *t.ResultsP() }
func (t *Type) Recv() *Type { return t.Recvs().Field(0) } func (t *Type) Recv() *Field { return t.Recvs().Field(0) }
// recvsParamsResults stores the accessor functions for a function Type's // recvsParamsResults stores the accessor functions for a function Type's
// receiver, parameters, and result parameters, in that order. // receiver, parameters, and result parameters, in that order.
@ -280,7 +300,7 @@ func (t *Type) Key() *Type {
} }
// Field returns the i'th field/method of struct/interface type t. // Field returns the i'th field/method of struct/interface type t.
func (t *Type) Field(i int) *Type { func (t *Type) Field(i int) *Field {
// TODO: store fields in a slice so we can // TODO: store fields in a slice so we can
// look them up by index in constant time. // look them up by index in constant time.
for f, it := IterFields(t); f != nil; f = it.Next() { for f, it := IterFields(t); f != nil; f = it.Next() {
@ -301,8 +321,8 @@ func (t *Type) Field(i int) *Type {
// FieldSlice returns a slice of containing all fields/methods of // FieldSlice returns a slice of containing all fields/methods of
// struct/interface type t. // struct/interface type t.
func (t *Type) FieldSlice() []*Type { func (t *Type) FieldSlice() []*Field {
var s []*Type var s []*Field
for f, it := IterFields(t); f != nil; f = it.Next() { for f, it := IterFields(t); f != nil; f = it.Next() {
s = append(s, f) s = append(s, f)
} }
@ -310,11 +330,11 @@ func (t *Type) FieldSlice() []*Type {
} }
// SetFields sets struct/interface type t's fields/methods to fields. // SetFields sets struct/interface type t's fields/methods to fields.
func (t *Type) SetFields(fields []*Type) { func (t *Type) SetFields(fields []*Field) {
if t.Etype != TSTRUCT && t.Etype != TINTER { if t.Etype != TSTRUCT && t.Etype != TINTER {
Fatalf("SetFields: type %v does not have fields", t) Fatalf("SetFields: type %v does not have fields", t)
} }
var next *Type var next *Field
for i := len(fields) - 1; i >= 0; i-- { for i := len(fields) - 1; i >= 0; i-- {
fields[i].Down = next fields[i].Down = next
next = fields[i] next = fields[i]
@ -456,12 +476,14 @@ func (t *Type) cmp(x *Type) ssa.Cmp {
} }
switch t.Etype { switch t.Etype {
case TMAP, TFIELD: case TMAP:
// No special cases for these two, they are handled if c := t.Down.cmp(x.Down); c != ssa.CMPeq {
// by the general code after the switch. return c
}
case TPTR32, TPTR64: case TPTR32, TPTR64:
return t.Type.cmp(x.Type) // No special cases for these two, they are handled
// by the general code after the switch.
case TSTRUCT: case TSTRUCT:
if t.Map == nil { if t.Map == nil {
@ -545,9 +567,7 @@ func (t *Type) cmp(x *Type) ssa.Cmp {
panic(e) panic(e)
} }
if c := t.Down.cmp(x.Down); c != ssa.CMPeq { // Common element type comparison for TARRAY, TCHAN, TMAP, TPTR32, and TPTR64.
return c
}
return t.Type.cmp(x.Type) return t.Type.cmp(x.Type)
} }

View File

@ -946,8 +946,7 @@ OpSwitch:
} }
if n.Type != nil && n.Type.Etype != TINTER { if n.Type != nil && n.Type.Etype != TINTER {
var have *Type var missing, have *Field
var missing *Type
var ptr int var ptr int
if !implements(n.Type, t, &missing, &have, &ptr) { if !implements(n.Type, t, &missing, &have, &ptr) {
if have != nil && have.Sym == missing.Sym { if have != nil && have.Sym == missing.Sym {
@ -2363,8 +2362,8 @@ func twoarg(n *Node) bool {
return true return true
} }
func lookdot1(errnode *Node, s *Sym, t *Type, f *Type, dostrcmp int) *Type { func lookdot1(errnode *Node, s *Sym, t *Type, f *Field, dostrcmp int) *Field {
var r *Type var r *Field
for f, it := RawIter(f); f != nil; f = it.Next() { for f, it := RawIter(f); f != nil; f = it.Next() {
if dostrcmp != 0 && f.Sym.Name == s.Name { if dostrcmp != 0 && f.Sym.Name == s.Name {
return f return f
@ -2410,14 +2409,13 @@ func looktypedot(n *Node, t *Type, dostrcmp int) bool {
// Find the base type: methtype will fail if t // Find the base type: methtype will fail if t
// is not of the form T or *T. // is not of the form T or *T.
f2 := methtype(t, 0) mt := methtype(t, 0)
if mt == nil {
if f2 == nil {
return false return false
} }
expandmeth(f2) expandmeth(mt)
f2 = lookdot1(n, s, f2, f2.Xmethod, dostrcmp) f2 := lookdot1(n, s, mt, mt.Xmethod, dostrcmp)
if f2 == nil { if f2 == nil {
return false return false
} }
@ -2449,24 +2447,24 @@ type typeSym struct {
// dotField maps (*Type, *Sym) pairs to the corresponding struct field (*Type with Etype==TFIELD). // dotField maps (*Type, *Sym) pairs to the corresponding struct field (*Type with Etype==TFIELD).
// It is a cache for use during usefield in walk.go, only enabled when field tracking. // It is a cache for use during usefield in walk.go, only enabled when field tracking.
var dotField = map[typeSym]*Type{} var dotField = map[typeSym]*Field{}
func lookdot(n *Node, t *Type, dostrcmp int) *Type { func lookdot(n *Node, t *Type, dostrcmp int) *Field {
s := n.Right.Sym s := n.Right.Sym
dowidth(t) dowidth(t)
var f1 *Type var f1 *Field
if t.Etype == TSTRUCT || t.Etype == TINTER { 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 *Type var f2 *Field
if n.Left.Type == t || n.Left.Type.Sym == nil { if n.Left.Type == t || n.Left.Type.Sym == nil {
f2 = methtype(t, 0) mt := methtype(t, 0)
if f2 != nil { if mt != nil {
// Use f2->method, not f2->xmethod: adddot has // Use f2->method, not f2->xmethod: adddot has
// already inserted all the necessary embedded dots. // already inserted all the necessary embedded dots.
f2 = lookdot1(n, s, f2, f2.Method, dostrcmp) f2 = lookdot1(n, s, mt, mt.Method, dostrcmp)
} }
} }

View File

@ -370,18 +370,18 @@ func lexinit1() {
rcvr := typ(TSTRUCT) rcvr := typ(TSTRUCT)
rcvr.Funarg = true rcvr.Funarg = true
field := typ(TFIELD) field := newField()
field.Type = Ptrto(typ(TSTRUCT)) field.Type = Ptrto(typ(TSTRUCT))
rcvr.SetFields([]*Type{field}) rcvr.SetFields([]*Field{field})
in := typ(TSTRUCT) in := typ(TSTRUCT)
in.Funarg = true in.Funarg = true
out := typ(TSTRUCT) out := typ(TSTRUCT)
out.Funarg = true out.Funarg = true
field = typ(TFIELD) field = newField()
field.Type = Types[TSTRING] field.Type = Types[TSTRING]
out.SetFields([]*Type{field}) out.SetFields([]*Field{field})
f := typ(TFUNC) f := typ(TFUNC)
*f.RecvsP() = rcvr *f.RecvsP() = rcvr
@ -393,10 +393,10 @@ func lexinit1() {
f.Outtuple = 1 f.Outtuple = 1
t := typ(TINTER) t := typ(TINTER)
field = typ(TFIELD) field = newField()
field.Sym = Lookup("Error") field.Sym = Lookup("Error")
field.Type = f field.Type = f
t.SetFields([]*Type{field}) t.SetFields([]*Field{field})
// error type // error type
s := Pkglookup("error", builtinpkg) s := Pkglookup("error", builtinpkg)

View File

@ -1752,7 +1752,7 @@ func ascompatet(op Op, nl Nodes, nr *Type, fp int, init *Nodes) []*Node {
} }
// package all the arguments that match a ... T parameter into a []T. // package all the arguments that match a ... T parameter into a []T.
func mkdotargslice(lr0, nn []*Node, l *Type, fp int, init *Nodes, ddd *Node) []*Node { func mkdotargslice(lr0, nn []*Node, l *Field, fp int, init *Nodes, ddd *Node) []*Node {
esc := uint16(EscUnknown) esc := uint16(EscUnknown)
if ddd != nil { if ddd != nil {
esc = ddd.Esc esc = ddd.Esc
@ -1792,7 +1792,7 @@ func dumptypes(nl *Type, what string) string {
if s != "" { if s != "" {
s += ", " s += ", "
} }
s += Tconv(l, 0) s += Fldconv(l, 0)
} }
if s == "" { if s == "" {
s = fmt.Sprintf("[no arguments %s]", what) s = fmt.Sprintf("[no arguments %s]", what)
@ -3774,7 +3774,7 @@ func usemethod(n *Node) {
} }
p0 := t.Params().Field(0) p0 := t.Params().Field(0)
res0 := t.Results().Field(0) res0 := t.Results().Field(0)
var res1 *Type var res1 *Field
if countfield(t.Results()) == 2 { if countfield(t.Results()) == 2 {
res1 = t.Results().Field(1) res1 = t.Results().Field(1)
} }
@ -3791,7 +3791,7 @@ func usemethod(n *Node) {
return return
} }
} }
if Tconv(res0, 0) != "reflect.Method" { if Tconv(res0.Type, 0) != "reflect.Method" {
return return
} }