Commit 5f525ca6 authored by Ian Lance Taylor's avatar Ian Lance Taylor

cmd/compile: change ODOT and friends to use Sym, not Right

The Node type ODOT and its variants all represent a selector, with a
simple name to the right of the dot.  Before this change this was
represented by using an ONAME Node in the Right field.  This ONAME node
served no useful purpose.  This CL changes these Node types to store the
symbol in the Sym field instead, thus not requiring allocating a Node
for each selector.

When compiling x/tools/go/types this CL eliminates nearly 5000 calls to
newname and reduces the total number of Nodes allocated by about 6.6%.
It seems to cut compilation time by 1 to 2 percent.

Getting this right was somewhat subtle, and I added two dubious changes
to produce the exact same output as before.  One is to ishairy in
inl.go: the ONAME node increased the cost of ODOT and friends by 1, and
I retained that, although really ODOT is not more expensive than any
other node.  The other is to varexpr in walk.go: because the ONAME in
the Right field of an ODOT has no class, varexpr would always return
false for an ODOT, although in fact for some ODOT's it seemingly ought
to return true; I added an && false for now.  I will send separate CLs,
that will break toolstash -cmp, to clean these up.

This CL passes toolstash -cmp.

Change-Id: I4af8a10cc59078c436130ce472f25abc3a9b2f80
Reviewed-on: https://go-review.googlesource.com/20890
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent fc6bcdee
......@@ -112,7 +112,7 @@ func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
// A special case to make write barriers more efficient.
// Comparing the first field of a named struct can be done directly.
base := n1
if n1.Op == gc.ODOT && n1.Left.Type.Etype == gc.TSTRUCT && n1.Left.Type.Field(0).Sym == n1.Right.Sym {
if n1.Op == gc.ODOT && n1.Left.Type.Etype == gc.TSTRUCT && n1.Left.Type.Field(0).Sym == n1.Sym {
base = n1.Left
}
......
......@@ -242,7 +242,7 @@ func genhash(sym *Sym, t *Type) {
if algtype1(f.Type, nil) != AMEM {
hashel := hashfor(f.Type)
call := Nod(OCALL, hashel, nil)
nx := Nod(OXDOT, np, newname(f.Sym)) // TODO: fields from other packages?
nx := NodSym(OXDOT, np, f.Sym) // TODO: fields from other packages?
na := Nod(OADDR, nx, nil)
na.Etype = 1 // no escape to heap
call.List.Append(na)
......@@ -258,7 +258,7 @@ func genhash(sym *Sym, t *Type) {
// h = hashel(&p.first, size, h)
hashel := hashmem(f.Type)
call := Nod(OCALL, hashel, nil)
nx := Nod(OXDOT, np, newname(f.Sym)) // TODO: fields from other packages?
nx := NodSym(OXDOT, np, f.Sym) // TODO: fields from other packages?
na := Nod(OADDR, nx, nil)
na.Etype = 1 // no escape to heap
call.List.Append(na)
......@@ -436,7 +436,7 @@ func geneq(sym *Sym, t *Type) {
// Compare non-memory fields with field equality.
if algtype1(f.Type, nil) != AMEM {
and(eqfield(np, nq, newname(f.Sym)))
and(eqfield(np, nq, f.Sym))
i++
continue
}
......@@ -449,11 +449,11 @@ func geneq(sym *Sym, t *Type) {
if s := fields[i:next]; len(s) <= 2 {
// Two or fewer fields: use plain field equality.
for _, f := range s {
and(eqfield(np, nq, newname(f.Sym)))
and(eqfield(np, nq, f.Sym))
}
} else {
// More than two fields: use memequal.
and(eqmem(np, nq, newname(f.Sym), size))
and(eqmem(np, nq, f.Sym, size))
}
i = next
}
......@@ -502,19 +502,19 @@ func geneq(sym *Sym, t *Type) {
// eqfield returns the node
// p.field == q.field
func eqfield(p *Node, q *Node, field *Node) *Node {
nx := Nod(OXDOT, p, field)
ny := Nod(OXDOT, q, field)
func eqfield(p *Node, q *Node, field *Sym) *Node {
nx := NodSym(OXDOT, p, field)
ny := NodSym(OXDOT, q, field)
ne := Nod(OEQ, nx, ny)
return ne
}
// eqmem returns the node
// memequal(&p.field, &q.field [, size])
func eqmem(p *Node, q *Node, field *Node, size int64) *Node {
nx := Nod(OADDR, Nod(OXDOT, p, field), nil)
func eqmem(p *Node, q *Node, field *Sym, size int64) *Node {
nx := Nod(OADDR, NodSym(OXDOT, p, field), nil)
nx.Etype = 1 // does not escape
ny := Nod(OADDR, Nod(OXDOT, q, field), nil)
ny := Nod(OADDR, NodSym(OXDOT, q, field), nil)
ny.Etype = 1 // does not escape
typecheck(&nx, Erv)
typecheck(&ny, Erv)
......
......@@ -890,7 +890,7 @@ func (p *exporter) node(n *Node) {
case ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT:
p.node(n.Left)
p.sym(n.Right.Sym)
p.sym(n.Sym)
case ODOTTYPE, ODOTTYPE2:
p.node(n.Left)
......
......@@ -658,7 +658,7 @@ func (p *importer) node() *Node {
obj.Used = true
return oldname(s)
}
return Nod(OXDOT, obj, newname(sel))
return NodSym(OXDOT, obj, sel)
case ODOTTYPE, ODOTTYPE2:
n.Left = p.node()
......
......@@ -802,7 +802,7 @@ func cgen_wbptr(n, res *Node) {
}
wbVar := syslook("writeBarrier")
wbEnabled := Nod(ODOT, wbVar, newname(wbVar.Type.Field(0).Sym))
wbEnabled := NodSym(ODOT, wbVar, wbVar.Type.Field(0).Sym)
wbEnabled = typecheck(&wbEnabled, Erv)
pbr := Thearch.Ginscmp(ONE, Types[TUINT8], wbEnabled, Nodintconst(0), -1)
Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, &dst)
......@@ -2440,11 +2440,6 @@ func cgen_callinter(n *Node, res *Node, proc int) {
Fatalf("cgen_callinter: not ODOTINTER %v", Oconv(i.Op, 0))
}
f := i.Right // field
if f.Op != ONAME {
Fatalf("cgen_callinter: not ONAME %v", Oconv(f.Op, 0))
}
i = i.Left // interface
if !i.Addable {
......
......@@ -462,7 +462,7 @@ func walkclosure(func_ *Node, init *Nodes) *Node {
return clos
}
func typecheckpartialcall(fn *Node, sym *Node) {
func typecheckpartialcall(fn *Node, sym *Sym) {
switch fn.Op {
case ODOTINTER, ODOTMETH:
break
......@@ -474,21 +474,21 @@ func typecheckpartialcall(fn *Node, sym *Node) {
// Create top-level function.
xfunc := makepartialcall(fn, fn.Type, sym)
fn.Func = xfunc.Func
fn.Right = sym
fn.Right = newname(sym)
fn.Op = OCALLPART
fn.Type = xfunc.Type
}
var makepartialcall_gopkg *Pkg
func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node {
func makepartialcall(fn *Node, t0 *Type, meth *Sym) *Node {
var p string
rcvrtype := fn.Left.Type
if exportname(meth.Sym.Name) {
p = fmt.Sprintf("(%v).%s-fm", Tconv(rcvrtype, FmtLeft|FmtShort), meth.Sym.Name)
if exportname(meth.Name) {
p = fmt.Sprintf("(%v).%s-fm", Tconv(rcvrtype, FmtLeft|FmtShort), meth.Name)
} else {
p = fmt.Sprintf("(%v).(%v)-fm", Tconv(rcvrtype, FmtLeft|FmtShort), Sconv(meth.Sym, FmtLeft))
p = fmt.Sprintf("(%v).(%v)-fm", Tconv(rcvrtype, FmtLeft|FmtShort), Sconv(meth, FmtLeft))
}
basetype := rcvrtype
if Isptr[rcvrtype.Etype] {
......@@ -592,7 +592,7 @@ func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node {
body = append(body, Nod(OAS, ptr, Nod(OADDR, cv, nil)))
}
call := Nod(OCALL, Nod(OXDOT, ptr, meth), nil)
call := Nod(OCALL, NodSym(OXDOT, ptr, meth), nil)
call.List.Set(callargs)
call.Isddd = ddd
if t0.Results().NumFields() == 0 {
......
......@@ -1432,7 +1432,7 @@ func (c *nowritebarrierrecChecker) visitcode(n *Node) {
func (c *nowritebarrierrecChecker) visitcall(n *Node) {
fn := n.Left
if n.Op == OCALLMETH {
fn = n.Left.Right.Sym.Def
fn = n.Left.Sym.Def
}
if fn == nil || fn.Op != ONAME || fn.Class != PFUNC || fn.Name.Defn == nil {
return
......
......@@ -131,7 +131,7 @@ func (v *bottomUpVisitor) visitcode(n *Node, min uint32) uint32 {
if n.Op == OCALLFUNC || n.Op == OCALLMETH {
fn := n.Left
if n.Op == OCALLMETH {
fn = n.Left.Right.Sym.Def
fn = n.Left.Sym.Def
}
if fn != nil && fn.Op == ONAME && fn.Class == PFUNC && fn.Name.Defn != nil {
m := v.visit(fn.Name.Defn)
......@@ -1421,7 +1421,7 @@ func esccall(e *EscState, n *Node, up *Node) {
indirect = fn.Op != ONAME || fn.Class != PFUNC
case OCALLMETH:
fn = n.Left.Right.Sym.Def
fn = n.Left.Sym.Def
if fn != nil {
fntype = fn.Type
} else {
......
......@@ -1249,12 +1249,7 @@ func exprfmt(n *Node, prec int) string {
}
return ":"
case OXDOT,
ODOT,
ODOTPTR,
ODOTINTER,
ODOTMETH,
OCALLPART:
case OCALLPART:
var f string
f += exprfmt(n.Left, nprec)
if n.Right == nil || n.Right.Sym == nil {
......@@ -1264,6 +1259,16 @@ func exprfmt(n *Node, prec int) string {
f += fmt.Sprintf(".%v", Sconv(n.Right.Sym, FmtShort|FmtByte))
return f
case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
var f string
f += exprfmt(n.Left, nprec)
if n.Sym == nil {
f += ".<nil>"
return f
}
f += fmt.Sprintf(".%v", Sconv(n.Sym, FmtShort|FmtByte))
return f
case ODOTTYPE, ODOTTYPE2:
var f string
f += exprfmt(n.Left, nprec)
......
......@@ -948,7 +948,7 @@ func cgen_callmeth(n *Node, proc int) {
n2 := *n
n2.Op = OCALLFUNC
n2.Left = l.Right
n2.Left = newname(l.Sym)
n2.Left.Type = l.Type
if n2.Left.Op == ONAME {
......
......@@ -416,7 +416,7 @@ func Naddr(a *obj.Addr, n *Node) {
// A special case to make write barriers more efficient.
// Taking the address of the first field of a named struct
// is the same as taking the address of the struct.
if n.Left.Type.Etype != TSTRUCT || n.Left.Type.Field(0).Sym != n.Right.Sym {
if n.Left.Type.Etype != TSTRUCT || n.Left.Type.Field(0).Sym != n.Sym {
Debug['h'] = 1
Dump("naddr", n)
Fatalf("naddr: bad %v %v", Oconv(n.Op, 0), Ctxt.Dconv(a))
......
......@@ -220,6 +220,13 @@ func ishairy(n *Node, budget *int) bool {
ODCLTYPE, // can't print yet
ORETJMP:
return true
case ODOT, ODOTPTR, ODOTMETH, ODOTINTER:
// These used to store the symbol name as an ONAME in
// the Right field, meaning that it cost one budget
// unit. Stay compatible for now.
// TODO(iant): Remove this.
(*budget)--
}
(*budget)--
......
......@@ -1793,7 +1793,7 @@ func (p *parser) new_dotname(obj *Node) *Node {
obj.Used = true
return oldname(s)
}
return Nod(OXDOT, obj, newname(sel))
return NodSym(OXDOT, obj, sel)
}
func (p *parser) dotname() *Node {
......
......@@ -226,27 +226,27 @@ func walkrange(n *Node) {
hit := prealloc[n]
hit.Type = th
n.Left = nil
keyname := newname(th.Field(0).Sym) // depends on layout of iterator struct. See reflect.go:hiter
valname := newname(th.Field(1).Sym) // ditto
keysym := th.Field(0).Sym // depends on layout of iterator struct. See reflect.go:hiter
valsym := th.Field(1).Sym // ditto
fn := syslook("mapiterinit")
substArgTypes(&fn, t.Key(), t.Type, th)
init = append(init, mkcall1(fn, nil, nil, typename(t), ha, Nod(OADDR, hit, nil)))
n.Left = Nod(ONE, Nod(ODOT, hit, keyname), nodnil())
n.Left = Nod(ONE, NodSym(ODOT, hit, keysym), nodnil())
fn = syslook("mapiternext")
substArgTypes(&fn, th)
n.Right = mkcall1(fn, nil, nil, Nod(OADDR, hit, nil))
key := Nod(ODOT, hit, keyname)
key := NodSym(ODOT, hit, keysym)
key = Nod(OIND, key, nil)
if v1 == nil {
body = nil
} else if v2 == nil {
body = []*Node{Nod(OAS, v1, key)}
} else {
val := Nod(ODOT, hit, valname)
val := NodSym(ODOT, hit, valsym)
val = Nod(OIND, val, nil)
a := Nod(OAS2, nil, nil)
a.List.Set([]*Node{v1, v2})
......
......@@ -574,10 +574,10 @@ func structlit(ctxt int, pass int, n *Node, var_ *Node, init *Nodes) {
case OARRAYLIT:
if value.Type.Bound < 0 {
if pass == 1 && ctxt != 0 {
a = Nod(ODOT, var_, newname(index.Sym))
a = NodSym(ODOT, var_, index.Sym)
slicelit(ctxt, value, a, init)
} else if pass == 2 && ctxt == 0 {
a = Nod(ODOT, var_, newname(index.Sym))
a = NodSym(ODOT, var_, index.Sym)
slicelit(ctxt, value, a, init)
} else if pass == 3 {
break
......@@ -585,12 +585,12 @@ func structlit(ctxt int, pass int, n *Node, var_ *Node, init *Nodes) {
continue
}
a = Nod(ODOT, var_, newname(index.Sym))
a = NodSym(ODOT, var_, index.Sym)
arraylit(ctxt, pass, value, a, init)
continue
case OSTRUCTLIT:
a = Nod(ODOT, var_, newname(index.Sym))
a = NodSym(ODOT, var_, index.Sym)
structlit(ctxt, pass, value, a, init)
continue
}
......@@ -605,7 +605,7 @@ func structlit(ctxt int, pass int, n *Node, var_ *Node, init *Nodes) {
// build list of var.field = expr
setlineno(value)
a = Nod(ODOT, var_, newname(index.Sym))
a = NodSym(ODOT, var_, index.Sym)
a = Nod(OAS, a, value)
typecheck(&a, Etop)
......@@ -904,7 +904,7 @@ func maplit(ctxt int, n *Node, var_ *Node, init *Nodes) {
a = Nodintconst(b)
a = Nod(OINDEX, vstat, a)
a = Nod(ODOT, a, newname(syma))
a = NodSym(ODOT, a, syma)
a = Nod(OAS, a, index)
typecheck(&a, Etop)
walkexpr(&a, init)
......@@ -916,7 +916,7 @@ func maplit(ctxt int, n *Node, var_ *Node, init *Nodes) {
a = Nodintconst(b)
a = Nod(OINDEX, vstat, a)
a = Nod(ODOT, a, newname(symb))
a = NodSym(ODOT, a, symb)
a = Nod(OAS, a, value)
typecheck(&a, Etop)
walkexpr(&a, init)
......@@ -935,11 +935,11 @@ func maplit(ctxt int, n *Node, var_ *Node, init *Nodes) {
a = Nod(OINDEX, vstat, index)
a.Bounded = true
a = Nod(ODOT, a, newname(symb))
a = NodSym(ODOT, a, symb)
r := Nod(OINDEX, vstat, index)
r.Bounded = true
r = Nod(ODOT, r, newname(syma))
r = NodSym(ODOT, r, syma)
r = Nod(OINDEX, var_, r)
r = Nod(OAS, r, a)
......
......@@ -2326,16 +2326,14 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
if fn.Op != ODOTMETH {
Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
}
if fn.Right.Op != ONAME {
Fatalf("OCALLMETH: n.Left.Right not a ONAME: %v", fn.Right)
}
if k == callNormal {
sym = fn.Right.Sym
sym = fn.Sym
break
}
n2 := *fn.Right
n2 := newname(fn.Sym)
n2.Class = PFUNC
closure = s.expr(&n2)
n2.Lineno = fn.Lineno
closure = s.expr(n2)
// Note: receiver is already assigned in n.List, so we don't
// want to set it here.
case OCALLINTER:
......@@ -3967,14 +3965,14 @@ func AutoVar(v *ssa.Value) (*Node, int64) {
// fieldIdx finds the index of the field referred to by the ODOT node n.
func fieldIdx(n *Node) int {
t := n.Left.Type
f := n.Right
f := n.Sym
if t.Etype != TSTRUCT {
panic("ODOT's LHS is not a struct")
}
var i int
for _, t1 := range t.Fields().Slice() {
if t1.Sym != f.Sym {
if t1.Sym != f {
i++
continue
}
......
......@@ -339,6 +339,14 @@ func Nod(op Op, nleft *Node, nright *Node) *Node {
return n
}
// NodSym makes a Node with Op op and with the Left field set to left
// and the Sym field set to sym. This is for ODOT and friends.
func NodSym(op Op, left *Node, sym *Sym) *Node {
n := Nod(op, left, nil)
n.Sym = sym
return n
}
func saveorignode(n *Node) {
if n.Orig != nil {
return
......@@ -1677,10 +1685,7 @@ func adddot(n *Node) *Node {
return n
}
if n.Right.Op != ONAME {
return n
}
s := n.Right.Sym
s := n.Sym
if s == nil {
return n
}
......@@ -1689,7 +1694,7 @@ func adddot(n *Node) *Node {
case path != nil:
// rebuild elided dots
for c := len(path) - 1; c >= 0; c-- {
n.Left = Nod(ODOT, n.Left, newname(path[c].field.Sym))
n.Left = NodSym(ODOT, n.Left, path[c].field.Sym)
n.Left.Implicit = true
}
case ambig:
......@@ -1960,7 +1965,7 @@ func genwrapper(rcvr *Type, method *Field, newnam *Sym, iface int) {
fn.Nbody.Append(n)
}
dot := adddot(Nod(OXDOT, this.Left, newname(method.Sym)))
dot := adddot(NodSym(OXDOT, this.Left, method.Sym))
// generate call
if !instrumenting && Isptr[rcvr.Etype] && Isptr[methodrcvr.Etype] && method.Embedded != 0 && !isifacemethod(method.Type) {
......
......@@ -595,14 +595,14 @@ func (s *typeSwitch) walk(sw *Node) {
if !isnilinter(cond.Right.Type) {
// Load type from itab.
typ = Nod(ODOTPTR, typ, nil)
typ = NodSym(ODOTPTR, typ, nil)
typ.Type = Ptrto(Types[TUINT8])
typ.Typecheck = 1
typ.Xoffset = int64(Widthptr) // offset of _type in runtime.itab
typ.Bounded = true // guaranteed not to fault
}
// Load hash from type.
h := Nod(ODOTPTR, typ, nil)
h := NodSym(ODOTPTR, typ, nil)
h.Type = Types[TUINT32]
h.Typecheck = 1
h.Xoffset = int64(2 * Widthptr) // offset of hash in runtime._type
......
......@@ -249,11 +249,11 @@ const (
ODCLTYPE // type Int int
ODELETE // delete(Left, Right)
ODOT // Left.Right (Left is of struct type)
ODOTPTR // Left.Right (Left is of pointer to struct type)
ODOTMETH // Left.Right (Left is non-interface, Right is method name)
ODOTINTER // Left.Right (Left is interface, Right is method name)
OXDOT // Left.Right (before rewrite to one of the preceding)
ODOT // Left.Sym (Left is of struct type)
ODOTPTR // Left.Sym (Left is of pointer to struct type)
ODOTMETH // Left.Sym (Left is non-interface, Right is method name)
ODOTINTER // Left.Sym (Left is interface, Right is method name)
OXDOT // Left.Sym (before rewrite to one of the preceding)
ODOTTYPE // Left.Right or Left.Type (.Right during parsing, .Type once resolved)
ODOTTYPE2 // Left.Right or Left.Type (.Right during parsing, .Type once resolved; on rhs of OAS2DOTTYPE)
OEQ // Left == Right
......
......@@ -252,17 +252,22 @@ func typecheck1(np **Node, top int) {
*np = n
}()
if n.Sym != nil {
if n.Op == ONAME && n.Etype != 0 && top&Ecall == 0 {
Yyerror("use of builtin %v not in function call", n.Sym)
n.Type = nil
return
}
switch n.Op {
case OXDOT, ODOT, ODOTPTR, ODOTMETH, ODOTINTER:
// n.Sym is a field/method name, not a variable.
default:
if n.Sym != nil {
if n.Op == ONAME && n.Etype != 0 && top&Ecall == 0 {
Yyerror("use of builtin %v not in function call", n.Sym)
n.Type = nil
return
}
typecheckdef(n)
if n.Op == ONONAME {
n.Type = nil
return
typecheckdef(n)
if n.Op == ONONAME {
n.Type = nil
return
}
}
}
......@@ -819,11 +824,6 @@ OpSwitch:
typecheck(&n.Left, Erv|Etype)
defaultlit(&n.Left, nil)
if n.Right.Op != ONAME {
Yyerror("rhs of . must be a name") // impossible
n.Type = nil
return
}
t := n.Left.Type
if t == nil {
......@@ -832,14 +832,14 @@ OpSwitch:
return
}
r := n.Right
s := n.Sym
if n.Left.Op == OTYPE {
if !looktypedot(n, t, 0) {
if looktypedot(n, t, 1) {
Yyerror("%v undefined (cannot refer to unexported method %v)", n, n.Right.Sym)
Yyerror("%v undefined (cannot refer to unexported method %v)", n, n.Sym)
} else {
Yyerror("%v undefined (type %v has no method %v)", n, t, n.Right.Sym)
Yyerror("%v undefined (type %v has no method %v)", n, t, n.Sym)
}
n.Type = nil
return
......@@ -856,7 +856,7 @@ OpSwitch:
if n.Name == nil {
n.Name = new(Name)
}
n.Sym = n.Right.Sym
n.Right = newname(n.Sym)
n.Type = methodfunc(n.Type, n.Left.Type)
n.Xoffset = 0
n.Class = PFUNC
......@@ -874,7 +874,7 @@ OpSwitch:
checkwidth(t)
}
if isblank(n.Right) {
if isblanksym(n.Sym) {
Yyerror("cannot refer to blank field or method")
n.Type = nil
return
......@@ -892,13 +892,13 @@ OpSwitch:
case lookdot(n, t, 1) != nil:
// Field or method matches by name, but it is not exported.
Yyerror("%v undefined (cannot refer to unexported field or method %v)", n, n.Right.Sym)
Yyerror("%v undefined (cannot refer to unexported field or method %v)", n, n.Sym)
default:
if mt := lookdot(n, t, 2); mt != nil { // Case-insensitive lookup.
Yyerror("%v undefined (type %v has no field or method %v, but does have %v)", n, n.Left.Type, n.Right.Sym, mt.Sym)
Yyerror("%v undefined (type %v has no field or method %v, but does have %v)", n, n.Left.Type, n.Sym, mt.Sym)
} else {
Yyerror("%v undefined (type %v has no field or method %v)", n, n.Left.Type, n.Right.Sym)
Yyerror("%v undefined (type %v has no field or method %v)", n, n.Left.Type, n.Sym)
}
}
n.Type = nil
......@@ -910,7 +910,7 @@ OpSwitch:
if top&Ecall != 0 {
ok |= Ecall
} else {
typecheckpartialcall(n, r)
typecheckpartialcall(n, s)
ok |= Erv
}
......@@ -2392,7 +2392,7 @@ func lookdot1(errnode *Node, s *Sym, t *Type, fs *Fields, dostrcmp int) *Field {
}
func looktypedot(n *Node, t *Type, dostrcmp int) bool {
s := n.Right.Sym
s := n.Sym
if t.Etype == TINTER {
f1 := lookdot1(n, s, t, t.Fields(), dostrcmp)
......@@ -2400,7 +2400,7 @@ func looktypedot(n *Node, t *Type, dostrcmp int) bool {
return false
}
n.Right = methodname(n.Right, t)
n.Sym = methodsym(n.Sym, t, 0)
n.Xoffset = f1.Width
n.Type = f1.Type
n.Op = ODOTINTER
......@@ -2426,7 +2426,7 @@ func looktypedot(n *Node, t *Type, dostrcmp int) bool {
return false
}
n.Right = methodname(n.Right, t)
n.Sym = methodsym(n.Sym, t, 0)
n.Xoffset = f2.Width
n.Type = f2.Type
n.Op = ODOTMETH
......@@ -2450,7 +2450,7 @@ type typeSym struct {
var dotField = map[typeSym]*Field{}
func lookdot(n *Node, t *Type, dostrcmp int) *Field {
s := n.Right.Sym
s := n.Sym
dowidth(t)
var f1 *Field
......@@ -2474,7 +2474,7 @@ func lookdot(n *Node, t *Type, dostrcmp int) *Field {
return f1
}
if f2 != nil {
Yyerror("%v is both field and method", n.Right.Sym)
Yyerror("%v is both field and method", n.Sym)
}
if f1.Width == BADWIDTH {
Fatalf("lookdot badwidth %v %p", f1, f1)
......@@ -2516,7 +2516,7 @@ func lookdot(n *Node, t *Type, dostrcmp int) *Field {
n.Left.Implicit = true
typecheck(&n.Left, Etype|Erv)
} else if tt.Etype == Tptr && tt.Type.Etype == Tptr && Eqtype(derefall(tt), derefall(rcvr)) {
Yyerror("calling method %v with receiver %v requires explicit dereference", n.Right, Nconv(n.Left, FmtLong))
Yyerror("calling method %v with receiver %v requires explicit dereference", n.Sym, Nconv(n.Left, FmtLong))
for tt.Etype == Tptr {
// Stop one level early for method with pointer receiver.
if rcvr.Etype == Tptr && tt.Type.Etype != Tptr {
......@@ -2545,7 +2545,7 @@ func lookdot(n *Node, t *Type, dostrcmp int) *Field {
return nil
}
n.Right = methodname(n.Right, n.Left.Type)
n.Sym = methodsym(n.Sym, n.Left.Type, 0)
n.Xoffset = f2.Width
n.Type = f2.Type
......@@ -3232,7 +3232,7 @@ func samesafeexpr(l *Node, r *Node) bool {
return l == r
case ODOT, ODOTPTR:
return l.Right != nil && r.Right != nil && l.Right.Sym == r.Right.Sym && samesafeexpr(l.Left, r.Left)
return l.Sym != nil && r.Sym != nil && l.Sym == r.Sym && samesafeexpr(l.Left, r.Left)
case OIND:
return samesafeexpr(l.Left, r.Left)
......
......@@ -2480,12 +2480,17 @@ func varexpr(n *Node) bool {
OPAREN,
OANDAND,
OOROR,
ODOT, // but not ODOTPTR
OCONV,
OCONVNOP,
OCONVIFACE,
ODOTTYPE:
return varexpr(n.Left) && varexpr(n.Right)
case ODOT: // but not ODOTPTR
// The original code always returned false for ODOT,
// because n.Right would be an ONAME with n.Class not set.
// TODO(iant): Fix this to remove "&& false".
return varexpr(n.Left) && false
}
// Be conservative.
......@@ -3234,8 +3239,8 @@ func walkcompare(np **Node, init *Nodes) {
if isblanksym(t1.Sym) {
continue
}
li = Nod(OXDOT, l, newname(t1.Sym))
ri = Nod(OXDOT, r, newname(t1.Sym))
li = NodSym(OXDOT, l, t1.Sym)
ri = NodSym(OXDOT, r, t1.Sym)
a = Nod(n.Op, li, ri)
if expr == nil {
expr = a
......@@ -3295,9 +3300,7 @@ func samecheap(a *Node, b *Node) bool {
return a == b
case ODOT, ODOTPTR:
ar = a.Right
br = b.Right
if ar.Op != ONAME || br.Op != ONAME || ar.Sym != br.Sym {
if a.Sym != b.Sym {
return false
}
......@@ -3815,7 +3818,7 @@ func usefield(n *Node) {
case ODOT, ODOTPTR:
break
}
if n.Right == nil {
if n.Sym == nil {
// No field name. This DOTPTR was built by the compiler for access
// to runtime data structures. Ignore.
return
......@@ -3825,9 +3828,9 @@ func usefield(n *Node) {
if Isptr[t.Etype] {
t = t.Type
}
field := dotField[typeSym{t.Orig, n.Right.Sym}]
field := dotField[typeSym{t.Orig, n.Sym}]
if field == nil {
Fatalf("usefield %v %v without paramfld", n.Left.Type, n.Right.Sym)
Fatalf("usefield %v %v without paramfld", n.Left.Type, n.Sym)
}
if field.Note == nil || !strings.Contains(*field.Note, "go:\"track\"") {
return
......
......@@ -639,7 +639,7 @@ func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
// A special case to make write barriers more efficient.
// Comparing the first field of a named struct can be done directly.
base := n1
if n1.Op == gc.ODOT && n1.Left.Type.Etype == gc.TSTRUCT && n1.Left.Type.Field(0).Sym == n1.Right.Sym {
if n1.Op == gc.ODOT && n1.Left.Type.Etype == gc.TSTRUCT && n1.Left.Type.Field(0).Sym == n1.Sym {
base = n1.Left
}
......
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