Commit 2e936906 authored by Matthew Dempsky's avatar Matthew Dempsky

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/20677Reviewed-by: default avatarRobert Griesemer <gri@golang.org>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 2a46b08a
......@@ -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.
// next is the index just after the end of the memory run.
// 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
for {
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
// by padding. The caller is responsible for providing t.FieldSlice() as fields.
// 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 {
Fatalf("ispaddedfield called non-struct %v", t)
}
......
......@@ -20,9 +20,6 @@ func Rnd(o int64, r int64) int64 {
func offmod(t *Type) {
o := int32(0)
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)
o += int32(Widthptr)
if int64(o) >= Thearch.MAXWIDTH {
......@@ -41,9 +38,6 @@ func widstruct(errtype *Type, t *Type, o int64, flag int) int64 {
lastzero := int64(0)
var w int64
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 {
// broken field, just skip it so that other valid fields
// get a width.
......
......@@ -433,10 +433,6 @@ func (p *exporter) typ(t *Type) {
// pick off named types
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.
if t.Orig == t {
Fatalf("exporter: predeclared type missing from type map?")
......@@ -464,7 +460,7 @@ func (p *exporter) typ(t *Type) {
// sort methods for reproducible export format
// TODO(gri) Determine if they are already sorted
// in which case we can drop this step.
var methods []*Type
var methods []*Field
for m, it := IterMethods(t); m != nil; m = it.Next() {
methods = append(methods, m)
}
......@@ -566,11 +562,7 @@ func (p *exporter) fieldList(t *Type) {
}
}
func (p *exporter) field(f *Type) {
if f.Etype != TFIELD {
Fatalf("exporter: field expected")
}
func (p *exporter) field(f *Field) {
p.fieldName(f)
p.typ(f.Type)
p.note(f.Note)
......@@ -599,11 +591,7 @@ func (p *exporter) methodList(t *Type) {
}
}
func (p *exporter) method(m *Type) {
if m.Etype != TFIELD {
Fatalf("exporter: method expected")
}
func (p *exporter) method(m *Field) {
p.fieldName(m)
// TODO(gri) For functions signatures, we use p.typ() to export
// 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
// for blank (_) or exported names.
func (p *exporter) fieldName(t *Type) {
func (p *exporter) fieldName(t *Field) {
sym := t.Sym
var name string
if t.Embedded == 0 {
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
// (bname != "" per spec, but we are conservative in case of errors)
name = "?"
......@@ -661,10 +649,7 @@ func (p *exporter) paramList(params *Type) {
}
}
func (p *exporter) param(q *Type, n int) {
if q.Etype != TFIELD {
Fatalf("exporter: parameter expected")
}
func (p *exporter) param(q *Field, n int) {
t := q.Type
if q.Isddd {
// 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)
}
func parName(q *Type) string {
func parName(q *Field) string {
if q.Sym == nil {
return ""
}
......
......@@ -2225,9 +2225,9 @@ func stkof(n *Node) int64 {
t = t.Type
}
t = t.Results().Field(0)
if t != nil {
return t.Width + Ctxt.FixedFrameSize()
f := t.Results().Field(0)
if f != nil {
return f.Width + Ctxt.FixedFrameSize()
}
}
......
......@@ -297,13 +297,13 @@ func transformclosure(xfunc *Node) {
f := xfunc.Func.Nname
// We are going to insert captured variables before input args.
var params []*Type
var params []*Field
var decls []*Node
for _, v := range func_.Func.Cvars.Slice() {
if v.Op == OXXX {
continue
}
fld := typ(TFIELD)
fld := newField()
fld.Funarg = true
if v.Name.Byval {
// If v is captured by value, we merely downgrade it to PPARAM.
......
......@@ -744,7 +744,7 @@ func checkembeddedtype(t *Type) {
}
}
func structfield(n *Node) *Type {
func structfield(n *Node) *Field {
lno := lineno
lineno = n.Lineno
......@@ -752,7 +752,7 @@ func structfield(n *Node) *Type {
Fatalf("structfield: oops %v\n", n)
}
f := typ(TFIELD)
f := newField()
f.Isddd = n.Isddd
if n.Right != nil {
......@@ -832,7 +832,7 @@ func tostruct0(t *Type, l []*Node) {
Fatalf("struct expected")
}
var fields []*Type
var fields []*Field
for _, n := range l {
fields = append(fields, structfield(n))
}
......@@ -855,7 +855,7 @@ func tofunargs(l []*Node) *Type {
t := typ(TSTRUCT)
t.Funarg = true
var fields []*Type
var fields []*Field
for _, n := range l {
f := structfield(n)
f.Funarg = true
......@@ -878,7 +878,7 @@ func tofunargs(l []*Node) *Type {
return t
}
func interfacefield(n *Node) *Type {
func interfacefield(n *Node) *Field {
lno := lineno
lineno = n.Lineno
......@@ -890,7 +890,7 @@ func interfacefield(n *Node) *Type {
Yyerror("interface method cannot have annotation")
}
f := typ(TFIELD)
f := newField()
f.Isddd = n.Isddd
if n.Right != nil {
......@@ -956,14 +956,14 @@ func tointerface0(t *Type, l []*Node) *Type {
Fatalf("interface expected")
}
var fields []*Type
var fields []*Field
for _, n := range l {
f := interfacefield(n)
if n.Left == nil && f.Type.Etype == TINTER {
// embedded interface, inline methods
for t1, it := IterFields(f.Type); t1 != nil; t1 = it.Next() {
f = typ(TFIELD)
f = newField()
f.Type = t1.Type
f.Broke = t1.Broke
f.Sym = t1.Sym
......@@ -1295,15 +1295,15 @@ func addmethod(msym *Sym, t *Type, tpkg *Pkg, local, nointerface bool) {
}
// get parent type sym
pa := t.Recv() // ptr to this structure
if pa == nil {
rf := t.Recv() // ptr to this structure
if rf == nil {
Yyerror("missing receiver")
return
}
pa = pa.Type // base type
f := methtype(pa, 1)
if f == nil {
pa := rf.Type // base type
mt := methtype(pa, 1)
if mt == nil {
t = pa
if t == nil { // rely on typecheck having complained before
return
......@@ -1344,7 +1344,7 @@ func addmethod(msym *Sym, t *Type, tpkg *Pkg, local, nointerface bool) {
return
}
pa = f
pa = mt
if local && !pa.Local {
Yyerror("cannot define new methods on non-local type %v", pa)
return
......@@ -1366,12 +1366,9 @@ func addmethod(msym *Sym, t *Type, tpkg *Pkg, local, nointerface bool) {
n := Nod(ODCLFIELD, newname(msym), nil)
n.Type = t
var d *Type // last found
var d *Field // last found
for f, it := IterMethods(pa); f != nil; f = it.Next() {
d = f
if f.Etype != TFIELD {
Fatalf("addmethod: not TFIELD: %v", Tconv(f, obj.FmtLong))
}
if msym.Name != f.Sym.Name {
continue
}
......@@ -1381,7 +1378,7 @@ func addmethod(msym *Sym, t *Type, tpkg *Pkg, local, nointerface bool) {
return
}
f = structfield(n)
f := structfield(n)
f.Nointerface = nointerface
// during import unexported method names should be in the type's package
......
......@@ -273,7 +273,7 @@ func dumpexportvar(s *Sym) {
}
// methodbyname sorts types by symbol name.
type methodbyname []*Type
type methodbyname []*Field
func (x methodbyname) Len() int { return len(x) }
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 {
return
}
if t.Etype == TFIELD {
Fatalf("unexpected TFIELD in dumpexporttype")
}
if t.Printed || t == Types[t.Etype] || t == bytetype || t == runetype || t == errortype {
return
}
......@@ -315,7 +312,7 @@ func dumpexporttype(t *Type) {
return
}
var m []*Type
var m []*Field
for f, it := IterMethods(t); f != nil; f = it.Next() {
dumpexporttype(f.Type)
m = append(m, f)
......@@ -334,10 +331,10 @@ func dumpexporttype(t *Type) {
if Debug['l'] < 2 {
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)
} 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))
}
}
}
......
......@@ -401,7 +401,6 @@ var etnames = []string{
TMAP: "MAP",
TINTER: "INTER",
TFORW: "FORW",
TFIELD: "FIELD",
TSTRING: "STRING",
TUNSAFEPTR: "TUNSAFEPTR",
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.
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 {
case FTypeId:
if flag&obj.FmtShort != 0 {
......@@ -664,14 +663,14 @@ func typefmt(t *Type, flag int) string {
buf.WriteString("(")
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(Tconv(t1, obj.FmtShort))
buf.WriteString(Fldconv(t1, obj.FmtShort))
if t1.Down != nil {
buf.WriteString(", ")
}
}
} else {
for t1, it := IterFields(t); t1 != nil; t1 = it.Next() {
buf.WriteString(Tconv(t1, 0))
buf.WriteString(Fldconv(t1, 0))
if t1.Down != nil {
buf.WriteString(", ")
}
......@@ -682,7 +681,7 @@ func typefmt(t *Type, flag int) string {
buf.WriteString("struct {")
for t1, it := IterFields(t); t1 != nil; t1 = it.Next() {
buf.WriteString(" ")
buf.WriteString(Tconv(t1, obj.FmtLong))
buf.WriteString(Fldconv(t1, obj.FmtLong))
if t1.Down != nil {
buf.WriteString(";")
}
......@@ -694,72 +693,6 @@ func typefmt(t *Type, flag int) 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:
if t.Sym != nil {
return fmt.Sprintf("undefined %v", t.Sym)
......@@ -1627,6 +1560,95 @@ func (t *Type) String() string {
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.
// Flags: 'l' print definition, not name
// 'h' omit 'func' and receiver from function types, short type names
......
......@@ -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() {
if field.Etype != TFIELD {
Fatalf("bad struct")
}
if !visitComponents(field.Type, startOffset+field.Width, f) {
return false
}
......
......@@ -531,11 +531,15 @@ func newplist() *obj.Plist {
// incorrectly) passed a 1; the behavior is exactly
// the same as it is for 1, except that PARAMOUT is
// generated instead of PARAM.
func nodarg(t *Type, fp int) *Node {
func nodarg(t interface{}, fp int) *Node {
var n *Node
// entire argument struct, not just one arg
if t.Etype == TSTRUCT && t.Funarg {
switch t := t.(type) {
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.Sym = Lookup(".args")
n.Type = t
......@@ -548,36 +552,31 @@ func nodarg(t *Type, fp int) *Node {
}
n.Xoffset = first.Width
n.Addable = true
goto fp
}
if t.Etype != TFIELD {
Fatalf("nodarg: not field %v", t)
}
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
case *Field:
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.Type = t.Type
n.Sym = t.Sym
if t.Width == BADWIDTH {
Fatalf("nodarg: offset not computed for %v", t)
n = Nod(ONAME, nil, nil)
n.Type = t.Type
n.Sym = t.Sym
if t.Width == BADWIDTH {
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 __,
// or else the assignment to _ will be
// discarded during code generation.
fp:
if isblank(n) {
n.Sym = Lookup("__")
}
......
......@@ -497,7 +497,7 @@ func mkinlcall(np **Node, fn *Node, isddd bool) {
safemode = save_safemode
}
func tinlvar(t *Type) *Node {
func tinlvar(t *Field) *Node {
if t.Nname != nil && !isblank(t.Nname) {
if t.Nname.Name.Inlvar == nil {
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.
func retvar(t *Type, i int) *Node {
func retvar(t *Field, i int) *Node {
n := newname(Lookupf("~r%d", i))
n.Type = t.Type
n.Class = PAUTO
......
......@@ -62,8 +62,8 @@ func uncommonSize(t *Type) int { // Sizeof(runtime.uncommontype{})
return 2*Widthptr + 2*Widthint
}
func makefield(name string, t *Type) *Type {
f := typ(TFIELD)
func makefield(name string, t *Type) *Field {
f := newField()
f.Type = t
f.Sym = nopkg.Lookup(name)
return f
......@@ -91,7 +91,7 @@ func mapbucket(t *Type) *Type {
arr.Type = Types[TUINT8]
arr.Bound = BUCKETSIZE
field := make([]*Type, 0, 5)
field := make([]*Field, 0, 5)
field = append(field, makefield("topbits", arr))
arr = typ(TARRAY)
arr.Type = keytype
......@@ -162,7 +162,7 @@ func hmap(t *Type) *Type {
}
bucket := mapbucket(t)
var field [8]*Type
var field [8]*Field
field[0] = makefield("count", Types[TINT])
field[1] = makefield("flags", Types[TUINT8])
field[2] = makefield("B", Types[TUINT8])
......@@ -203,7 +203,7 @@ func hiter(t *Type) *Type {
// checkBucket uintptr
// }
// must match ../../../../runtime/hashmap.go:hiter.
var field [12]*Type
var field [12]*Field
field[0] = makefield("key", Ptrto(t.Key()))
field[1] = makefield("val", Ptrto(t.Type))
field[2] = makefield("t", Ptrto(Types[TUINT8]))
......@@ -286,9 +286,6 @@ func methods(t *Type) []*Sig {
// generating code if necessary.
var ms []*Sig
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 {
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 {
var methods []*Sig
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 {
continue
}
......@@ -623,9 +617,6 @@ func haspointers(t *Type) bool {
fallthrough
default:
ret = true
case TFIELD:
Fatalf("haspointers: unexpected type, %v", t)
}
t.Haspointers = 1 + uint8(obj.Bool2int(ret))
......@@ -667,7 +658,7 @@ func typeptrdata(t *Type) int64 {
case TSTRUCT:
// Find the last field that has pointers.
var lastPtrField *Type
var lastPtrField *Field
for t1, it := IterFields(t); t1 != nil; t1 = it.Next() {
if haspointers(t1.Type) {
lastPtrField = t1
......@@ -800,7 +791,7 @@ func typesym(t *Type) *Sym {
// tracksym returns the symbol for tracking use of field/method f, assumed
// 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)
}
......
......@@ -869,11 +869,11 @@ func maplit(ctxt int, n *Node, var_ *Node, init *Nodes) {
syma := Lookup("a")
symb := Lookup("b")
var fields [2]*Type
fields[0] = typ(TFIELD)
var fields [2]*Field
fields[0] = newField()
fields[0].Type = tk
fields[0].Sym = syma
fields[1] = typ(TFIELD)
fields[1] = newField()
fields[1].Type = tv
fields[1].Sym = symb
......
......@@ -27,7 +27,7 @@ func TestSizeof(t *testing.T) {
{Name{}, 52, 80},
{Node{}, 92, 144},
{Sym{}, 60, 112},
{Type{}, 140, 232},
{Type{}, 132, 224},
}
for _, tt := range tests {
......
......@@ -3943,9 +3943,6 @@ func fieldIdx(n *Node) int64 {
var i int64
for t1, it := IterFields(t); t1 != nil; t1 = it.Next() {
if t1.Etype != TFIELD {
panic("non-TFIELD in TSTRUCT")
}
if t1.Sym != f.Sym {
i++
continue
......
......@@ -388,7 +388,7 @@ func maptype(key *Type, val *Type) *Type {
}
// 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) 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
}
t1, i1 := IterFields(t1)
t2, i2 := IterFields(t2)
f1, i1 := IterFields(t1)
f2, i2 := IterFields(t2)
for {
if !Eqtype(t1, t2) {
if !Eqtype(f1.Type, f2.Type) {
return false
}
if t1 == nil {
if f1 == nil {
return true
}
t1 = i1.Next()
t2 = i2.Next()
f1 = i1.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.
if dst.Etype == TINTER && src.Etype != TNIL {
var missing *Type
var missing, have *Field
var ptr int
var have *Type
if implements(src, dst, &missing, &have, &ptr) {
return OCONVIFACE
}
......@@ -861,9 +860,8 @@ func assignop(src *Type, dst *Type, why *string) Op {
}
if src.Etype == TINTER && dst.Etype != TBLANK {
var have *Type
var missing, have *Field
var ptr int
var missing *Type
if why != nil && implements(dst, src, &missing, &have, &ptr) {
*why = ": need type assertion"
}
......@@ -1096,7 +1094,7 @@ func substAny(t *Type, types *[]*Type) *Type {
t = (*types)[0]
*types = (*types)[1:]
case TPTR32, TPTR64, TCHAN, TARRAY, TFIELD:
case TPTR32, TPTR64, TCHAN, TARRAY:
elem := substAny(t.Type, types)
if elem != t.Type {
t = t.Copy()
......@@ -1133,24 +1131,35 @@ func substAny(t *Type, types *[]*Type) *Type {
case TSTRUCT:
// nfs only has to be big enough for the builtin functions.
var nfs [8]*Type
var nfs [8]*Field
fields := t.FieldSlice()
changed := false
for i, f := range fields {
nf := substAny(f, types)
if nf != f {
if !changed {
for j := 0; j < i; j++ {
nfs[j] = fields[j].Copy()
}
}
nft := substAny(f.Type, types)
if nft != f.Type {
nfs[i] = f.Copy()
nfs[i].Type = nft
changed = true
} else if changed {
nf = f.Copy()
}
nfs[i] = nf
}
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.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 TSTRUCT or TINTER Type.
type Dlist struct {
field *Type
field *Field
}
// 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
// with Type t. If exactly one exists, it will be returned in *save
// (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
if Isptr[u.Etype] {
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
// embedded fields at depth d, so callers can decide whether to retry at
// 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 {
return
}
......@@ -1644,7 +1653,7 @@ out:
// 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 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
// types: structs parent the types they embed, and types parent their
// 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
// the actual methods.
type Symlink struct {
field *Type
field *Field
link *Symlink
good bool
followptr bool
......@@ -1803,7 +1812,6 @@ func expandmeth(t *Type) {
// mark top-level method symbols
// so that expand1 doesn't consider them.
var f *Type
for f, it := IterMethods(t); f != nil; f = it.Next() {
f.Sym.Flags |= SymUniq
}
......@@ -1816,6 +1824,7 @@ func expandmeth(t *Type) {
// check each method to be uniquely reachable
for sl := slist; sl != nil; sl = sl.link {
sl.field.Sym.Flags &^= SymUniq
var f *Field
if path, _ := dotpath(sl.field.Sym, t, &f, false); path == nil {
continue
}
......@@ -1894,7 +1903,7 @@ func structargs(tl *Type, mustname bool) []*Node {
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 {
fmt.Printf("genwrapper rcvrtype=%v method=%v newnam=%v\n", rcvr, method, newnam)
}
......@@ -2045,14 +2054,14 @@ func hashmem(t *Type) *Node {
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
if t == nil {
return nil
}
var m *Type
var m *Field
path, ambig := dotpath(s, t, &m, ignorecase)
if path == nil {
if ambig {
......@@ -2076,7 +2085,7 @@ func ifacelookdot(s *Sym, t *Type, followptr *bool, ignorecase bool) *Type {
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
if t == nil {
return false
......@@ -2114,16 +2123,13 @@ func implements(t *Type, iface *Type, m **Type, samename **Type, ptr *int) bool
if t != nil {
expandmeth(t)
}
var tm *Type
var imtype *Type
var followptr bool
var rcvr *Type
for im, it := IterFields(iface); im != nil; im = it.Next() {
if im.Broke {
continue
}
imtype = methodfunc(im.Type, nil)
tm = ifacelookdot(im.Sym, t, &followptr, false)
imtype := methodfunc(im.Type, nil)
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 = 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,
// 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 false && Debug['r'] != 0 {
......
......@@ -146,7 +146,7 @@ func typecheckswitch(n *Node) {
// type switch
case Etype:
var missing, have *Type
var missing, have *Field
var ptr int
switch {
case n1.Op == OLITERAL && Istype(n1.Type, TNIL):
......
......@@ -146,7 +146,7 @@ type Param struct {
Stackparam *Node // OPARAM node referring to stack copy of param
// ONAME PPARAM
Field *Type // TFIELD in arg struct
Field *Field // TFIELD in arg struct
// ONAME closure param with PPARAMREF
Outer *Node // outer PPARAMREF in nested closure
......
......@@ -51,7 +51,6 @@ const (
TMAP
TINTER
TFORW
TFIELD
TANY
TSTRING
TUNSAFEPTR
......@@ -103,17 +102,14 @@ var (
// A Type represents a Go type.
type Type struct {
Etype EType
Nointerface bool
Noalg bool
Chan uint8
Trecur uint8 // to detect loops
Printed bool
Embedded uint8 // TFIELD embedded type
Funarg bool // on TSTRUCT and TFIELD
Local bool // created in this file
Funarg bool // on TSTRUCT and TFIELD
Local bool // created in this file
Deferwidth bool
Broke bool // broken type definition.
Isddd bool // TFIELD is ... argument
Align uint8
Haspointers uint8 // 0 unknown, 1 no, 2 yes
......@@ -127,8 +123,8 @@ type Type struct {
Intuple int
Outnamed bool
Method *Type
Xmethod *Type
Method *Field
Xmethod *Field
Sym *Sym
Vargen int32 // unique name for OTYPE/ONAME
......@@ -137,15 +133,13 @@ type Type struct {
Argwid int64
// most nodes
Type *Type // actual type for TFIELD, element type for TARRAY, TCHAN, TMAP, TPTRxx
Width int64 // offset in TFIELD, width in all others
Type *Type // element type for TARRAY, TCHAN, TMAP, TPTRxx
Width int64
// TSTRUCT
Fields *Type // first struct field
Fields *Field // first struct field
// TFIELD
Down *Type // next struct field, also key type in TMAP
Note *string // literal string annotation
Down *Type // key type in TMAP; next struct in Funarg TSTRUCT
// TARRAY
Bound int64 // negative is slice
......@@ -163,6 +157,24 @@ type Type struct {
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.
func typ(et EType) *Type {
t := &Type{
......@@ -174,6 +186,12 @@ func typ(et EType) *Type {
return t
}
func newField() *Field {
return &Field{
Width: BADWIDTH,
}
}
// Copy returns a shallow copy of the Type.
func (t *Type) Copy() *Type {
if t == nil {
......@@ -187,15 +205,20 @@ func (t *Type) Copy() *Type {
return &nt
}
func (f *Field) Copy() *Field {
nf := *f
return &nf
}
// Iter provides an abstraction for iterating across struct fields and
// interface methods.
type Iter struct {
x *Type
x *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) (*Type, Iter) {
func IterFields(t *Type) (*Field, Iter) {
if t.Etype != TSTRUCT && t.Etype != TINTER {
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
// and an Iter value to continue iterating across the rest.
// IterMethods does not include promoted methods.
func IterMethods(t *Type) (*Type, Iter) {
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) (*Type, Iter) {
func IterAllMethods(t *Type) (*Field, Iter) {
// TODO(mdempsky): Validate t?
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
// its successor fields. Most code should instead use one of the IterXXX
// functions above.
func RawIter(t *Type) (*Type, Iter) {
func RawIter(t *Field) (*Field, Iter) {
i := Iter{x: t}
f := i.Next()
return f, i
}
// Next returns the next field or method, if any.
func (i *Iter) Next() *Type {
func (i *Iter) Next() *Field {
if i.x == nil {
return nil
}
t := i.x
if t.Etype != TFIELD {
Fatalf("Iter.Next: type %v is not a field", t)
}
i.x = t.Down
return t
f := i.x
i.x = f.Down
return f
}
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) 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
// 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.
func (t *Type) Field(i int) *Type {
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() {
......@@ -301,8 +321,8 @@ func (t *Type) Field(i int) *Type {
// FieldSlice returns a slice of containing all fields/methods of
// struct/interface type t.
func (t *Type) FieldSlice() []*Type {
var s []*Type
func (t *Type) FieldSlice() []*Field {
var s []*Field
for f, it := IterFields(t); f != nil; f = it.Next() {
s = append(s, f)
}
......@@ -310,11 +330,11 @@ func (t *Type) FieldSlice() []*Type {
}
// 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 {
Fatalf("SetFields: type %v does not have fields", t)
}
var next *Type
var next *Field
for i := len(fields) - 1; i >= 0; i-- {
fields[i].Down = next
next = fields[i]
......@@ -456,12 +476,14 @@ func (t *Type) cmp(x *Type) ssa.Cmp {
}
switch t.Etype {
case TMAP, TFIELD:
// No special cases for these two, they are handled
// by the general code after the switch.
case TMAP:
if c := t.Down.cmp(x.Down); c != ssa.CMPeq {
return c
}
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:
if t.Map == nil {
......@@ -545,9 +567,7 @@ func (t *Type) cmp(x *Type) ssa.Cmp {
panic(e)
}
if c := t.Down.cmp(x.Down); c != ssa.CMPeq {
return c
}
// Common element type comparison for TARRAY, TCHAN, TMAP, TPTR32, and TPTR64.
return t.Type.cmp(x.Type)
}
......
......@@ -946,8 +946,7 @@ OpSwitch:
}
if n.Type != nil && n.Type.Etype != TINTER {
var have *Type
var missing *Type
var missing, have *Field
var ptr int
if !implements(n.Type, t, &missing, &have, &ptr) {
if have != nil && have.Sym == missing.Sym {
......@@ -2363,8 +2362,8 @@ func twoarg(n *Node) bool {
return true
}
func lookdot1(errnode *Node, s *Sym, t *Type, f *Type, dostrcmp int) *Type {
var r *Type
func lookdot1(errnode *Node, s *Sym, t *Type, f *Field, dostrcmp int) *Field {
var r *Field
for f, it := RawIter(f); f != nil; f = it.Next() {
if dostrcmp != 0 && f.Sym.Name == s.Name {
return f
......@@ -2410,14 +2409,13 @@ func looktypedot(n *Node, t *Type, dostrcmp int) bool {
// Find the base type: methtype will fail if t
// is not of the form T or *T.
f2 := methtype(t, 0)
if f2 == nil {
mt := methtype(t, 0)
if mt == nil {
return false
}
expandmeth(f2)
f2 = lookdot1(n, s, f2, f2.Xmethod, dostrcmp)
expandmeth(mt)
f2 := lookdot1(n, s, mt, mt.Xmethod, dostrcmp)
if f2 == nil {
return false
}
......@@ -2449,24 +2447,24 @@ type typeSym struct {
// 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.
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
dowidth(t)
var f1 *Type
var f1 *Field
if t.Etype == TSTRUCT || t.Etype == TINTER {
f1 = lookdot1(n, s, t, t.Fields, dostrcmp)
}
var f2 *Type
var f2 *Field
if n.Left.Type == t || n.Left.Type.Sym == nil {
f2 = methtype(t, 0)
if f2 != nil {
mt := methtype(t, 0)
if mt != nil {
// Use f2->method, not f2->xmethod: adddot has
// already inserted all the necessary embedded dots.
f2 = lookdot1(n, s, f2, f2.Method, dostrcmp)
f2 = lookdot1(n, s, mt, mt.Method, dostrcmp)
}
}
......
......@@ -370,18 +370,18 @@ func lexinit1() {
rcvr := typ(TSTRUCT)
rcvr.Funarg = true
field := typ(TFIELD)
field := newField()
field.Type = Ptrto(typ(TSTRUCT))
rcvr.SetFields([]*Type{field})
rcvr.SetFields([]*Field{field})
in := typ(TSTRUCT)
in.Funarg = true
out := typ(TSTRUCT)
out.Funarg = true
field = typ(TFIELD)
field = newField()
field.Type = Types[TSTRING]
out.SetFields([]*Type{field})
out.SetFields([]*Field{field})
f := typ(TFUNC)
*f.RecvsP() = rcvr
......@@ -393,10 +393,10 @@ func lexinit1() {
f.Outtuple = 1
t := typ(TINTER)
field = typ(TFIELD)
field = newField()
field.Sym = Lookup("Error")
field.Type = f
t.SetFields([]*Type{field})
t.SetFields([]*Field{field})
// error type
s := Pkglookup("error", builtinpkg)
......
......@@ -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.
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)
if ddd != nil {
esc = ddd.Esc
......@@ -1792,7 +1792,7 @@ func dumptypes(nl *Type, what string) string {
if s != "" {
s += ", "
}
s += Tconv(l, 0)
s += Fldconv(l, 0)
}
if s == "" {
s = fmt.Sprintf("[no arguments %s]", what)
......@@ -3774,7 +3774,7 @@ func usemethod(n *Node) {
}
p0 := t.Params().Field(0)
res0 := t.Results().Field(0)
var res1 *Type
var res1 *Field
if countfield(t.Results()) == 2 {
res1 = t.Results().Field(1)
}
......@@ -3791,7 +3791,7 @@ func usemethod(n *Node) {
return
}
}
if Tconv(res0, 0) != "reflect.Method" {
if Tconv(res0.Type, 0) != "reflect.Method" {
return
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment