diff --git a/go/ssa/builder.go b/go/ssa/builder.go index 06c4389fd71..de8916005d1 100644 --- a/go/ssa/builder.go +++ b/go/ssa/builder.go @@ -443,8 +443,8 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue { return b.addr(fn, e.X, escaping) case *ast.SelectorExpr: - sel, ok := fn.info.Selections[e] - if !ok { + sel := fn.selection(e) + if sel == nil { // qualified identifier return b.addr(fn, e.Sel, escaping) } @@ -786,8 +786,8 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value { return emitLoad(fn, fn.lookup(obj, false)) // var (address) case *ast.SelectorExpr: - sel, ok := fn.info.Selections[e] - if !ok { + sel := fn.selection(e) + if sel == nil { // builtin unsafe.{Add,Slice} if obj, ok := fn.info.Uses[e.Sel].(*types.Builtin); ok { return &Builtin{name: obj.Name(), sig: fn.typ(tv.Type).(*types.Signature)} @@ -799,28 +799,12 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value { case types.MethodExpr: // (*T).f or T.f, the method f from the method-set of type T. // The result is a "thunk". - - sel := selection(sel) - if base := fn.typ(sel.Recv()); base != sel.Recv() { - // instantiate sel as sel.Recv is not equal after substitution. - pkg := fn.declaredPackage().Pkg - // mv is the instantiated method value. - mv := types.NewMethodSet(base).Lookup(pkg, sel.Obj().Name()) - sel = toMethodExpr(mv) - } thunk := makeThunk(fn.Prog, sel, b.created) return emitConv(fn, thunk, fn.typ(tv.Type)) case types.MethodVal: // e.f where e is an expression and f is a method. // The result is a "bound". - - if base := fn.typ(sel.Recv()); base != sel.Recv() { - // instantiate sel as sel.Recv is not equal after substitution. - pkg := fn.declaredPackage().Pkg - // mv is the instantiated method value. - sel = types.NewMethodSet(base).Lookup(pkg, sel.Obj().Name()) - } obj := sel.Obj().(*types.Func) rt := fn.typ(recvType(obj)) wantAddr := isPointer(rt) @@ -939,7 +923,7 @@ func (b *builder) stmtList(fn *Function, list []ast.Stmt) { // must thus be addressable. // // escaping is defined as per builder.addr(). -func (b *builder) receiver(fn *Function, e ast.Expr, wantAddr, escaping bool, sel *types.Selection) Value { +func (b *builder) receiver(fn *Function, e ast.Expr, wantAddr, escaping bool, sel *selection) Value { var v Value if wantAddr && !sel.Indirect() && !isPointer(fn.typeOf(e)) { v = b.addr(fn, e, escaping).address(fn) @@ -964,15 +948,9 @@ func (b *builder) setCallFunc(fn *Function, e *ast.CallExpr, c *CallCommon) { // Is this a method call? if selector, ok := unparen(e.Fun).(*ast.SelectorExpr); ok { - sel, ok := fn.info.Selections[selector] - if ok && sel.Kind() == types.MethodVal { + sel := fn.selection(selector) + if sel != nil && sel.Kind() == types.MethodVal { obj := sel.Obj().(*types.Func) - if recv := fn.typ(sel.Recv()); recv != sel.Recv() { - // adjust obj if the sel.Recv() changed during monomorphization. - pkg := fn.declaredPackage().Pkg - method, _, _ := types.LookupFieldOrMethod(recv, true, pkg, sel.Obj().Name()) - obj = method.(*types.Func) - } recv := recvType(obj) wantAddr := isPointer(recv) diff --git a/go/ssa/func.go b/go/ssa/func.go index 9ce2bfe410b..84d8113d931 100644 --- a/go/ssa/func.go +++ b/go/ssa/func.go @@ -52,6 +52,40 @@ func (f *Function) instanceType(id *ast.Ident) types.Type { return f.typeOf(id) } +// selection returns a *selection corresponding to f.info.Selections[selector] +// with potential updates for type substitution. +func (f *Function) selection(selector *ast.SelectorExpr) *selection { + sel := f.info.Selections[selector] + if sel == nil { + return nil + } + + switch sel.Kind() { + case types.MethodExpr, types.MethodVal: + if recv := f.typ(sel.Recv()); recv != sel.Recv() { + // recv changed during type substitution. + pkg := f.declaredPackage().Pkg + obj, index, indirect := types.LookupFieldOrMethod(recv, true, pkg, sel.Obj().Name()) + + // sig replaces sel.Type(). See (types.Selection).Typ() for details. + sig := obj.Type().(*types.Signature) + sig = changeRecv(sig, newVar(sig.Recv().Name(), recv)) + if sel.Kind() == types.MethodExpr { + sig = recvAsFirstArg(sig) + } + return &selection{ + kind: sel.Kind(), + recv: recv, + typ: sig, + obj: obj, + index: index, + indirect: indirect, + } + } + } + return toSelection(sel) +} + // Destinations associated with unlabelled for/switch/select stmts. // We push/pop one of these as we enter/leave each construct and for // each BranchStmt we scan for the innermost target of the right type. diff --git a/go/ssa/methods.go b/go/ssa/methods.go index aedb41fc699..9af426111f7 100644 --- a/go/ssa/methods.go +++ b/go/ssa/methods.go @@ -98,6 +98,7 @@ func (prog *Program) addMethod(mset *methodSet, sel *types.Selection, cr *creato id := sel.Obj().Id() fn := mset.mapping[id] if fn == nil { + sel := toSelection(sel) obj := sel.Obj().(*types.Func) needsPromotion := len(sel.Index()) > 1 diff --git a/go/ssa/ssa.go b/go/ssa/ssa.go index c96ced22658..cbc638c81a8 100644 --- a/go/ssa/ssa.go +++ b/go/ssa/ssa.go @@ -307,7 +307,7 @@ type Node interface { type Function struct { name string object types.Object // a declared *types.Func or one of its wrappers - method selection // info about provenance of synthetic methods + method *selection // info about provenance of synthetic methods; thunk => non-nil Signature *types.Signature pos token.Pos diff --git a/go/ssa/wrappers.go b/go/ssa/wrappers.go index f3305fcaef2..8896beb9b59 100644 --- a/go/ssa/wrappers.go +++ b/go/ssa/wrappers.go @@ -42,7 +42,7 @@ import ( // - the result may be a thunk or a wrapper. // // EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu) -func makeWrapper(prog *Program, sel selection, cr *creator) *Function { +func makeWrapper(prog *Program, sel *selection, cr *creator) *Function { obj := sel.Obj().(*types.Func) // the declared function sig := sel.Type().(*types.Signature) // type of this wrapper @@ -255,7 +255,7 @@ func makeBound(prog *Program, obj *types.Func, cr *creator) *Function { // than inlining the stub. // // EXCLUSIVE_LOCKS_ACQUIRED(meth.Prog.methodsMu) -func makeThunk(prog *Program, sel selection, cr *creator) *Function { +func makeThunk(prog *Program, sel *selection, cr *creator) *Function { if sel.Kind() != types.MethodExpr { panic(sel) } @@ -303,9 +303,10 @@ type boundsKey struct { inst *typeList // canonical type instantiation list. } -// methodExpr is an copy of a *types.Selection. -// This exists as there is no way to create MethodExpr's for an instantiation. -type methodExpr struct { +// A local version of *types.Selection. +// Needed for some additional control, such as creating a MethodExpr for an instantiation. +type selection struct { + kind types.SelectionKind recv types.Type typ types.Type obj types.Object @@ -313,33 +314,21 @@ type methodExpr struct { indirect bool } -func (*methodExpr) Kind() types.SelectionKind { return types.MethodExpr } -func (m *methodExpr) Type() types.Type { return m.typ } -func (m *methodExpr) Recv() types.Type { return m.recv } -func (m *methodExpr) Obj() types.Object { return m.obj } -func (m *methodExpr) Index() []int { return m.index } -func (m *methodExpr) Indirect() bool { return m.indirect } - -// create MethodExpr from a MethodValue. -func toMethodExpr(mv *types.Selection) *methodExpr { - if mv.Kind() != types.MethodVal { - panic(mv) - } - return &methodExpr{ - recv: mv.Recv(), - typ: recvAsFirstArg(mv.Type().(*types.Signature)), - obj: mv.Obj(), - index: mv.Index(), - indirect: mv.Indirect(), - } -} +// TODO(taking): inline and eliminate. +func (sel *selection) Kind() types.SelectionKind { return sel.kind } +func (sel *selection) Type() types.Type { return sel.typ } +func (sel *selection) Recv() types.Type { return sel.recv } +func (sel *selection) Obj() types.Object { return sel.obj } +func (sel *selection) Index() []int { return sel.index } +func (sel *selection) Indirect() bool { return sel.indirect } -// generalization of a *types.Selection and a methodExpr. -type selection interface { - Kind() types.SelectionKind - Type() types.Type - Recv() types.Type - Obj() types.Object - Index() []int - Indirect() bool +func toSelection(sel *types.Selection) *selection { + return &selection{ + kind: sel.Kind(), + recv: sel.Recv(), + typ: sel.Type(), + obj: sel.Obj(), + index: sel.Index(), + indirect: sel.Indirect(), + } }