// 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
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)
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"
}
case ir.OCALLPART, ir.OSLICELIT:
v.budget-- // Hack for toolstash -cmp.
+
+ case ir.OMETHEXPR:
+ v.budget++ // Hack for toolstash -cmp.
}
v.budget--
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
return n
case ir.OMETHEXPR:
- n := n.(*ir.MethodExpr)
+ n := n.(*ir.SelectorExpr)
return n
case ir.OLITERAL, ir.ONIL, ir.OTYPE:
}
}
-// 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
}
}
-// 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 {
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 {
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
}
}
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() {}
// 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")
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_)
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 {
}
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)
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
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 {
switch r.Op() {
case ir.OMETHEXPR:
- r = r.(*ir.MethodExpr).FuncName()
+ r = r.(*ir.SelectorExpr).FuncName()
fallthrough
case ir.ONAME:
r := r.(*ir.Name)
}
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
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:
return n, 0, true
case ir.OMETHEXPR:
- n := n.(*ir.MethodExpr)
+ n := n.(*ir.SelectorExpr)
return StaticLoc(n.FuncName())
case ir.ODOT:
}
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
}
// 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()),
// 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()
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)
// 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())
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 {
// 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)
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:
//
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())
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:
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:
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:
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),
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)