]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.regabi] cmd/compile: merge {Selector,CallPart,Method}Expr
authorMatthew Dempsky <mdempsky@google.com>
Tue, 29 Dec 2020 00:14:11 +0000 (16:14 -0800)
committerMatthew Dempsky <mdempsky@google.com>
Tue, 29 Dec 2020 02:35:04 +0000 (02:35 +0000)
These three expression nodes all represent the same syntax, and so
they're represented the same within types2. And also they're not
handled that meaningfully differently throughout the rest of the
compiler to merit unique representations.

Method expressions are somewhat unique today that they're very
frequently turned into plain function names. But eventually that can
be handled by a post-typecheck desugaring phase that reduces the
number of redundant AST forms.

Passes toolstash -cmp.

Change-Id: I20df91bbd0d885c1f18ec67feb61ae1558670719
Reviewed-on: https://go-review.googlesource.com/c/go/+/280636
Trust: Matthew Dempsky <mdempsky@google.com>
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Dan Scales <danscales@google.com>
14 files changed:
src/cmd/compile/internal/escape/escape.go
src/cmd/compile/internal/inline/inl.go
src/cmd/compile/internal/ir/expr.go
src/cmd/compile/internal/ir/fmt.go
src/cmd/compile/internal/ir/node_gen.go
src/cmd/compile/internal/staticinit/sched.go
src/cmd/compile/internal/typecheck/expr.go
src/cmd/compile/internal/typecheck/func.go
src/cmd/compile/internal/typecheck/iexport.go
src/cmd/compile/internal/typecheck/typecheck.go
src/cmd/compile/internal/walk/closure.go
src/cmd/compile/internal/walk/complit.go
src/cmd/compile/internal/walk/expr.go
src/cmd/compile/internal/walk/order.go

index d8f0111d2de693248263b992c3c29e27aa8821cf..7b4037e028b34abc7b6c85a4972c1d5f3f7e23e5 100644 (file)
@@ -612,10 +612,10 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) {
                // Flow the receiver argument to both the closure and
                // to the receiver parameter.
 
-               n := n.(*ir.CallPartExpr)
+               n := n.(*ir.SelectorExpr)
                closureK := e.spill(k, n)
 
-               m := n.Method
+               m := n.Selection
 
                // We don't know how the method value will be called
                // later, so conservatively assume the result
@@ -1542,7 +1542,7 @@ func (e *escape) finish(fns []*ir.Func) {
                                        n := n.(*ir.ClosureExpr)
                                        n.SetTransient(true)
                                case ir.OCALLPART:
-                                       n := n.(*ir.CallPartExpr)
+                                       n := n.(*ir.SelectorExpr)
                                        n.SetTransient(true)
                                case ir.OSLICELIT:
                                        n := n.(*ir.CompLitExpr)
@@ -1863,7 +1863,7 @@ func HeapAllocReason(n ir.Node) string {
        if n.Op() == ir.OCLOSURE && typecheck.ClosureType(n.(*ir.ClosureExpr)).Size() >= ir.MaxImplicitStackVarSize {
                return "too large for stack"
        }
-       if n.Op() == ir.OCALLPART && typecheck.PartialCallType(n.(*ir.CallPartExpr)).Size() >= ir.MaxImplicitStackVarSize {
+       if n.Op() == ir.OCALLPART && typecheck.PartialCallType(n.(*ir.SelectorExpr)).Size() >= ir.MaxImplicitStackVarSize {
                return "too large for stack"
        }
 
index 67162771e93508fd7ea0089f6007373927f694a0..fc6a17b9337554048aed8c35aee758727109c272 100644 (file)
@@ -419,6 +419,9 @@ func (v *hairyVisitor) doNode(n ir.Node) error {
 
        case ir.OCALLPART, ir.OSLICELIT:
                v.budget-- // Hack for toolstash -cmp.
+
+       case ir.OMETHEXPR:
+               v.budget++ // Hack for toolstash -cmp.
        }
 
        v.budget--
@@ -613,12 +616,12 @@ func inlCallee(fn ir.Node) *ir.Func {
        fn = ir.StaticValue(fn)
        switch fn.Op() {
        case ir.OMETHEXPR:
-               fn := fn.(*ir.MethodExpr)
+               fn := fn.(*ir.SelectorExpr)
                n := ir.MethodExprName(fn)
-               // Check that receiver type matches fn.Left.
+               // Check that receiver type matches fn.X.
                // TODO(mdempsky): Handle implicit dereference
                // of pointer receiver argument?
-               if n == nil || !types.Identical(n.Type().Recv().Type, fn.T) {
+               if n == nil || !types.Identical(n.Type().Recv().Type, fn.X.Type()) {
                        return nil
                }
                return n.Func
@@ -1098,7 +1101,7 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
                return n
 
        case ir.OMETHEXPR:
-               n := n.(*ir.MethodExpr)
+               n := n.(*ir.SelectorExpr)
                return n
 
        case ir.OLITERAL, ir.ONIL, ir.OTYPE:
index 1337d356a17e793eba1c1a077700ed1bd3d615f2..872f81a447862f8e0f7bc9e994d20c1f71d70950 100644 (file)
@@ -225,26 +225,6 @@ func (n *CallExpr) SetOp(op Op) {
        }
 }
 
-// A CallPartExpr is a method expression X.Method (uncalled).
-type CallPartExpr struct {
-       miniExpr
-       Func     *Func
-       X        Node
-       Method   *types.Field
-       Prealloc *Name
-}
-
-func NewCallPartExpr(pos src.XPos, x Node, method *types.Field, fn *Func) *CallPartExpr {
-       n := &CallPartExpr{Func: fn, X: x, Method: method}
-       n.op = OCALLPART
-       n.pos = pos
-       n.typ = fn.Type()
-       n.Func = fn
-       return n
-}
-
-func (n *CallPartExpr) Sym() *types.Sym { return n.Method.Sym }
-
 // A ClosureExpr is a function literal expression.
 type ClosureExpr struct {
        miniExpr
@@ -476,24 +456,6 @@ func (n *MakeExpr) SetOp(op Op) {
        }
 }
 
-// A MethodExpr is a method expression T.M (where T is a type).
-type MethodExpr struct {
-       miniExpr
-       T         *types.Type
-       Method    *types.Field
-       FuncName_ *Name
-}
-
-func NewMethodExpr(pos src.XPos, t *types.Type, method *types.Field) *MethodExpr {
-       n := &MethodExpr{T: t, Method: method}
-       n.pos = pos
-       n.op = OMETHEXPR
-       return n
-}
-
-func (n *MethodExpr) FuncName() *Name { return n.FuncName_ }
-func (n *MethodExpr) Sym() *types.Sym { panic("MethodExpr.Sym") }
-
 // A NilExpr represents the predefined untyped constant nil.
 // (It may be copied and assigned a type, though.)
 type NilExpr struct {
@@ -567,12 +529,13 @@ func NewNameOffsetExpr(pos src.XPos, name *Name, offset int64, typ *types.Type)
        return n
 }
 
-// A SelectorExpr is a selector expression X.Sym.
+// A SelectorExpr is a selector expression X.Sel.
 type SelectorExpr struct {
        miniExpr
        X         Node
        Sel       *types.Sym
        Selection *types.Field
+       Prealloc  *Name // preallocated storage for OCALLPART, if any
 }
 
 func NewSelectorExpr(pos src.XPos, op Op, x Node, sel *types.Sym) *SelectorExpr {
@@ -586,7 +549,7 @@ func (n *SelectorExpr) SetOp(op Op) {
        switch op {
        default:
                panic(n.no("SetOp " + op.String()))
-       case ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT:
+       case OXDOT, ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OCALLPART, OMETHEXPR:
                n.op = op
        }
 }
@@ -596,6 +559,16 @@ func (n *SelectorExpr) Implicit() bool     { return n.flags&miniExprImplicit !=
 func (n *SelectorExpr) SetImplicit(b bool) { n.flags.set(miniExprImplicit, b) }
 func (n *SelectorExpr) Offset() int64      { return n.Selection.Offset }
 
+func (n *SelectorExpr) FuncName() *Name {
+       if n.Op() != OMETHEXPR {
+               panic(n.no("FuncName"))
+       }
+       fn := NewNameAt(n.Selection.Pos, MethodSym(n.X.Type(), n.Sel))
+       fn.Class_ = PFUNC
+       fn.SetType(n.Type())
+       return fn
+}
+
 // Before type-checking, bytes.Buffer is a SelectorExpr.
 // After type-checking it becomes a Name.
 func (*SelectorExpr) CanBeNtype() {}
@@ -1089,13 +1062,8 @@ func MethodExprName(n Node) *Name {
 // MethodFunc is like MethodName, but returns the types.Field instead.
 func MethodExprFunc(n Node) *types.Field {
        switch n.Op() {
-       case ODOTMETH:
+       case ODOTMETH, OMETHEXPR, OCALLPART:
                return n.(*SelectorExpr).Selection
-       case OMETHEXPR:
-               return n.(*MethodExpr).Method
-       case OCALLPART:
-               n := n.(*CallPartExpr)
-               return n.Method
        }
        base.Fatalf("unexpected node: %v (%v)", n, n.Op())
        panic("unreachable")
index 49f451a5d85a10e4796d5afd308cb73a8f0edb80..7680f05ad2bfc0df5adceab801f59e62452b6f7a 100644 (file)
@@ -630,10 +630,6 @@ func exprFmt(n Node, s fmt.State, prec int) {
        case OPACK, ONONAME:
                fmt.Fprint(s, n.Sym())
 
-       case OMETHEXPR:
-               n := n.(*MethodExpr)
-               fmt.Fprint(s, n.FuncName().Sym())
-
        case ONAMEOFFSET:
                n := n.(*NameOffsetExpr)
                fmt.Fprintf(s, "(%v)(%v@%d)", n.Type(), n.Name_, n.Offset_)
@@ -749,16 +745,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
                n := n.(*StructKeyExpr)
                fmt.Fprintf(s, "%v:%v", n.Field, n.Value)
 
-       case OCALLPART:
-               n := n.(*CallPartExpr)
-               exprFmt(n.X, s, nprec)
-               if n.Method.Sym == nil {
-                       fmt.Fprint(s, ".<nil>")
-                       return
-               }
-               fmt.Fprintf(s, ".%s", n.Method.Sym.Name)
-
-       case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
+       case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH, OCALLPART, OMETHEXPR:
                n := n.(*SelectorExpr)
                exprFmt(n.X, s, nprec)
                if n.Sel == nil {
@@ -1160,12 +1147,6 @@ func dumpNode(w io.Writer, n Node, depth int) {
                }
                return
 
-       case OMETHEXPR:
-               n := n.(*MethodExpr)
-               fmt.Fprintf(w, "%+v-%+v", n.Op(), n.FuncName().Sym())
-               dumpNodeHeader(w, n)
-               return
-
        case OASOP:
                n := n.(*AssignOpStmt)
                fmt.Fprintf(w, "%+v-%+v", n.Op(), n.AsOp)
index 27a5311748c2565f79fd7bf87a4d2abc0dacdd99..a1ce9a4e9dddb647b72b9969879fd524963d65ad 100644 (file)
@@ -209,23 +209,6 @@ func (n *CallExpr) editChildren(edit func(Node) Node) {
        editList(n.Body, edit)
 }
 
-func (n *CallPartExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
-func (n *CallPartExpr) copy() Node {
-       c := *n
-       c.init = c.init.Copy()
-       return &c
-}
-func (n *CallPartExpr) doChildren(do func(Node) error) error {
-       var err error
-       err = maybeDoList(n.init, err, do)
-       err = maybeDo(n.X, err, do)
-       return err
-}
-func (n *CallPartExpr) editChildren(edit func(Node) Node) {
-       editList(n.init, edit)
-       n.X = maybeEdit(n.X, edit)
-}
-
 func (n *CaseClause) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
 func (n *CaseClause) copy() Node {
        c := *n
@@ -655,21 +638,6 @@ func (n *MapType) editChildren(edit func(Node) Node) {
        n.Elem = maybeEdit(n.Elem, edit)
 }
 
-func (n *MethodExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
-func (n *MethodExpr) copy() Node {
-       c := *n
-       c.init = c.init.Copy()
-       return &c
-}
-func (n *MethodExpr) doChildren(do func(Node) error) error {
-       var err error
-       err = maybeDoList(n.init, err, do)
-       return err
-}
-func (n *MethodExpr) editChildren(edit func(Node) Node) {
-       editList(n.init, edit)
-}
-
 func (n *Name) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
 func (n *Name) copy() Node                    { panic("Name.copy") }
 func (n *Name) doChildren(do func(Node) error) error {
index 2711f6cec0a9ec06930119f9a660b1c0da7b78e2..d8f51766deee17fbe2152d1e41117b9f1af33612 100644 (file)
@@ -104,7 +104,7 @@ func (s *Schedule) staticcopy(l *ir.Name, loff int64, rn *ir.Name, typ *types.Ty
 
        switch r.Op() {
        case ir.OMETHEXPR:
-               r = r.(*ir.MethodExpr).FuncName()
+               r = r.(*ir.SelectorExpr).FuncName()
                fallthrough
        case ir.ONAME:
                r := r.(*ir.Name)
@@ -165,7 +165,7 @@ func (s *Schedule) staticcopy(l *ir.Name, loff int64, rn *ir.Name, typ *types.Ty
                        }
                        x := e.Expr
                        if x.Op() == ir.OMETHEXPR {
-                               x = x.(*ir.MethodExpr).FuncName()
+                               x = x.(*ir.SelectorExpr).FuncName()
                        }
                        if x.Op() == ir.ONAME && s.staticcopy(l, loff+e.Xoffset, x.(*ir.Name), typ) {
                                continue
@@ -195,7 +195,7 @@ func (s *Schedule) StaticAssign(l *ir.Name, loff int64, r ir.Node, typ *types.Ty
                return s.staticcopy(l, loff, r, typ)
 
        case ir.OMETHEXPR:
-               r := r.(*ir.MethodExpr)
+               r := r.(*ir.SelectorExpr)
                return s.staticcopy(l, loff, r.FuncName(), typ)
 
        case ir.ONIL:
@@ -461,7 +461,7 @@ func StaticLoc(n ir.Node) (name *ir.Name, offset int64, ok bool) {
                return n, 0, true
 
        case ir.OMETHEXPR:
-               n := n.(*ir.MethodExpr)
+               n := n.(*ir.SelectorExpr)
                return StaticLoc(n.FuncName())
 
        case ir.ODOT:
index 3e7a880c2a466a2e032b2c70425afd980ee82b1a..0682548c273679f630d18c3d5546e7460277c588 100644 (file)
@@ -626,10 +626,8 @@ func tcDot(n *ir.SelectorExpr, top int) ir.Node {
        }
 
        if (n.Op() == ir.ODOTINTER || n.Op() == ir.ODOTMETH) && top&ctxCallee == 0 {
-               // Create top-level function.
-               fn := makepartialcall(n)
-
-               return ir.NewCallPartExpr(n.Pos(), n.X, n.Selection, fn)
+               n.SetOp(ir.OCALLPART)
+               n.SetType(MethodValueWrapper(n).Type())
        }
        return n
 }
index ed4f3ad4fe9e780aa3d196459120c4e47e0dc942..c58fef10ecd21950a602db25312572a7ec868461 100644 (file)
@@ -91,7 +91,7 @@ func ClosureType(clo *ir.ClosureExpr) *types.Type {
 // PartialCallType returns the struct type used to hold all the information
 // needed in the closure for n (n must be a OCALLPART node).
 // The address of a variable of the returned type can be cast to a func.
-func PartialCallType(n *ir.CallPartExpr) *types.Type {
+func PartialCallType(n *ir.SelectorExpr) *types.Type {
        t := types.NewStruct(types.NoPkg, []*types.Field{
                types.NewField(base.Pos, Lookup("F"), types.Types[types.TUINTPTR]),
                types.NewField(base.Pos, Lookup("R"), n.X.Type()),
@@ -247,9 +247,17 @@ func closurename(outerfunc *ir.Func) *types.Sym {
 // globClosgen is like Func.Closgen, but for the global scope.
 var globClosgen int32
 
-// makepartialcall returns a DCLFUNC node representing the wrapper function (*-fm) needed
-// for partial calls.
-func makepartialcall(dot *ir.SelectorExpr) *ir.Func {
+// MethodValueWrapper returns the DCLFUNC node representing the
+// wrapper function (*-fm) needed for the given method value. If the
+// wrapper function hasn't already been created yet, it's created and
+// added to Target.Decls.
+//
+// TODO(mdempsky): Move into walk. This isn't part of type checking.
+func MethodValueWrapper(dot *ir.SelectorExpr) *ir.Func {
+       if dot.Op() != ir.OCALLPART {
+               base.Fatalf("MethodValueWrapper: unexpected %v (%v)", dot, dot.Op())
+       }
+
        t0 := dot.Type()
        meth := dot.Sel
        rcvrtype := dot.X.Type()
index 3b071a61abbd456af9bdec5aabcfd9b64767308b..e35cbcafa25e532166a8dd47df2d31732fc73fb9 100644 (file)
@@ -1252,17 +1252,6 @@ func (w *exportWriter) expr(n ir.Node) {
                w.pos(n.Pos())
                w.value(n.Type(), n.Val())
 
-       case ir.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.
-               n := n.(*ir.MethodExpr)
-               w.op(ir.OXDOT)
-               w.pos(n.Pos())
-               w.op(ir.OTYPE)
-               w.typ(n.T) // n.Left.Op == OTYPE
-               w.selector(n.Method.Sym)
-
        case ir.ONAME:
                // Package scope name.
                n := n.(*ir.Name)
@@ -1336,15 +1325,7 @@ func (w *exportWriter) expr(n ir.Node) {
        // case OSTRUCTKEY:
        //      unreachable - handled in case OSTRUCTLIT by elemList
 
-       case ir.OCALLPART:
-               // An OCALLPART is an OXDOT before type checking.
-               n := n.(*ir.CallPartExpr)
-               w.op(ir.OXDOT)
-               w.pos(n.Pos())
-               w.expr(n.X)
-               w.selector(n.Method.Sym)
-
-       case ir.OXDOT, ir.ODOT, ir.ODOTPTR, ir.ODOTINTER, ir.ODOTMETH:
+       case ir.OXDOT, ir.ODOT, ir.ODOTPTR, ir.ODOTINTER, ir.ODOTMETH, ir.OCALLPART, ir.OMETHEXPR:
                n := n.(*ir.SelectorExpr)
                w.op(ir.OXDOT)
                w.pos(n.Pos())
index e23c249ff2b90465e7cb29c32e6bd2209a87411d..ff9178b5972f718fb70bcd963fb76aa94e9ff2df 100644 (file)
@@ -1176,19 +1176,16 @@ func typecheckMethodExpr(n *ir.SelectorExpr) (res ir.Node) {
                return n
        }
 
-       me := ir.NewMethodExpr(n.Pos(), n.X.Type(), m)
-       me.SetType(NewMethodType(m.Type, n.X.Type()))
-       f := NewName(ir.MethodSym(t, m.Sym))
-       f.Class_ = ir.PFUNC
-       f.SetType(me.Type())
-       me.FuncName_ = f
+       n.SetOp(ir.OMETHEXPR)
+       n.Selection = m
+       n.SetType(NewMethodType(m.Type, n.X.Type()))
 
        // Issue 25065. Make sure that we emit the symbol for a local method.
        if base.Ctxt.Flag_dynlink && !inimport && (t.Sym() == nil || t.Sym().Pkg == types.LocalPkg) {
-               NeedFuncSym(me.FuncName_.Sym())
+               NeedFuncSym(n.FuncName().Sym())
        }
 
-       return me
+       return n
 }
 
 func derefall(t *types.Type) *types.Type {
@@ -1422,7 +1419,7 @@ notenough:
                        // Method expressions have the form T.M, and the compiler has
                        // rewritten those to ONAME nodes but left T in Left.
                        if call.Op() == ir.OMETHEXPR {
-                               call := call.(*ir.MethodExpr)
+                               call := call.(*ir.SelectorExpr)
                                base.Errorf("not enough arguments in call to method expression %v%s", call, details)
                        } else {
                                base.Errorf("not enough arguments in call to %v%s", call, details)
index 30f86f0965a78ae1f38116074a10cff00e06a1dc..9bcb82bc036693164ce49d2ef184b04f088a3aed 100644 (file)
@@ -151,7 +151,7 @@ func walkClosure(clo *ir.ClosureExpr, init *ir.Nodes) ir.Node {
        return walkExpr(cfn, init)
 }
 
-func walkCallPart(n *ir.CallPartExpr, init *ir.Nodes) ir.Node {
+func walkCallPart(n *ir.SelectorExpr, init *ir.Nodes) ir.Node {
        // Create closure in the form of a composite literal.
        // For x.M with receiver (x) type T, the generated code looks like:
        //
@@ -176,7 +176,7 @@ func walkCallPart(n *ir.CallPartExpr, init *ir.Nodes) ir.Node {
 
        clos := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ).(ir.Ntype), nil)
        clos.SetEsc(n.Esc())
-       clos.List = []ir.Node{ir.NewUnaryExpr(base.Pos, ir.OCFUNC, n.Func.Nname), n.X}
+       clos.List = []ir.Node{ir.NewUnaryExpr(base.Pos, ir.OCFUNC, typecheck.MethodValueWrapper(n).Nname), n.X}
 
        addr := typecheck.NodAddr(clos)
        addr.SetEsc(n.Esc())
index 8c4f9583ef5df7075caa056b434cc25272812a70..fadcd87f258033824c161fa4a497864251199bd4 100644 (file)
@@ -539,7 +539,7 @@ func anylit(n ir.Node, var_ ir.Node, init *ir.Nodes) {
                appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, n))
 
        case ir.OMETHEXPR:
-               n := n.(*ir.MethodExpr)
+               n := n.(*ir.SelectorExpr)
                anylit(n.FuncName(), var_, init)
 
        case ir.OPTRLIT:
@@ -666,7 +666,7 @@ func genAsStatic(as *ir.AssignStmt) {
                staticdata.InitConst(name, offset, r, int(r.Type().Width))
                return
        case ir.OMETHEXPR:
-               r := r.(*ir.MethodExpr)
+               r := r.(*ir.SelectorExpr)
                staticdata.InitFunc(name, offset, r.FuncName())
                return
        case ir.ONAME:
index fd0dd5b06248a2563c1e0f496e1cb0c2d65519d4..7cc67580248b5196908c15caa44818fa965938d9 100644 (file)
@@ -100,7 +100,7 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node {
 
        case ir.OMETHEXPR:
                // TODO(mdempsky): Do this right after type checking.
-               n := n.(*ir.MethodExpr)
+               n := n.(*ir.SelectorExpr)
                return n.FuncName()
 
        case ir.ONOT, ir.ONEG, ir.OPLUS, ir.OBITNOT, ir.OREAL, ir.OIMAG, ir.OSPTR, ir.OITAB, ir.OIDATA:
@@ -306,7 +306,7 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node {
                return walkClosure(n.(*ir.ClosureExpr), init)
 
        case ir.OCALLPART:
-               return walkCallPart(n.(*ir.CallPartExpr), init)
+               return walkCallPart(n.(*ir.SelectorExpr), init)
        }
 
        // No return! Each case must return (or panic),
index ebbd4675701451a9c5f603e7556032542c04cee7..0dd76ccee9a9bc0980dba6dd3e8a169cd4f014ea 100644 (file)
@@ -1310,7 +1310,7 @@ func (o *orderState) expr1(n, lhs ir.Node) ir.Node {
                return n
 
        case ir.OCALLPART:
-               n := n.(*ir.CallPartExpr)
+               n := n.(*ir.SelectorExpr)
                n.X = o.expr(n.X, nil)
                if n.Transient() {
                        t := typecheck.PartialCallType(n)