1
0
mirror of https://github.com/golang/go synced 2024-11-26 03:47:57 -07:00

[dev.typeparams] cmd/compile: escape analysis of method expression calls

This CL extends escape analysis to analyze function calls using method
expressions the same as it would a normal method call. That is, it now
analyzes "T.M(recv, args...)" the same as "recv.M(args...)".

This is useful because it means the frontend can eventually stop
supporting both function calls and method calls. We can simply desugar
method calls into function calls, like we already do in the backend to
simplify SSA construction.

Change-Id: I9cd5ec0d534cbcd9860f0014c86e4ae416920c26
Reviewed-on: https://go-review.googlesource.com/c/go/+/330331
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
This commit is contained in:
Matthew Dempsky 2021-06-23 00:31:16 -07:00
parent 0a0e3a3dea
commit eb691fdd62
2 changed files with 27 additions and 13 deletions

View File

@ -56,11 +56,15 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
var fn *ir.Name var fn *ir.Name
switch call.Op() { switch call.Op() {
case ir.OCALLFUNC: case ir.OCALLFUNC:
switch v := ir.StaticValue(call.X); { switch v := ir.StaticValue(call.X); v.Op() {
case v.Op() == ir.ONAME && v.(*ir.Name).Class == ir.PFUNC: case ir.ONAME:
fn = v.(*ir.Name) if v := v.(*ir.Name); v.Class == ir.PFUNC {
case v.Op() == ir.OCLOSURE: fn = v
}
case ir.OCLOSURE:
fn = v.(*ir.ClosureExpr).Func.Nname fn = v.(*ir.ClosureExpr).Func.Nname
case ir.OMETHEXPR:
fn = ir.MethodExprName(v)
} }
case ir.OCALLMETH: case ir.OCALLMETH:
fn = ir.MethodExprName(call.X) fn = ir.MethodExprName(call.X)
@ -77,19 +81,30 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
} }
} }
if r := fntype.Recv(); r != nil { var recvp *ir.Node
dot := call.X.(*ir.SelectorExpr) if call.Op() == ir.OCALLFUNC {
argumentFunc(fn, e.tagHole(ks, fn, r), &dot.X)
} else {
// Evaluate callee function expression. // Evaluate callee function expression.
// //
// Note: We use argument and not argumentFunc, because call.X // Note: We use argument and not argumentFunc, because while
// here may be an argument to runtime.{new,defer}proc, but it's // call.X here may be an argument to runtime.{new,defer}proc,
// not an argument to fn itself. // it's not an argument to fn itself.
argument(e.discardHole(), &call.X) argument(e.discardHole(), &call.X)
} else {
recvp = &call.X.(*ir.SelectorExpr).X
} }
args := call.Args args := call.Args
if recv := fntype.Recv(); recv != nil {
if recvp == nil {
// Function call using method expression. Recevier argument is
// at the front of the regular arguments list.
recvp = &args[0]
args = args[1:]
}
argumentFunc(fn, e.tagHole(ks, fn, recv), recvp)
}
for i, param := range fntype.Params().FieldSlice() { for i, param := range fntype.Params().FieldSlice() {
argumentFunc(fn, e.tagHole(ks, fn, param), &args[i]) argumentFunc(fn, e.tagHole(ks, fn, param), &args[i])
} }

View File

@ -180,8 +180,7 @@ func _() {
} }
func fbad24305() { func fbad24305() {
// BAD u should not be heap allocated var u U
var u U // ERROR "moved to heap: u"
(*U).M(&u) (*U).M(&u)
(*U).N(&u) (*U).N(&u)
} }