mirror of https://github.com/golang/go.git
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 <adonovan@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Robert Findley <rfindley@google.com> gopls-CI: kokoro <noreply+kokoro@google.com> Run-TryBot: Tim King <taking@google.com>
This commit is contained in:
parent
f918e87c18
commit
304195cc44
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
// 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 }
|
||||
|
||||
// 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(),
|
||||
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(),
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue