Skip to content

Commit 304195c

Browse files
committed
go/ssa: create *ssa.selection.
Simplifies handling *types.Selections by always using a *ssa.selection internally. Updates the selection during monomorphization. Updates golang/go#48525 Change-Id: If9cf7a623d3fed060dda41a5b65c46fcfe3d431c Reviewed-on: https://go-review.googlesource.com/c/tools/+/405557 Reviewed-by: Alan Donovan <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Robert Findley <[email protected]> gopls-CI: kokoro <[email protected]> Run-TryBot: Tim King <[email protected]>
1 parent f918e87 commit 304195c

File tree

5 files changed

+65
-63
lines changed

5 files changed

+65
-63
lines changed

go/ssa/builder.go

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -443,8 +443,8 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue {
443443
return b.addr(fn, e.X, escaping)
444444

445445
case *ast.SelectorExpr:
446-
sel, ok := fn.info.Selections[e]
447-
if !ok {
446+
sel := fn.selection(e)
447+
if sel == nil {
448448
// qualified identifier
449449
return b.addr(fn, e.Sel, escaping)
450450
}
@@ -786,8 +786,8 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value {
786786
return emitLoad(fn, fn.lookup(obj, false)) // var (address)
787787

788788
case *ast.SelectorExpr:
789-
sel, ok := fn.info.Selections[e]
790-
if !ok {
789+
sel := fn.selection(e)
790+
if sel == nil {
791791
// builtin unsafe.{Add,Slice}
792792
if obj, ok := fn.info.Uses[e.Sel].(*types.Builtin); ok {
793793
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 {
799799
case types.MethodExpr:
800800
// (*T).f or T.f, the method f from the method-set of type T.
801801
// The result is a "thunk".
802-
803-
sel := selection(sel)
804-
if base := fn.typ(sel.Recv()); base != sel.Recv() {
805-
// instantiate sel as sel.Recv is not equal after substitution.
806-
pkg := fn.declaredPackage().Pkg
807-
// mv is the instantiated method value.
808-
mv := types.NewMethodSet(base).Lookup(pkg, sel.Obj().Name())
809-
sel = toMethodExpr(mv)
810-
}
811802
thunk := makeThunk(fn.Prog, sel, b.created)
812803
return emitConv(fn, thunk, fn.typ(tv.Type))
813804

814805
case types.MethodVal:
815806
// e.f where e is an expression and f is a method.
816807
// The result is a "bound".
817-
818-
if base := fn.typ(sel.Recv()); base != sel.Recv() {
819-
// instantiate sel as sel.Recv is not equal after substitution.
820-
pkg := fn.declaredPackage().Pkg
821-
// mv is the instantiated method value.
822-
sel = types.NewMethodSet(base).Lookup(pkg, sel.Obj().Name())
823-
}
824808
obj := sel.Obj().(*types.Func)
825809
rt := fn.typ(recvType(obj))
826810
wantAddr := isPointer(rt)
@@ -939,7 +923,7 @@ func (b *builder) stmtList(fn *Function, list []ast.Stmt) {
939923
// must thus be addressable.
940924
//
941925
// escaping is defined as per builder.addr().
942-
func (b *builder) receiver(fn *Function, e ast.Expr, wantAddr, escaping bool, sel *types.Selection) Value {
926+
func (b *builder) receiver(fn *Function, e ast.Expr, wantAddr, escaping bool, sel *selection) Value {
943927
var v Value
944928
if wantAddr && !sel.Indirect() && !isPointer(fn.typeOf(e)) {
945929
v = b.addr(fn, e, escaping).address(fn)
@@ -964,15 +948,9 @@ func (b *builder) setCallFunc(fn *Function, e *ast.CallExpr, c *CallCommon) {
964948

965949
// Is this a method call?
966950
if selector, ok := unparen(e.Fun).(*ast.SelectorExpr); ok {
967-
sel, ok := fn.info.Selections[selector]
968-
if ok && sel.Kind() == types.MethodVal {
951+
sel := fn.selection(selector)
952+
if sel != nil && sel.Kind() == types.MethodVal {
969953
obj := sel.Obj().(*types.Func)
970-
if recv := fn.typ(sel.Recv()); recv != sel.Recv() {
971-
// adjust obj if the sel.Recv() changed during monomorphization.
972-
pkg := fn.declaredPackage().Pkg
973-
method, _, _ := types.LookupFieldOrMethod(recv, true, pkg, sel.Obj().Name())
974-
obj = method.(*types.Func)
975-
}
976954
recv := recvType(obj)
977955

978956
wantAddr := isPointer(recv)

go/ssa/func.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,40 @@ func (f *Function) instanceType(id *ast.Ident) types.Type {
5252
return f.typeOf(id)
5353
}
5454

55+
// selection returns a *selection corresponding to f.info.Selections[selector]
56+
// with potential updates for type substitution.
57+
func (f *Function) selection(selector *ast.SelectorExpr) *selection {
58+
sel := f.info.Selections[selector]
59+
if sel == nil {
60+
return nil
61+
}
62+
63+
switch sel.Kind() {
64+
case types.MethodExpr, types.MethodVal:
65+
if recv := f.typ(sel.Recv()); recv != sel.Recv() {
66+
// recv changed during type substitution.
67+
pkg := f.declaredPackage().Pkg
68+
obj, index, indirect := types.LookupFieldOrMethod(recv, true, pkg, sel.Obj().Name())
69+
70+
// sig replaces sel.Type(). See (types.Selection).Typ() for details.
71+
sig := obj.Type().(*types.Signature)
72+
sig = changeRecv(sig, newVar(sig.Recv().Name(), recv))
73+
if sel.Kind() == types.MethodExpr {
74+
sig = recvAsFirstArg(sig)
75+
}
76+
return &selection{
77+
kind: sel.Kind(),
78+
recv: recv,
79+
typ: sig,
80+
obj: obj,
81+
index: index,
82+
indirect: indirect,
83+
}
84+
}
85+
}
86+
return toSelection(sel)
87+
}
88+
5589
// Destinations associated with unlabelled for/switch/select stmts.
5690
// We push/pop one of these as we enter/leave each construct and for
5791
// each BranchStmt we scan for the innermost target of the right type.

go/ssa/methods.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ func (prog *Program) addMethod(mset *methodSet, sel *types.Selection, cr *creato
9898
id := sel.Obj().Id()
9999
fn := mset.mapping[id]
100100
if fn == nil {
101+
sel := toSelection(sel)
101102
obj := sel.Obj().(*types.Func)
102103

103104
needsPromotion := len(sel.Index()) > 1

go/ssa/ssa.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ type Node interface {
307307
type Function struct {
308308
name string
309309
object types.Object // a declared *types.Func or one of its wrappers
310-
method selection // info about provenance of synthetic methods
310+
method *selection // info about provenance of synthetic methods; thunk => non-nil
311311
Signature *types.Signature
312312
pos token.Pos
313313

go/ssa/wrappers.go

Lines changed: 22 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ import (
4242
// - the result may be a thunk or a wrapper.
4343
//
4444
// EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu)
45-
func makeWrapper(prog *Program, sel selection, cr *creator) *Function {
45+
func makeWrapper(prog *Program, sel *selection, cr *creator) *Function {
4646
obj := sel.Obj().(*types.Func) // the declared function
4747
sig := sel.Type().(*types.Signature) // type of this wrapper
4848

@@ -255,7 +255,7 @@ func makeBound(prog *Program, obj *types.Func, cr *creator) *Function {
255255
// than inlining the stub.
256256
//
257257
// EXCLUSIVE_LOCKS_ACQUIRED(meth.Prog.methodsMu)
258-
func makeThunk(prog *Program, sel selection, cr *creator) *Function {
258+
func makeThunk(prog *Program, sel *selection, cr *creator) *Function {
259259
if sel.Kind() != types.MethodExpr {
260260
panic(sel)
261261
}
@@ -303,43 +303,32 @@ type boundsKey struct {
303303
inst *typeList // canonical type instantiation list.
304304
}
305305

306-
// methodExpr is an copy of a *types.Selection.
307-
// This exists as there is no way to create MethodExpr's for an instantiation.
308-
type methodExpr struct {
306+
// A local version of *types.Selection.
307+
// Needed for some additional control, such as creating a MethodExpr for an instantiation.
308+
type selection struct {
309+
kind types.SelectionKind
309310
recv types.Type
310311
typ types.Type
311312
obj types.Object
312313
index []int
313314
indirect bool
314315
}
315316

316-
func (*methodExpr) Kind() types.SelectionKind { return types.MethodExpr }
317-
func (m *methodExpr) Type() types.Type { return m.typ }
318-
func (m *methodExpr) Recv() types.Type { return m.recv }
319-
func (m *methodExpr) Obj() types.Object { return m.obj }
320-
func (m *methodExpr) Index() []int { return m.index }
321-
func (m *methodExpr) Indirect() bool { return m.indirect }
322-
323-
// create MethodExpr from a MethodValue.
324-
func toMethodExpr(mv *types.Selection) *methodExpr {
325-
if mv.Kind() != types.MethodVal {
326-
panic(mv)
327-
}
328-
return &methodExpr{
329-
recv: mv.Recv(),
330-
typ: recvAsFirstArg(mv.Type().(*types.Signature)),
331-
obj: mv.Obj(),
332-
index: mv.Index(),
333-
indirect: mv.Indirect(),
334-
}
335-
}
317+
// TODO(taking): inline and eliminate.
318+
func (sel *selection) Kind() types.SelectionKind { return sel.kind }
319+
func (sel *selection) Type() types.Type { return sel.typ }
320+
func (sel *selection) Recv() types.Type { return sel.recv }
321+
func (sel *selection) Obj() types.Object { return sel.obj }
322+
func (sel *selection) Index() []int { return sel.index }
323+
func (sel *selection) Indirect() bool { return sel.indirect }
336324

337-
// generalization of a *types.Selection and a methodExpr.
338-
type selection interface {
339-
Kind() types.SelectionKind
340-
Type() types.Type
341-
Recv() types.Type
342-
Obj() types.Object
343-
Index() []int
344-
Indirect() bool
325+
func toSelection(sel *types.Selection) *selection {
326+
return &selection{
327+
kind: sel.Kind(),
328+
recv: sel.Recv(),
329+
typ: sel.Type(),
330+
obj: sel.Obj(),
331+
index: sel.Index(),
332+
indirect: sel.Indirect(),
333+
}
345334
}

0 commit comments

Comments
 (0)