Commit 0cff5058 authored by Matthew Dempsky's avatar Matthew Dempsky

cmd/compile: add Recv0 and Field helper methods for Type

Accessing the n'th field of a struct is fairly common, and in
particular accessing the 0'th field of the receiver parameter list is
very common. Add helper methods for both of these tasks and update
code to make use of them.

Change-Id: I81f551fecdca306b3800636caebcd0dc106f2ed7
Reviewed-on: https://go-review.googlesource.com/20498
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: default avatarDave Cheney <dave@cheney.net>
parent d20b92e0
......@@ -1677,7 +1677,7 @@ func Igen(n *Node, a *Node, res *Node) {
cgen_callinter(n, nil, 0)
}
fp, _ := IterFields(n.Left.Type.Results())
fp := n.Left.Type.Results().Field(0)
*a = Node{}
a.Op = OINDREG
a.Reg = int16(Thearch.REGSP)
......@@ -2225,7 +2225,7 @@ func stkof(n *Node) int64 {
t = t.Type
}
t, _ = IterFields(t.Results())
t = t.Results().Field(0)
if t != nil {
return t.Width + Ctxt.FixedFrameSize()
}
......@@ -2561,7 +2561,7 @@ func cgen_callret(n *Node, res *Node) {
t = t.Type
}
fp, _ := IterFields(t.Results())
fp := t.Results().Field(0)
if fp == nil {
Fatalf("cgen_callret: nil")
}
......@@ -2585,7 +2585,7 @@ func cgen_aret(n *Node, res *Node) {
t = t.Type
}
fp, _ := IterFields(t.Results())
fp := t.Results().Field(0)
if fp == nil {
Fatalf("cgen_aret: nil")
}
......
......@@ -1134,7 +1134,7 @@ func fakethis() *Node {
// Those methods have an anonymous *struct{} as the receiver.
// (See fakethis above.)
func isifacemethod(f *Type) bool {
rcvr := f.Recv().Type
rcvr := f.Recv0()
if rcvr.Sym != nil {
return false
}
......@@ -1306,7 +1306,7 @@ func addmethod(sf *Sym, t *Type, local bool, nointerface bool) {
}
// get parent type sym
pa := t.Recv().Type // ptr to this structure
pa := t.Recv0() // ptr to this structure
if pa == nil {
Yyerror("missing receiver")
return
......
......@@ -1384,7 +1384,7 @@ func esccall(e *EscState, n *Node, up *Node) {
initEscretval(e, n, fntype)
// If there is a receiver, it also leaks to heap.
if n.Op != OCALLFUNC {
t := fntype.Recv().Type
t := fntype.Recv0()
src := n.Left.Left
if haspointers(t.Type) {
escassign(e, &e.theSink, src)
......@@ -1468,7 +1468,7 @@ func esccall(e *EscState, n *Node, up *Node) {
// Receiver.
if n.Op != OCALLFUNC {
t := fntype.Recv().Type
t := fntype.Recv0()
src := n.Left.Left
if haspointers(t.Type) {
escassignfromtag(e, t.Note, nE.Escretval, src)
......
......@@ -314,10 +314,10 @@ func dumpexporttype(t *Type) {
if Debug['l'] < 2 {
typecheckinl(f.Type.Nname)
}
exportf("\tfunc (%v) %v %v { %v }\n", Tconv(f.Type.Recv().Type, 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.Recv0(), 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().Type, 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.Recv0(), obj.FmtSharp), Sconv(f.Sym, obj.FmtShort|obj.FmtByte|obj.FmtSharp), Tconv(f.Type, obj.FmtShort|obj.FmtSharp))
}
}
}
......
......@@ -548,7 +548,7 @@ func nodarg(t *Type, fp int) *Node {
n = Nod(ONAME, nil, nil)
n.Sym = Lookup(".args")
n.Type = t
first, _ := IterFields(t)
first := t.Field(0)
if first == nil {
Fatalf("nodarg: bad struct")
}
......
......@@ -48,7 +48,7 @@ var inlretvars *NodeList // temp out variables
func fnpkg(fn *Node) *Pkg {
if fn.Type.Thistuple != 0 {
// method
rcvr := fn.Type.Recv().Type.Type
rcvr := fn.Type.Recv0().Type
if Isptr[rcvr.Etype] {
rcvr = rcvr.Type
......@@ -614,7 +614,7 @@ func mkinlcall1(np **Node, fn *Node, isddd bool) {
var as *Node
if fn.Type.Thistuple != 0 && n.Left.Op == ODOTMETH {
// method call with a receiver.
t := fn.Type.Recv().Type
t := fn.Type.Recv0()
if t != nil && t.Nname != nil && !isblank(t.Nname) && t.Nname.Name.Inlvar == nil {
Fatalf("missing inlvar for %v\n", t.Nname)
......@@ -683,7 +683,7 @@ func mkinlcall1(np **Node, fn *Node, isddd bool) {
}
// append receiver inlvar to LHS.
t := fn.Type.Recv().Type
t := fn.Type.Recv0()
if t != nil && t.Nname != nil && !isblank(t.Nname) && t.Nname.Name.Inlvar == nil {
Fatalf("missing inlvar for %v\n", t.Nname)
......
......@@ -306,7 +306,7 @@ func methods(t *Type) []*Sig {
if f.Type.Etype != TFUNC || f.Type.Thistuple == 0 {
Fatalf("non-method on %v method %v %v\n", mt, f.Sym, f)
}
if f.Type.Recv().Type == nil {
if f.Type.Recv0() == nil {
Fatalf("receiver with no type on %v method %v %v\n", mt, f.Sym, f)
}
if f.Nointerface {
......@@ -322,7 +322,7 @@ func methods(t *Type) []*Sig {
// if pointer receiver but non-pointer t and
// this is not an embedded pointer inside a struct,
// method does not apply.
this := f.Type.Recv().Type.Type
this := f.Type.Recv0().Type
if Isptr[this.Etype] && this.Type == t {
continue
......
......@@ -2405,7 +2405,7 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
// Start exit block, find address of result.
s.startBlock(bNext)
fp, _ := IterFields(n.Left.Type.Results())
fp := n.Left.Type.Results().Field(0)
if fp == nil || k != callNormal {
// call has no return value. Continue with the next statement.
return nil
......
......@@ -1959,7 +1959,7 @@ func genwrapper(rcvr *Type, method *Type, newnam *Sym, iface int) {
isddd = n.Left.Isddd
}
methodrcvr := method.Type.Recv().Type.Type
methodrcvr := method.Type.Recv0().Type
// generate nil pointer check for better error
if Isptr[rcvr.Etype] && rcvr.Type == methodrcvr {
......@@ -2148,7 +2148,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.Type
rcvr = tm.Type.Recv0().Type
if Isptr[rcvr.Etype] && !Isptr[t0.Etype] && !followptr && !isifacemethod(tm.Type) {
if false && Debug['r'] != 0 {
......
......@@ -243,6 +243,9 @@ func (t *Type) Recv() *Type { return *t.RecvP() }
func (t *Type) Params() *Type { return *t.ParamsP() }
func (t *Type) Results() *Type { return *t.ResultsP() }
// TODO(mdempsky): Rename Recv to Recvs, so Recv0 can become just Recv.
func (t *Type) Recv0() *Type { return t.Recv().Field(0) }
// recvParamsResults stores the accessor functions for a function Type's
// receiver, parameters, and result parameters, in that order.
// It can be used to iterate over all of a function's parameter lists.
......@@ -250,6 +253,26 @@ var recvParamsResults = [3]func(*Type) *Type{
(*Type).Recv, (*Type).Params, (*Type).Results,
}
// Field returns the i'th field/method of struct/interface type t.
func (t *Type) Field(i int) *Type {
// 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--
}
if i == 0 {
// To simplify automated rewrites of existing code, if the
// caller asks for the n'th member of an n-element type,
// return nil instead of panicking.
// TODO(mdempsky): Make callers responsible for bounds checking.
return nil
}
panic("not enough fields")
}
func (t *Type) Size() int64 {
dowidth(t)
return t.Width
......@@ -551,30 +574,10 @@ func (t *Type) NumFields() int64 {
return int64(countfield(t))
}
func (t *Type) FieldType(i int64) ssa.Type {
// TODO: store fields in a slice so we can
// look them up by index in constant time.
for t1 := t.Type; t1 != nil; t1 = t1.Down {
if t1.Etype != TFIELD {
panic("non-TFIELD in a TSTRUCT")
}
if i == 0 {
return t1.Type
}
i--
}
panic("not enough fields")
return t.Field(int(i)).Type
}
func (t *Type) FieldOff(i int64) int64 {
for t1 := t.Type; t1 != nil; t1 = t1.Down {
if t1.Etype != TFIELD {
panic("non-TFIELD in a TSTRUCT")
}
if i == 0 {
return t1.Width
}
i--
}
panic("not enough fields")
return t.Field(int(i)).Width
}
func (t *Type) NumElem() int64 {
......
......@@ -1311,7 +1311,7 @@ OpSwitch:
// information further down the call chain to know if we
// were testing a method receiver for unexported fields.
// It isn't necessary, so just do a sanity check.
tp := t.Recv().Type.Type
tp := t.Recv0().Type
if l.Left == nil || !Eqtype(l.Left.Type, tp) {
Fatalf("method receiver")
......@@ -2430,7 +2430,7 @@ func looktypedot(n *Node, t *Type, dostrcmp int) bool {
}
// disallow T.m if m requires *T receiver
if Isptr[f2.Type.Recv().Type.Type.Etype] && !Isptr[t.Etype] && f2.Embedded != 2 && !isifacemethod(f2.Type) {
if Isptr[f2.Type.Recv0().Type.Etype] && !Isptr[t.Etype] && f2.Embedded != 2 && !isifacemethod(f2.Type) {
Yyerror("invalid method expression %v (needs pointer receiver: (*%v).%v)", n, t, Sconv(f2.Sym, obj.FmtShort))
return false
}
......@@ -2513,7 +2513,7 @@ func lookdot(n *Node, t *Type, dostrcmp int) *Type {
}
tt := n.Left.Type
dowidth(tt)
rcvr := f2.Type.Recv().Type.Type
rcvr := f2.Type.Recv0().Type
if !Eqtype(rcvr, tt) {
if rcvr.Etype == Tptr && Eqtype(rcvr.Type, tt) {
checklvalue(n.Left, "call pointer method on")
......@@ -3436,7 +3436,7 @@ func typecheckfunc(n *Node) {
}
n.Type = t
t.Nname = n.Func.Nname
rcvr := t.Recv().Type
rcvr := t.Recv0()
if rcvr != nil && n.Func.Shortname != nil {
addmethod(n.Func.Shortname.Sym, t, true, n.Func.Nname.Nointerface)
}
......
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