diff --git a/src/cmd/compile/internal/devirtualize/devirtualize.go b/src/cmd/compile/internal/devirtualize/devirtualize.go index 60ba208d08..f52499e07f 100644 --- a/src/cmd/compile/internal/devirtualize/devirtualize.go +++ b/src/cmd/compile/internal/devirtualize/devirtualize.go @@ -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). diff --git a/src/cmd/compile/internal/escape/call.go b/src/cmd/compile/internal/escape/call.go index b8e28cd46a..62727a8ef8 100644 --- a/src/cmd/compile/internal/escape/call.go +++ b/src/cmd/compile/internal/escape/call.go @@ -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. // diff --git a/src/cmd/compile/internal/typecheck/func.go b/src/cmd/compile/internal/typecheck/func.go index 031279f42c..00770c87cf 100644 --- a/src/cmd/compile/internal/typecheck/func.go +++ b/src/cmd/compile/internal/typecheck/func.go @@ -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. diff --git a/src/cmd/compile/internal/walk/expr.go b/src/cmd/compile/internal/walk/expr.go index bbf289d90e..d8bded8075 100644 --- a/src/cmd/compile/internal/walk/expr.go +++ b/src/cmd/compile/internal/walk/expr.go @@ -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