mirror of
https://github.com/golang/go.git
synced 2025-11-11 22:21:06 +00:00
[dev.regabi] cmd/compile: merge {Selector,CallPart,Method}Expr
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>
This commit is contained in:
parent
e563715b30
commit
4629f6a51d
14 changed files with 58 additions and 154 deletions
|
|
@ -612,10 +612,10 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) {
|
||||||
// Flow the receiver argument to both the closure and
|
// Flow the receiver argument to both the closure and
|
||||||
// to the receiver parameter.
|
// to the receiver parameter.
|
||||||
|
|
||||||
n := n.(*ir.CallPartExpr)
|
n := n.(*ir.SelectorExpr)
|
||||||
closureK := e.spill(k, n)
|
closureK := e.spill(k, n)
|
||||||
|
|
||||||
m := n.Method
|
m := n.Selection
|
||||||
|
|
||||||
// We don't know how the method value will be called
|
// We don't know how the method value will be called
|
||||||
// later, so conservatively assume the result
|
// later, so conservatively assume the result
|
||||||
|
|
@ -1542,7 +1542,7 @@ func (e *escape) finish(fns []*ir.Func) {
|
||||||
n := n.(*ir.ClosureExpr)
|
n := n.(*ir.ClosureExpr)
|
||||||
n.SetTransient(true)
|
n.SetTransient(true)
|
||||||
case ir.OCALLPART:
|
case ir.OCALLPART:
|
||||||
n := n.(*ir.CallPartExpr)
|
n := n.(*ir.SelectorExpr)
|
||||||
n.SetTransient(true)
|
n.SetTransient(true)
|
||||||
case ir.OSLICELIT:
|
case ir.OSLICELIT:
|
||||||
n := n.(*ir.CompLitExpr)
|
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 {
|
if n.Op() == ir.OCLOSURE && typecheck.ClosureType(n.(*ir.ClosureExpr)).Size() >= ir.MaxImplicitStackVarSize {
|
||||||
return "too large for stack"
|
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"
|
return "too large for stack"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -419,6 +419,9 @@ func (v *hairyVisitor) doNode(n ir.Node) error {
|
||||||
|
|
||||||
case ir.OCALLPART, ir.OSLICELIT:
|
case ir.OCALLPART, ir.OSLICELIT:
|
||||||
v.budget-- // Hack for toolstash -cmp.
|
v.budget-- // Hack for toolstash -cmp.
|
||||||
|
|
||||||
|
case ir.OMETHEXPR:
|
||||||
|
v.budget++ // Hack for toolstash -cmp.
|
||||||
}
|
}
|
||||||
|
|
||||||
v.budget--
|
v.budget--
|
||||||
|
|
@ -613,12 +616,12 @@ func inlCallee(fn ir.Node) *ir.Func {
|
||||||
fn = ir.StaticValue(fn)
|
fn = ir.StaticValue(fn)
|
||||||
switch fn.Op() {
|
switch fn.Op() {
|
||||||
case ir.OMETHEXPR:
|
case ir.OMETHEXPR:
|
||||||
fn := fn.(*ir.MethodExpr)
|
fn := fn.(*ir.SelectorExpr)
|
||||||
n := ir.MethodExprName(fn)
|
n := ir.MethodExprName(fn)
|
||||||
// Check that receiver type matches fn.Left.
|
// Check that receiver type matches fn.X.
|
||||||
// TODO(mdempsky): Handle implicit dereference
|
// TODO(mdempsky): Handle implicit dereference
|
||||||
// of pointer receiver argument?
|
// 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 nil
|
||||||
}
|
}
|
||||||
return n.Func
|
return n.Func
|
||||||
|
|
@ -1098,7 +1101,7 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case ir.OMETHEXPR:
|
case ir.OMETHEXPR:
|
||||||
n := n.(*ir.MethodExpr)
|
n := n.(*ir.SelectorExpr)
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case ir.OLITERAL, ir.ONIL, ir.OTYPE:
|
case ir.OLITERAL, ir.ONIL, ir.OTYPE:
|
||||||
|
|
|
||||||
|
|
@ -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.
|
// A ClosureExpr is a function literal expression.
|
||||||
type ClosureExpr struct {
|
type ClosureExpr struct {
|
||||||
miniExpr
|
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.
|
// A NilExpr represents the predefined untyped constant nil.
|
||||||
// (It may be copied and assigned a type, though.)
|
// (It may be copied and assigned a type, though.)
|
||||||
type NilExpr struct {
|
type NilExpr struct {
|
||||||
|
|
@ -567,12 +529,13 @@ func NewNameOffsetExpr(pos src.XPos, name *Name, offset int64, typ *types.Type)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// A SelectorExpr is a selector expression X.Sym.
|
// A SelectorExpr is a selector expression X.Sel.
|
||||||
type SelectorExpr struct {
|
type SelectorExpr struct {
|
||||||
miniExpr
|
miniExpr
|
||||||
X Node
|
X Node
|
||||||
Sel *types.Sym
|
Sel *types.Sym
|
||||||
Selection *types.Field
|
Selection *types.Field
|
||||||
|
Prealloc *Name // preallocated storage for OCALLPART, if any
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSelectorExpr(pos src.XPos, op Op, x Node, sel *types.Sym) *SelectorExpr {
|
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 {
|
switch op {
|
||||||
default:
|
default:
|
||||||
panic(n.no("SetOp " + op.String()))
|
panic(n.no("SetOp " + op.String()))
|
||||||
case ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT:
|
case OXDOT, ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OCALLPART, OMETHEXPR:
|
||||||
n.op = op
|
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) SetImplicit(b bool) { n.flags.set(miniExprImplicit, b) }
|
||||||
func (n *SelectorExpr) Offset() int64 { return n.Selection.Offset }
|
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.
|
// Before type-checking, bytes.Buffer is a SelectorExpr.
|
||||||
// After type-checking it becomes a Name.
|
// After type-checking it becomes a Name.
|
||||||
func (*SelectorExpr) CanBeNtype() {}
|
func (*SelectorExpr) CanBeNtype() {}
|
||||||
|
|
@ -1089,13 +1062,8 @@ func MethodExprName(n Node) *Name {
|
||||||
// MethodFunc is like MethodName, but returns the types.Field instead.
|
// MethodFunc is like MethodName, but returns the types.Field instead.
|
||||||
func MethodExprFunc(n Node) *types.Field {
|
func MethodExprFunc(n Node) *types.Field {
|
||||||
switch n.Op() {
|
switch n.Op() {
|
||||||
case ODOTMETH:
|
case ODOTMETH, OMETHEXPR, OCALLPART:
|
||||||
return n.(*SelectorExpr).Selection
|
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())
|
base.Fatalf("unexpected node: %v (%v)", n, n.Op())
|
||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
|
|
|
||||||
|
|
@ -630,10 +630,6 @@ func exprFmt(n Node, s fmt.State, prec int) {
|
||||||
case OPACK, ONONAME:
|
case OPACK, ONONAME:
|
||||||
fmt.Fprint(s, n.Sym())
|
fmt.Fprint(s, n.Sym())
|
||||||
|
|
||||||
case OMETHEXPR:
|
|
||||||
n := n.(*MethodExpr)
|
|
||||||
fmt.Fprint(s, n.FuncName().Sym())
|
|
||||||
|
|
||||||
case ONAMEOFFSET:
|
case ONAMEOFFSET:
|
||||||
n := n.(*NameOffsetExpr)
|
n := n.(*NameOffsetExpr)
|
||||||
fmt.Fprintf(s, "(%v)(%v@%d)", n.Type(), n.Name_, n.Offset_)
|
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)
|
n := n.(*StructKeyExpr)
|
||||||
fmt.Fprintf(s, "%v:%v", n.Field, n.Value)
|
fmt.Fprintf(s, "%v:%v", n.Field, n.Value)
|
||||||
|
|
||||||
case OCALLPART:
|
case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH, OCALLPART, OMETHEXPR:
|
||||||
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:
|
|
||||||
n := n.(*SelectorExpr)
|
n := n.(*SelectorExpr)
|
||||||
exprFmt(n.X, s, nprec)
|
exprFmt(n.X, s, nprec)
|
||||||
if n.Sel == nil {
|
if n.Sel == nil {
|
||||||
|
|
@ -1160,12 +1147,6 @@ func dumpNode(w io.Writer, n Node, depth int) {
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|
||||||
case OMETHEXPR:
|
|
||||||
n := n.(*MethodExpr)
|
|
||||||
fmt.Fprintf(w, "%+v-%+v", n.Op(), n.FuncName().Sym())
|
|
||||||
dumpNodeHeader(w, n)
|
|
||||||
return
|
|
||||||
|
|
||||||
case OASOP:
|
case OASOP:
|
||||||
n := n.(*AssignOpStmt)
|
n := n.(*AssignOpStmt)
|
||||||
fmt.Fprintf(w, "%+v-%+v", n.Op(), n.AsOp)
|
fmt.Fprintf(w, "%+v-%+v", n.Op(), n.AsOp)
|
||||||
|
|
|
||||||
|
|
@ -209,23 +209,6 @@ func (n *CallExpr) editChildren(edit func(Node) Node) {
|
||||||
editList(n.Body, edit)
|
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) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
|
||||||
func (n *CaseClause) copy() Node {
|
func (n *CaseClause) copy() Node {
|
||||||
c := *n
|
c := *n
|
||||||
|
|
@ -655,21 +638,6 @@ func (n *MapType) editChildren(edit func(Node) Node) {
|
||||||
n.Elem = maybeEdit(n.Elem, edit)
|
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) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
|
||||||
func (n *Name) copy() Node { panic("Name.copy") }
|
func (n *Name) copy() Node { panic("Name.copy") }
|
||||||
func (n *Name) doChildren(do func(Node) error) error {
|
func (n *Name) doChildren(do func(Node) error) error {
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ func (s *Schedule) staticcopy(l *ir.Name, loff int64, rn *ir.Name, typ *types.Ty
|
||||||
|
|
||||||
switch r.Op() {
|
switch r.Op() {
|
||||||
case ir.OMETHEXPR:
|
case ir.OMETHEXPR:
|
||||||
r = r.(*ir.MethodExpr).FuncName()
|
r = r.(*ir.SelectorExpr).FuncName()
|
||||||
fallthrough
|
fallthrough
|
||||||
case ir.ONAME:
|
case ir.ONAME:
|
||||||
r := r.(*ir.Name)
|
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
|
x := e.Expr
|
||||||
if x.Op() == ir.OMETHEXPR {
|
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) {
|
if x.Op() == ir.ONAME && s.staticcopy(l, loff+e.Xoffset, x.(*ir.Name), typ) {
|
||||||
continue
|
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)
|
return s.staticcopy(l, loff, r, typ)
|
||||||
|
|
||||||
case ir.OMETHEXPR:
|
case ir.OMETHEXPR:
|
||||||
r := r.(*ir.MethodExpr)
|
r := r.(*ir.SelectorExpr)
|
||||||
return s.staticcopy(l, loff, r.FuncName(), typ)
|
return s.staticcopy(l, loff, r.FuncName(), typ)
|
||||||
|
|
||||||
case ir.ONIL:
|
case ir.ONIL:
|
||||||
|
|
@ -461,7 +461,7 @@ func StaticLoc(n ir.Node) (name *ir.Name, offset int64, ok bool) {
|
||||||
return n, 0, true
|
return n, 0, true
|
||||||
|
|
||||||
case ir.OMETHEXPR:
|
case ir.OMETHEXPR:
|
||||||
n := n.(*ir.MethodExpr)
|
n := n.(*ir.SelectorExpr)
|
||||||
return StaticLoc(n.FuncName())
|
return StaticLoc(n.FuncName())
|
||||||
|
|
||||||
case ir.ODOT:
|
case ir.ODOT:
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
if (n.Op() == ir.ODOTINTER || n.Op() == ir.ODOTMETH) && top&ctxCallee == 0 {
|
||||||
// Create top-level function.
|
n.SetOp(ir.OCALLPART)
|
||||||
fn := makepartialcall(n)
|
n.SetType(MethodValueWrapper(n).Type())
|
||||||
|
|
||||||
return ir.NewCallPartExpr(n.Pos(), n.X, n.Selection, fn)
|
|
||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ func ClosureType(clo *ir.ClosureExpr) *types.Type {
|
||||||
// PartialCallType returns the struct type used to hold all the information
|
// PartialCallType returns the struct type used to hold all the information
|
||||||
// needed in the closure for n (n must be a OCALLPART node).
|
// 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.
|
// 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{
|
t := types.NewStruct(types.NoPkg, []*types.Field{
|
||||||
types.NewField(base.Pos, Lookup("F"), types.Types[types.TUINTPTR]),
|
types.NewField(base.Pos, Lookup("F"), types.Types[types.TUINTPTR]),
|
||||||
types.NewField(base.Pos, Lookup("R"), n.X.Type()),
|
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.
|
// globClosgen is like Func.Closgen, but for the global scope.
|
||||||
var globClosgen int32
|
var globClosgen int32
|
||||||
|
|
||||||
// makepartialcall returns a DCLFUNC node representing the wrapper function (*-fm) needed
|
// MethodValueWrapper returns the DCLFUNC node representing the
|
||||||
// for partial calls.
|
// wrapper function (*-fm) needed for the given method value. If the
|
||||||
func makepartialcall(dot *ir.SelectorExpr) *ir.Func {
|
// 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()
|
t0 := dot.Type()
|
||||||
meth := dot.Sel
|
meth := dot.Sel
|
||||||
rcvrtype := dot.X.Type()
|
rcvrtype := dot.X.Type()
|
||||||
|
|
|
||||||
|
|
@ -1252,17 +1252,6 @@ func (w *exportWriter) expr(n ir.Node) {
|
||||||
w.pos(n.Pos())
|
w.pos(n.Pos())
|
||||||
w.value(n.Type(), n.Val())
|
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:
|
case ir.ONAME:
|
||||||
// Package scope name.
|
// Package scope name.
|
||||||
n := n.(*ir.Name)
|
n := n.(*ir.Name)
|
||||||
|
|
@ -1336,15 +1325,7 @@ func (w *exportWriter) expr(n ir.Node) {
|
||||||
// case OSTRUCTKEY:
|
// case OSTRUCTKEY:
|
||||||
// unreachable - handled in case OSTRUCTLIT by elemList
|
// unreachable - handled in case OSTRUCTLIT by elemList
|
||||||
|
|
||||||
case ir.OCALLPART:
|
case ir.OXDOT, ir.ODOT, ir.ODOTPTR, ir.ODOTINTER, ir.ODOTMETH, ir.OCALLPART, ir.OMETHEXPR:
|
||||||
// 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:
|
|
||||||
n := n.(*ir.SelectorExpr)
|
n := n.(*ir.SelectorExpr)
|
||||||
w.op(ir.OXDOT)
|
w.op(ir.OXDOT)
|
||||||
w.pos(n.Pos())
|
w.pos(n.Pos())
|
||||||
|
|
|
||||||
|
|
@ -1176,19 +1176,16 @@ func typecheckMethodExpr(n *ir.SelectorExpr) (res ir.Node) {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
me := ir.NewMethodExpr(n.Pos(), n.X.Type(), m)
|
n.SetOp(ir.OMETHEXPR)
|
||||||
me.SetType(NewMethodType(m.Type, n.X.Type()))
|
n.Selection = m
|
||||||
f := NewName(ir.MethodSym(t, m.Sym))
|
n.SetType(NewMethodType(m.Type, n.X.Type()))
|
||||||
f.Class_ = ir.PFUNC
|
|
||||||
f.SetType(me.Type())
|
|
||||||
me.FuncName_ = f
|
|
||||||
|
|
||||||
// Issue 25065. Make sure that we emit the symbol for a local method.
|
// 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) {
|
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 {
|
func derefall(t *types.Type) *types.Type {
|
||||||
|
|
@ -1422,7 +1419,7 @@ notenough:
|
||||||
// Method expressions have the form T.M, and the compiler has
|
// Method expressions have the form T.M, and the compiler has
|
||||||
// rewritten those to ONAME nodes but left T in Left.
|
// rewritten those to ONAME nodes but left T in Left.
|
||||||
if call.Op() == ir.OMETHEXPR {
|
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)
|
base.Errorf("not enough arguments in call to method expression %v%s", call, details)
|
||||||
} else {
|
} else {
|
||||||
base.Errorf("not enough arguments in call to %v%s", call, details)
|
base.Errorf("not enough arguments in call to %v%s", call, details)
|
||||||
|
|
|
||||||
|
|
@ -151,7 +151,7 @@ func walkClosure(clo *ir.ClosureExpr, init *ir.Nodes) ir.Node {
|
||||||
return walkExpr(cfn, init)
|
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.
|
// Create closure in the form of a composite literal.
|
||||||
// For x.M with receiver (x) type T, the generated code looks like:
|
// 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 := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ).(ir.Ntype), nil)
|
||||||
clos.SetEsc(n.Esc())
|
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 := typecheck.NodAddr(clos)
|
||||||
addr.SetEsc(n.Esc())
|
addr.SetEsc(n.Esc())
|
||||||
|
|
|
||||||
|
|
@ -539,7 +539,7 @@ func anylit(n ir.Node, var_ ir.Node, init *ir.Nodes) {
|
||||||
appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, n))
|
appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, n))
|
||||||
|
|
||||||
case ir.OMETHEXPR:
|
case ir.OMETHEXPR:
|
||||||
n := n.(*ir.MethodExpr)
|
n := n.(*ir.SelectorExpr)
|
||||||
anylit(n.FuncName(), var_, init)
|
anylit(n.FuncName(), var_, init)
|
||||||
|
|
||||||
case ir.OPTRLIT:
|
case ir.OPTRLIT:
|
||||||
|
|
@ -666,7 +666,7 @@ func genAsStatic(as *ir.AssignStmt) {
|
||||||
staticdata.InitConst(name, offset, r, int(r.Type().Width))
|
staticdata.InitConst(name, offset, r, int(r.Type().Width))
|
||||||
return
|
return
|
||||||
case ir.OMETHEXPR:
|
case ir.OMETHEXPR:
|
||||||
r := r.(*ir.MethodExpr)
|
r := r.(*ir.SelectorExpr)
|
||||||
staticdata.InitFunc(name, offset, r.FuncName())
|
staticdata.InitFunc(name, offset, r.FuncName())
|
||||||
return
|
return
|
||||||
case ir.ONAME:
|
case ir.ONAME:
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node {
|
||||||
|
|
||||||
case ir.OMETHEXPR:
|
case ir.OMETHEXPR:
|
||||||
// TODO(mdempsky): Do this right after type checking.
|
// TODO(mdempsky): Do this right after type checking.
|
||||||
n := n.(*ir.MethodExpr)
|
n := n.(*ir.SelectorExpr)
|
||||||
return n.FuncName()
|
return n.FuncName()
|
||||||
|
|
||||||
case ir.ONOT, ir.ONEG, ir.OPLUS, ir.OBITNOT, ir.OREAL, ir.OIMAG, ir.OSPTR, ir.OITAB, ir.OIDATA:
|
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)
|
return walkClosure(n.(*ir.ClosureExpr), init)
|
||||||
|
|
||||||
case ir.OCALLPART:
|
case ir.OCALLPART:
|
||||||
return walkCallPart(n.(*ir.CallPartExpr), init)
|
return walkCallPart(n.(*ir.SelectorExpr), init)
|
||||||
}
|
}
|
||||||
|
|
||||||
// No return! Each case must return (or panic),
|
// No return! Each case must return (or panic),
|
||||||
|
|
|
||||||
|
|
@ -1310,7 +1310,7 @@ func (o *orderState) expr1(n, lhs ir.Node) ir.Node {
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case ir.OCALLPART:
|
case ir.OCALLPART:
|
||||||
n := n.(*ir.CallPartExpr)
|
n := n.(*ir.SelectorExpr)
|
||||||
n.X = o.expr(n.X, nil)
|
n.X = o.expr(n.X, nil)
|
||||||
if n.Transient() {
|
if n.Transient() {
|
||||||
t := typecheck.PartialCallType(n)
|
t := typecheck.PartialCallType(n)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue