From: Matthew Dempsky Date: Sat, 6 Aug 2022 23:08:41 +0000 (-0700) Subject: cmd/compile/internal/noder: explicit receiver expression handling X-Git-Tag: go1.20rc1~1705 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=de95dca32fb196d5f09bf5db4a6ba592907559c3;p=gostls13.git cmd/compile/internal/noder: explicit receiver expression handling This CL adds a helper expression code for receiver addressing; i.e., the implicit addressing, dereferencing, and field selections involved in changing the `x` in `x.M()` into an appropriate expression to pass as an argument to the method. Change-Id: I9be933e2a38c8f94f6a85d95b54f34164e5efb0a Reviewed-on: https://go-review.googlesource.com/c/go/+/421820 Reviewed-by: Cuong Manh Le Run-TryBot: Matthew Dempsky Reviewed-by: Keith Randall TryBot-Result: Gopher Robot Reviewed-by: Keith Randall --- diff --git a/src/cmd/compile/internal/noder/codes.go b/src/cmd/compile/internal/noder/codes.go index d8de1f483c..fb4fb4a886 100644 --- a/src/cmd/compile/internal/noder/codes.go +++ b/src/cmd/compile/internal/noder/codes.go @@ -57,6 +57,7 @@ const ( exprMake exprNil exprFuncInst + exprRecv ) type codeAssign int diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 8c80c78c0b..3ab11399a5 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -1914,6 +1914,19 @@ func (r *reader) expr() (res ir.Node) { } return typecheck.Expr(ir.NewBinaryExpr(pos, op, x, y)) + case exprRecv: + x := r.expr() + pos := r.pos() + for i, n := 0, r.Len(); i < n; i++ { + x = Implicit(DotField(pos, x, r.Len())) + } + if r.Bool() { // needs deref + x = Implicit(Deref(pos, x.Type().Elem(), x)) + } else if r.Bool() { // needs addr + x = Implicit(Addr(pos, x)) + } + return x + case exprCall: fun := r.expr() if r.Bool() { // method call diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go index 9cf914743d..ef84a53cf3 100644 --- a/src/cmd/compile/internal/noder/writer.go +++ b/src/cmd/compile/internal/noder/writer.go @@ -1540,7 +1540,7 @@ func (w *writer) expr(expr syntax.Expr) { case types2.MethodVal: w.Code(exprMethodVal) - w.expr(expr.X) + w.recvExpr(expr, sel) w.pos(expr) w.selector(sel.Obj()) @@ -1697,7 +1697,7 @@ func (w *writer) expr(expr syntax.Expr) { writeFunExpr := func() { if selector, ok := unparen(expr.Fun).(*syntax.SelectorExpr); ok { if sel, ok := w.p.info.Selections[selector]; ok && sel.Kind() == types2.MethodVal { - w.expr(selector.X) + w.recvExpr(selector, sel) w.Bool(true) // method call w.pos(selector) w.selector(sel.Obj()) @@ -1741,6 +1741,40 @@ func (w *writer) optExpr(expr syntax.Expr) { } } +// recvExpr writes out expr.X, but handles any implicit addressing, +// dereferencing, and field selections. +func (w *writer) recvExpr(expr *syntax.SelectorExpr, sel *types2.Selection) types2.Type { + index := sel.Index() + implicits := index[:len(index)-1] + + w.Code(exprRecv) + w.expr(expr.X) + w.pos(expr) + w.Len(len(implicits)) + + typ := w.p.typeOf(expr.X) + for _, ix := range implicits { + typ = deref2(typ).Underlying().(*types2.Struct).Field(ix).Type() + w.Len(ix) + } + + isPtrTo := func(from, to types2.Type) bool { + if from, ok := from.(*types2.Pointer); ok { + return types2.Identical(from.Elem(), to) + } + return false + } + + recv := sel.Obj().(*types2.Func).Type().(*types2.Signature).Recv().Type() + if w.Bool(isPtrTo(typ, recv)) { // needs deref + typ = recv + } else if w.Bool(isPtrTo(recv, typ)) { // needs addr + typ = recv + } + + return typ +} + // multiExpr writes a sequence of expressions, where the i'th value is // implicitly converted to dstType(i). It also handles when exprs is a // single, multi-valued expression (e.g., the multi-valued argument in