Skip to content

Commit

Permalink
go/ssa: create *ssa.selection.
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
timothy-king committed May 13, 2022
1 parent f918e87 commit 304195c
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 63 deletions.
36 changes: 7 additions & 29 deletions go/ssa/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)}
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down
34 changes: 34 additions & 0 deletions go/ssa/func.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions go/ssa/methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion go/ssa/ssa.go
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
55 changes: 22 additions & 33 deletions go/ssa/wrappers.go
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -303,43 +303,32 @@ 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
index []int
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(),
}
}

0 comments on commit 304195c

Please sign in to comment.