]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.regabi] cmd/compile: introduce OMETHEXPR instead of overloading ONAME
authorRuss Cox <rsc@golang.org>
Wed, 18 Nov 2020 16:25:29 +0000 (11:25 -0500)
committerRuss Cox <rsc@golang.org>
Tue, 24 Nov 2020 20:58:29 +0000 (20:58 +0000)
A method expression today is an ONAME that has none of the
invariants or properties of other ONAMEs and is always a special case
(hence the Node.IsMethodExpression method).
Remove the special cases by making a separate Op.

Passes toolstash -cmp.

Change-Id: I7667693c9155d5486a6924dbf75ebb59891c4afc
Reviewed-on: https://go-review.googlesource.com/c/go/+/272867
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
src/cmd/compile/internal/gc/escape.go
src/cmd/compile/internal/gc/fmt.go
src/cmd/compile/internal/gc/iexport.go
src/cmd/compile/internal/gc/initorder.go
src/cmd/compile/internal/gc/inl.go
src/cmd/compile/internal/gc/scc.go
src/cmd/compile/internal/gc/sinit.go
src/cmd/compile/internal/gc/ssa.go
src/cmd/compile/internal/gc/syntax.go
src/cmd/compile/internal/gc/typecheck.go
src/cmd/compile/internal/gc/walk.go

index 07cc5498259bb77461a017847300e815a9a4d169..497151d02f33fb2054f95e7d8ebaa90d40791219 100644 (file)
@@ -476,7 +476,7 @@ func (e *Escape) exprSkipInit(k EscHole, n *Node) {
        default:
                Fatalf("unexpected expr: %v", n)
 
-       case OLITERAL, ONIL, OGETG, OCLOSUREVAR, OTYPE:
+       case OLITERAL, ONIL, OGETG, OCLOSUREVAR, OTYPE, OMETHEXPR:
                // nop
 
        case ONAME:
index e62a526eebc721fdcf68bf0c72226438e63f828f..addb010e5c71e64dab4d299e07eb3dcac99b4ec2 100644 (file)
@@ -1355,15 +1355,15 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
                        mode.Fprintf(s, ")")
                }
 
-       // Special case: name used as local variable in export.
-       // _ becomes ~b%d internally; print as _ for export
        case ONAME:
+               // Special case: name used as local variable in export.
+               // _ becomes ~b%d internally; print as _ for export
                if mode == FErr && n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' {
                        fmt.Fprint(s, "_")
                        return
                }
                fallthrough
-       case OPACK, ONONAME:
+       case OPACK, ONONAME, OMETHEXPR:
                fmt.Fprint(s, smodeString(n.Sym, mode))
 
        case OTYPE:
@@ -1695,7 +1695,7 @@ func (n *Node) nodedump(s fmt.State, flag FmtFlag, mode fmtMode) {
        case OLITERAL:
                mode.Fprintf(s, "%v-%v%j", n.Op, n.Val(), n)
 
-       case ONAME, ONONAME:
+       case ONAME, ONONAME, OMETHEXPR:
                if n.Sym != nil {
                        mode.Fprintf(s, "%v-%v%j", n.Op, n.Sym, n)
                } else {
index d661fca2d14477625c67872dd2b4eb5ab151510b..842025705b9c2f2813ea36cd6ef0984ca35f9196 100644 (file)
@@ -1218,18 +1218,16 @@ func (w *exportWriter) expr(n *Node) {
                w.pos(n.Pos)
                w.value(n.Type, n.Val())
 
-       case ONAME:
+       case OMETHEXPR:
                // Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method,
                // but for export, this should be rendered as (*pkg.T).meth.
                // These nodes have the special property that they are names with a left OTYPE and a right ONAME.
-               if n.isMethodExpression() {
-                       w.op(OXDOT)
-                       w.pos(n.Pos)
-                       w.expr(n.Left) // n.Left.Op == OTYPE
-                       w.selector(n.Right.Sym)
-                       break
-               }
+               w.op(OXDOT)
+               w.pos(n.Pos)
+               w.expr(n.Left) // n.Left.Op == OTYPE
+               w.selector(n.Right.Sym)
 
+       case ONAME:
                // Package scope name.
                if (n.Class() == PEXTERN || n.Class() == PFUNC) && !n.isBlank() {
                        w.op(ONONAME)
index f82df04b7307bd91630377a460d7a666ac3fdda4..ecbfc5631a3e692fd1d2ae1d8f2701c8c370a555 100644 (file)
@@ -273,12 +273,11 @@ func (d *initDeps) inspectList(l Nodes) { inspectList(l, d.visit) }
 // referenced by n, if any.
 func (d *initDeps) visit(n *Node) bool {
        switch n.Op {
-       case ONAME:
-               if n.isMethodExpression() {
-                       d.foundDep(n.MethodName())
-                       return false
-               }
+       case OMETHEXPR:
+               d.foundDep(n.MethodName())
+               return false
 
+       case ONAME:
                switch n.Class() {
                case PEXTERN, PFUNC:
                        d.foundDep(n)
index db53b2aae147cc0d2133d03b99cc0c21c1f05b75..0695b161f1249c1ad20e2bdf96f8e50d6200fe03 100644 (file)
@@ -260,15 +260,14 @@ func inlFlood(n *Node) {
        // because after inlining they might be callable.
        inspectList(asNodes(n.Func.Inl.Body), func(n *Node) bool {
                switch n.Op {
+               case OMETHEXPR:
+                       inlFlood(n.MethodName())
+
                case ONAME:
                        switch n.Class() {
                        case PFUNC:
-                               if n.isMethodExpression() {
-                                       inlFlood(n.MethodName())
-                               } else {
-                                       inlFlood(n)
-                                       exportsym(n)
-                               }
+                               inlFlood(n)
+                               exportsym(n)
                        case PEXTERN:
                                exportsym(n)
                        }
@@ -709,17 +708,16 @@ func inlnode(n *Node, maxCost int32, inlMap map[*Node]bool) *Node {
 func inlCallee(fn *Node) *Node {
        fn = staticValue(fn)
        switch {
-       case fn.Op == ONAME && fn.Class() == PFUNC:
-               if fn.isMethodExpression() {
-                       n := fn.MethodName()
-                       // Check that receiver type matches fn.Left.
-                       // TODO(mdempsky): Handle implicit dereference
-                       // of pointer receiver argument?
-                       if n == nil || !types.Identical(n.Type.Recv().Type, fn.Left.Type) {
-                               return nil
-                       }
-                       return n
+       case fn.Op == OMETHEXPR:
+               n := fn.MethodName()
+               // Check that receiver type matches fn.Left.
+               // TODO(mdempsky): Handle implicit dereference
+               // of pointer receiver argument?
+               if n == nil || !types.Identical(n.Type.Recv().Type, fn.Left.Type) {
+                       return nil
                }
+               return n
+       case fn.Op == ONAME && fn.Class() == PFUNC:
                return fn
        case fn.Op == OCLOSURE:
                c := fn.Func.Decl
@@ -963,7 +961,7 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
                        ninit.AppendNodes(&callee.Ninit)
                        callee = callee.Left
                }
-               if callee.Op != ONAME && callee.Op != OCLOSURE {
+               if callee.Op != ONAME && callee.Op != OCLOSURE && callee.Op != OMETHEXPR {
                        Fatalf("unexpected callee expression: %v", callee)
                }
        }
@@ -1323,6 +1321,9 @@ func (subst *inlsubst) node(n *Node) *Node {
                }
                return n
 
+       case OMETHEXPR:
+               return n
+
        case OLITERAL, ONIL, OTYPE:
                // If n is a named constant or type, we can continue
                // using it in the inline copy. Otherwise, make a copy
index 8e41ebac29c65b3dc6a9ec99a67c2019a391b280..891012cbc9f2bbd06c15a928f925bfbdbdded3cd 100644 (file)
@@ -77,15 +77,19 @@ func (v *bottomUpVisitor) visit(n *Node) uint32 {
                switch n.Op {
                case ONAME:
                        if n.Class() == PFUNC {
-                               if n.isMethodExpression() {
-                                       n = n.MethodName()
-                               }
                                if n != nil && n.Name.Defn != nil {
                                        if m := v.visit(n.Name.Defn); m < min {
                                                min = m
                                        }
                                }
                        }
+               case OMETHEXPR:
+                       fn := n.MethodName()
+                       if fn != nil && fn.Name.Defn != nil {
+                               if m := v.visit(fn.Name.Defn); m < min {
+                                       min = m
+                               }
+                       }
                case ODOTMETH:
                        fn := n.MethodName()
                        if fn != nil && fn.Op == ONAME && fn.Class() == PFUNC && fn.Name.Defn != nil {
index 5727245562420f7268f92ddd319d05b2dbbcd356..3b4056cf7d208f51f4d881f023458f38b6f25172 100644 (file)
@@ -68,7 +68,7 @@ func (s *InitSchedule) tryStaticInit(n *Node) bool {
 // like staticassign but we are copying an already
 // initialized value r.
 func (s *InitSchedule) staticcopy(l *Node, r *Node) bool {
-       if r.Op != ONAME {
+       if r.Op != ONAME && r.Op != OMETHEXPR {
                return false
        }
        if r.Class() == PFUNC {
@@ -95,7 +95,7 @@ func (s *InitSchedule) staticcopy(l *Node, r *Node) bool {
        }
 
        switch r.Op {
-       case ONAME:
+       case ONAME, OMETHEXPR:
                if s.staticcopy(l, r) {
                        return true
                }
@@ -171,7 +171,7 @@ func (s *InitSchedule) staticassign(l *Node, r *Node) bool {
        }
 
        switch r.Op {
-       case ONAME:
+       case ONAME, OMETHEXPR:
                return s.staticcopy(l, r)
 
        case ONIL:
@@ -383,7 +383,7 @@ func readonlystaticname(t *types.Type) *Node {
 }
 
 func (n *Node) isSimpleName() bool {
-       return n.Op == ONAME && n.Class() != PAUTOHEAP && n.Class() != PEXTERN
+       return (n.Op == ONAME || n.Op == OMETHEXPR) && n.Class() != PAUTOHEAP && n.Class() != PEXTERN
 }
 
 func litas(l *Node, r *Node, init *Nodes) {
@@ -870,7 +870,7 @@ func anylit(n *Node, var_ *Node, init *Nodes) {
        default:
                Fatalf("anylit: not lit, op=%v node=%v", n.Op, n)
 
-       case ONAME:
+       case ONAME, OMETHEXPR:
                a := nod(OAS, var_, n)
                a = typecheck(a, ctxStmt)
                init.Append(a)
@@ -1007,7 +1007,7 @@ func stataddr(nam *Node, n *Node) bool {
        }
 
        switch n.Op {
-       case ONAME:
+       case ONAME, OMETHEXPR:
                *nam = *n
                return true
 
@@ -1172,7 +1172,7 @@ func genAsStatic(as *Node) {
        switch {
        case as.Right.Op == OLITERAL:
                litsym(&nam, as.Right, int(as.Right.Type.Width))
-       case as.Right.Op == ONAME && as.Right.Class() == PFUNC:
+       case (as.Right.Op == ONAME || as.Right.Op == OMETHEXPR) && as.Right.Class() == PFUNC:
                pfuncsym(&nam, as.Right)
        default:
                Fatalf("genAsStatic: rhs %v", as.Right)
index e23a189d7176df04cb404e3c0d8cc74132dd2276..88ff8d684c5ecf9f08ac1882b4159b3c2cd0feb0 100644 (file)
@@ -2016,6 +2016,9 @@ func (s *state) expr(n *Node) *ssa.Value {
        case OCFUNC:
                aux := n.Left.Sym.Linksym()
                return s.entryNewValue1A(ssa.OpAddr, n.Type, aux, s.sb)
+       case OMETHEXPR:
+               sym := funcsym(n.Sym).Linksym()
+               return s.entryNewValue1A(ssa.OpAddr, types.NewPtr(n.Type), sym, s.sb)
        case ONAME:
                if n.Class() == PFUNC {
                        // "value" of a function is the address of the function's closure
index 343d5b171c36bb4827dff37d157d81a26c01de21..39f2996808ecb67fc1e8b1ce05d176246ed3097c 100644 (file)
@@ -303,11 +303,6 @@ func (n *Node) mayBeShared() bool {
        return false
 }
 
-// isMethodExpression reports whether n represents a method expression T.M.
-func (n *Node) isMethodExpression() bool {
-       return n.Op == ONAME && n.Left != nil && n.Left.Op == OTYPE && n.Right != nil && n.Right.Op == ONAME
-}
-
 // funcname returns the name (without the package) of the function n.
 func (n *Node) funcname() string {
        if n == nil || n.Func == nil || n.Func.Nname == nil {
@@ -599,15 +594,10 @@ func (p *Param) SetEmbedFiles(list []string) {
 // will be the qualified method name (e.g., "T.m") and
 // f.Func.Shortname is the bare method name (e.g., "m").
 //
-// A method expression (T.M) is represented as an ONAME node
-// like a function name would be, but n.Left and n.Right point to
-// the type and method, respectively. A method expression can
-// be distinguished from a normal function ONAME by checking
-// n.IsMethodExpression. Unlike ordinary ONAME nodes, each
-// distinct mention of a method expression in the source code
-// constructs a fresh ONAME node.
-// TODO(rsc): Method expressions deserve their own opcode
-// instead of violating invariants of ONAME.
+// A method expression (T.M) is represented as an OMETHEXPR node,
+// in which n.Left and n.Right point to the type and method, respectively.
+// Each distinct mention of a method expression in the source code
+// constructs a fresh node.
 //
 // A method value (t.M) is represented by ODOTMETH/ODOTINTER
 // when it is called directly and by OCALLPART otherwise.
index 11c1ae38ea735860f0fc5dda14352ec2cca3caa3..5cc7c8a34c4e00eefd67c567e385dea4d8e83476 100644 (file)
@@ -2408,7 +2408,7 @@ func typecheckMethodExpr(n *Node) (res *Node) {
                return n
        }
 
-       n.Op = ONAME
+       n.Op = OMETHEXPR
        if n.Name == nil {
                n.Name = new(Name)
        }
@@ -2668,7 +2668,7 @@ notenough:
                        // call is the expression being called, not the overall call.
                        // Method expressions have the form T.M, and the compiler has
                        // rewritten those to ONAME nodes but left T in Left.
-                       if call.isMethodExpression() {
+                       if call.Op == OMETHEXPR {
                                yyerror("not enough arguments in call to method expression %v%s", call, details)
                        } else {
                                yyerror("not enough arguments in call to %v%s", call, details)
@@ -4032,10 +4032,10 @@ func (n *Node) MethodName() *Node {
 
 // MethodFunc is like MethodName, but returns the types.Field instead.
 func (n *Node) MethodFunc() *types.Field {
-       switch {
-       case n.Op == ODOTMETH || n.isMethodExpression():
+       switch n.Op {
+       case ODOTMETH, OMETHEXPR:
                return n.Opt().(*types.Field)
-       case n.Op == OCALLPART:
+       case OCALLPART:
                return callpartMethod(n)
        }
        Fatalf("unexpected node: %v (%v)", n, n.Op)
index ae344fc8e101b109fae01ea7aa0c8f9c8595beed..7bf5281a67308a674d31302c377e4035e8b2d419 100644 (file)
@@ -464,7 +464,7 @@ opswitch:
                Dump("walk", n)
                Fatalf("walkexpr: switch 1 unknown op %+S", n)
 
-       case ONONAME, OEMPTY, OGETG, ONEWOBJ:
+       case ONONAME, OEMPTY, OGETG, ONEWOBJ, OMETHEXPR:
 
        case OTYPE, ONAME, OLITERAL, ONIL:
                // TODO(mdempsky): Just return n; see discussion on CL 38655.