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: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/src/cmd/compile/internal/amd64/gsubr.go b/src/cmd/compile/internal/amd64/gsubr.go
index 788a9bc..5c9f650 100644
--- a/src/cmd/compile/internal/amd64/gsubr.go
+++ b/src/cmd/compile/internal/amd64/gsubr.go
@@ -112,7 +112,7 @@
// 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
}
diff --git a/src/cmd/compile/internal/gc/alg.go b/src/cmd/compile/internal/gc/alg.go
index 6ef99c8..4ee9de5 100644
--- a/src/cmd/compile/internal/gc/alg.go
+++ b/src/cmd/compile/internal/gc/alg.go
@@ -242,7 +242,7 @@
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 @@
// 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 @@
// 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 @@
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 @@
// 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)
diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go
index bf5b577..eea7df5 100644
--- a/src/cmd/compile/internal/gc/bexport.go
+++ b/src/cmd/compile/internal/gc/bexport.go
@@ -890,7 +890,7 @@
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)
diff --git a/src/cmd/compile/internal/gc/bimport.go b/src/cmd/compile/internal/gc/bimport.go
index 16d0e39..1c8cb80 100644
--- a/src/cmd/compile/internal/gc/bimport.go
+++ b/src/cmd/compile/internal/gc/bimport.go
@@ -658,7 +658,7 @@
obj.Used = true
return oldname(s)
}
- return Nod(OXDOT, obj, newname(sel))
+ return NodSym(OXDOT, obj, sel)
case ODOTTYPE, ODOTTYPE2:
n.Left = p.node()
diff --git a/src/cmd/compile/internal/gc/cgen.go b/src/cmd/compile/internal/gc/cgen.go
index 37eb776..b1e152b 100644
--- a/src/cmd/compile/internal/gc/cgen.go
+++ b/src/cmd/compile/internal/gc/cgen.go
@@ -802,7 +802,7 @@
}
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 @@
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 {
diff --git a/src/cmd/compile/internal/gc/closure.go b/src/cmd/compile/internal/gc/closure.go
index 10faf52..4c97cad 100644
--- a/src/cmd/compile/internal/gc/closure.go
+++ b/src/cmd/compile/internal/gc/closure.go
@@ -462,7 +462,7 @@
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 @@
// 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 @@
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 {
diff --git a/src/cmd/compile/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go
index 57698ce..f2b566f 100644
--- a/src/cmd/compile/internal/gc/dcl.go
+++ b/src/cmd/compile/internal/gc/dcl.go
@@ -1432,7 +1432,7 @@
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
diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go
index c4e07dd..19fc633 100644
--- a/src/cmd/compile/internal/gc/esc.go
+++ b/src/cmd/compile/internal/gc/esc.go
@@ -131,7 +131,7 @@
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 @@
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 {
diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go
index 39320d1..e82be44 100644
--- a/src/cmd/compile/internal/gc/fmt.go
+++ b/src/cmd/compile/internal/gc/fmt.go
@@ -1249,12 +1249,7 @@
}
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 @@
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)
diff --git a/src/cmd/compile/internal/gc/gen.go b/src/cmd/compile/internal/gc/gen.go
index 5f01d4d..7e192a8 100644
--- a/src/cmd/compile/internal/gc/gen.go
+++ b/src/cmd/compile/internal/gc/gen.go
@@ -948,7 +948,7 @@
n2 := *n
n2.Op = OCALLFUNC
- n2.Left = l.Right
+ n2.Left = newname(l.Sym)
n2.Left.Type = l.Type
if n2.Left.Op == ONAME {
diff --git a/src/cmd/compile/internal/gc/gsubr.go b/src/cmd/compile/internal/gc/gsubr.go
index ddaa3f2..d3bcb76 100644
--- a/src/cmd/compile/internal/gc/gsubr.go
+++ b/src/cmd/compile/internal/gc/gsubr.go
@@ -416,7 +416,7 @@
// 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))
diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go
index ebfeb9b..0ef9253 100644
--- a/src/cmd/compile/internal/gc/inl.go
+++ b/src/cmd/compile/internal/gc/inl.go
@@ -220,6 +220,13 @@
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)--
diff --git a/src/cmd/compile/internal/gc/parser.go b/src/cmd/compile/internal/gc/parser.go
index 4288570..e7be3ee 100644
--- a/src/cmd/compile/internal/gc/parser.go
+++ b/src/cmd/compile/internal/gc/parser.go
@@ -1793,7 +1793,7 @@
obj.Used = true
return oldname(s)
}
- return Nod(OXDOT, obj, newname(sel))
+ return NodSym(OXDOT, obj, sel)
}
func (p *parser) dotname() *Node {
diff --git a/src/cmd/compile/internal/gc/range.go b/src/cmd/compile/internal/gc/range.go
index 28c6896..bf7938a 100644
--- a/src/cmd/compile/internal/gc/range.go
+++ b/src/cmd/compile/internal/gc/range.go
@@ -226,27 +226,27 @@
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})
diff --git a/src/cmd/compile/internal/gc/sinit.go b/src/cmd/compile/internal/gc/sinit.go
index 7f0b98c..6386517 100644
--- a/src/cmd/compile/internal/gc/sinit.go
+++ b/src/cmd/compile/internal/gc/sinit.go
@@ -574,10 +574,10 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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)
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index 84dc29c..55ab138 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -2326,16 +2326,14 @@
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 @@
// 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
}
diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go
index c7cac05..411f7e0 100644
--- a/src/cmd/compile/internal/gc/subr.go
+++ b/src/cmd/compile/internal/gc/subr.go
@@ -339,6 +339,14 @@
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 @@
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 @@
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 @@
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) {
diff --git a/src/cmd/compile/internal/gc/swt.go b/src/cmd/compile/internal/gc/swt.go
index 2f07988..2a4e741 100644
--- a/src/cmd/compile/internal/gc/swt.go
+++ b/src/cmd/compile/internal/gc/swt.go
@@ -595,14 +595,14 @@
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
diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go
index 4d4189a..d4a26c4 100644
--- a/src/cmd/compile/internal/gc/syntax.go
+++ b/src/cmd/compile/internal/gc/syntax.go
@@ -249,11 +249,11 @@
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
diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go
index e857943..7e09912 100644
--- a/src/cmd/compile/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -252,17 +252,22 @@
*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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
if top&Ecall != 0 {
ok |= Ecall
} else {
- typecheckpartialcall(n, r)
+ typecheckpartialcall(n, s)
ok |= Erv
}
@@ -2392,7 +2392,7 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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)
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index e0e05c7..587914b 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -2480,12 +2480,17 @@
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 @@
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 @@
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 @@
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 @@
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
diff --git a/src/cmd/compile/internal/x86/gsubr.go b/src/cmd/compile/internal/x86/gsubr.go
index 2ed29e5..8228182 100644
--- a/src/cmd/compile/internal/x86/gsubr.go
+++ b/src/cmd/compile/internal/x86/gsubr.go
@@ -639,7 +639,7 @@
// 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
}