]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.typeparams] cmd/compile: rewrite method call into method expression during escap...
authorCuong Manh Le <cuong.manhle.vn@gmail.com>
Thu, 24 Jun 2021 16:05:09 +0000 (23:05 +0700)
committerCuong Manh Le <cuong.manhle.vn@gmail.com>
Fri, 25 Jun 2021 02:29:28 +0000 (02:29 +0000)
CL 330331 extended escape analysis to analyze method expression calls
the same as normal method calls. We can now simply desugar method calls
into function calls in escape analysis.

To do this, two things must be changed:

 - Folding the rewrite method call to method expression call into an
   export function in typecheck package, so others can re-use it.

 - walkCall now have to call usemethod for method expression calls.
   (It seems to me this is a bug in current tip, because if one write
   (*rtype).Method(typ, i) in package "reflect", then the function won't
   be marked with AttrReflectMethod)

Passes toolstash -cmp.

Change-Id: I4745ab6110b417c7fd32949cc799811a882cd2ec
Reviewed-on: https://go-review.googlesource.com/c/go/+/330671
Trust: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
src/cmd/compile/internal/devirtualize/devirtualize.go
src/cmd/compile/internal/escape/call.go
src/cmd/compile/internal/typecheck/func.go
src/cmd/compile/internal/walk/expr.go

index 60ba208d0876b119d74e10e33d0103c97fee5c8c..f52499e07f660a0ff0182edcad756d52cb7487d7 100644 (file)
@@ -50,7 +50,6 @@ func Call(call *ir.CallExpr) {
                if base.Flag.LowerM != 0 {
                        base.WarnfAt(call.Pos(), "devirtualizing %v to %v", sel, typ)
                }
-               call.SetOp(ir.OCALLMETH)
                call.X = x
        case ir.ODOTINTER:
                // Promoted method from embedded interface-typed field (#42279).
index b8e28cd46a828df01a41e2449106823eb413c1fa..62727a8ef860e3f0a72087b456ee75857988f32e 100644 (file)
@@ -46,6 +46,7 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
        case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
                call := call.(*ir.CallExpr)
                typecheck.FixVariadicCall(call)
+               typecheck.FixMethodCall(call)
 
                // Pick out the function callee, if statically known.
                //
index 031279f42c1794f771f4289593b0010931a4a3cd..00770c87cf809e8995e75bdf3e113bfafc771a73 100644 (file)
@@ -15,7 +15,7 @@ import (
        "go/token"
 )
 
-// package all the arguments that match a ... T parameter into a []T.
+// MakeDotArgs package all the arguments that match a ... T parameter into a []T.
 func MakeDotArgs(pos src.XPos, typ *types.Type, args []ir.Node) ir.Node {
        var n ir.Node
        if len(args) == 0 {
@@ -57,6 +57,25 @@ func FixVariadicCall(call *ir.CallExpr) {
        call.IsDDD = true
 }
 
+// FixMethodCall rewrites a method call t.M(...) into a function call T.M(t, ...).
+func FixMethodCall(call *ir.CallExpr) {
+       if call.X.Op() != ir.ODOTMETH {
+               return
+       }
+
+       dot := call.X.(*ir.SelectorExpr)
+
+       fn := Expr(ir.NewSelectorExpr(dot.Pos(), ir.OXDOT, ir.TypeNode(dot.X.Type()), dot.Selection.Sym))
+
+       args := make([]ir.Node, 1+len(call.Args))
+       args[0] = dot.X
+       copy(args[1:], call.Args)
+
+       call.SetOp(ir.OCALLFUNC)
+       call.X = fn
+       call.Args = args
+}
+
 // ClosureType returns the struct type used to hold all the information
 // needed in the closure for clo (clo must be a OCLOSURE node).
 // The address of a variable of the returned type can be cast to a func.
index bbf289d90e6702d384a2391e3de01a37f8bc8ab3..d8bded807584e7b21a9d94a840dff2bf783be5a4 100644 (file)
@@ -489,7 +489,7 @@ func walkAddString(n *ir.AddStringExpr, init *ir.Nodes) ir.Node {
 
 // walkCall walks an OCALLFUNC, OCALLINTER, or OCALLMETH node.
 func walkCall(n *ir.CallExpr, init *ir.Nodes) ir.Node {
-       if n.Op() == ir.OCALLINTER || n.Op() == ir.OCALLMETH {
+       if n.Op() == ir.OCALLINTER || n.X.Op() == ir.OMETHEXPR {
                // We expect both interface call reflect.Type.Method and concrete
                // call reflect.(*rtype).Method.
                usemethod(n)
@@ -549,20 +549,8 @@ func walkCall1(n *ir.CallExpr, init *ir.Nodes) {
        }
        n.SetWalked(true)
 
-       // If this is a method call t.M(...),
-       // rewrite into a function call T.M(t, ...).
-       // TODO(mdempsky): Do this right after type checking.
        if n.Op() == ir.OCALLMETH {
-               withRecv := make([]ir.Node, len(n.Args)+1)
-               dot := n.X.(*ir.SelectorExpr)
-               withRecv[0] = dot.X
-               copy(withRecv[1:], n.Args)
-               n.Args = withRecv
-
-               dot = ir.NewSelectorExpr(dot.Pos(), ir.OXDOT, ir.TypeNode(dot.X.Type()), dot.Selection.Sym)
-
-               n.SetOp(ir.OCALLFUNC)
-               n.X = typecheck.Expr(dot)
+               typecheck.FixMethodCall(n)
        }
 
        args := n.Args