go.tools/ssa: drop ssa.Id in favour of types.Id function.
Also exploit fact that Recv() is now always non-nil, even for interfaces. R=gri CC=golang-dev https://golang.org/cl/11613043
This commit is contained in:
parent
d722d82c52
commit
d203f128e2
|
|
@ -681,7 +681,7 @@ func (b *builder) expr(fn *Function, e ast.Expr) Value {
|
||||||
return b.expr(fn, e.Sel)
|
return b.expr(fn, e.Sel)
|
||||||
}
|
}
|
||||||
|
|
||||||
id := makeId(e.Sel.Name, fn.Pkg.Object)
|
id := types.Id(fn.Pkg.Object, e.Sel.Name)
|
||||||
|
|
||||||
// (*T).f or T.f, the method f from the method-set of type T.
|
// (*T).f or T.f, the method f from the method-set of type T.
|
||||||
if fn.Pkg.info.IsType(e.X) {
|
if fn.Pkg.info.IsType(e.X) {
|
||||||
|
|
@ -772,7 +772,7 @@ func (b *builder) stmtList(fn *Function, list []ast.Stmt) {
|
||||||
//
|
//
|
||||||
// findMethod returns (nil, nil) if no such method was found.
|
// findMethod returns (nil, nil) if no such method was found.
|
||||||
//
|
//
|
||||||
func (b *builder) findMethod(fn *Function, base ast.Expr, id Id) (*Function, Value) {
|
func (b *builder) findMethod(fn *Function, base ast.Expr, id string) (*Function, Value) {
|
||||||
typ := fn.Pkg.typeOf(base)
|
typ := fn.Pkg.typeOf(base)
|
||||||
|
|
||||||
// Consult method-set of X.
|
// Consult method-set of X.
|
||||||
|
|
@ -831,7 +831,7 @@ func (b *builder) setCallFunc(fn *Function, e *ast.CallExpr, c *CallCommon) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id := makeId(sel.Sel.Name, fn.Pkg.Object)
|
id := types.Id(fn.Pkg.Object, sel.Sel.Name)
|
||||||
|
|
||||||
// Let X be the type of x.
|
// Let X be the type of x.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,10 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
|
||||||
pkg.values[obj] = fn
|
pkg.values[obj] = fn
|
||||||
pkg.Members[name] = fn
|
pkg.Members[name] = fn
|
||||||
} else {
|
} else {
|
||||||
|
// TODO(adonovan): interface methods now have
|
||||||
|
// objects, but we probably don't want to call
|
||||||
|
// memberFromObject for them.
|
||||||
|
|
||||||
// Method declaration.
|
// Method declaration.
|
||||||
// TODO(adonovan) Move this test elsewhere.
|
// TODO(adonovan) Move this test elsewhere.
|
||||||
if _, ok := recv.Type().Underlying().(*types.Interface); ok {
|
if _, ok := recv.Type().Underlying().(*types.Interface); ok {
|
||||||
|
|
@ -125,7 +129,7 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
|
||||||
}
|
}
|
||||||
_, method := namedTypeMethodIndex(
|
_, method := namedTypeMethodIndex(
|
||||||
deref(recv.Type()).(*types.Named),
|
deref(recv.Type()).(*types.Named),
|
||||||
makeId(name, pkg.Object))
|
types.Id(pkg.Object, name))
|
||||||
pkg.Prog.concreteMethods[method] = fn
|
pkg.Prog.concreteMethods[method] = fn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -409,14 +409,14 @@ func initReflect(i *interpreter) {
|
||||||
}
|
}
|
||||||
|
|
||||||
i.rtypeMethods = ssa.MethodSet{
|
i.rtypeMethods = ssa.MethodSet{
|
||||||
ssa.Id{nil, "Bits"}: newMethod(i.reflectPackage, rtypeType, "Bits"),
|
"Bits": newMethod(i.reflectPackage, rtypeType, "Bits"),
|
||||||
ssa.Id{nil, "Elem"}: newMethod(i.reflectPackage, rtypeType, "Elem"),
|
"Elem": newMethod(i.reflectPackage, rtypeType, "Elem"),
|
||||||
ssa.Id{nil, "Kind"}: newMethod(i.reflectPackage, rtypeType, "Kind"),
|
"Kind": newMethod(i.reflectPackage, rtypeType, "Kind"),
|
||||||
ssa.Id{nil, "NumOut"}: newMethod(i.reflectPackage, rtypeType, "NumOut"),
|
"NumOut": newMethod(i.reflectPackage, rtypeType, "NumOut"),
|
||||||
ssa.Id{nil, "Out"}: newMethod(i.reflectPackage, rtypeType, "Out"),
|
"Out": newMethod(i.reflectPackage, rtypeType, "Out"),
|
||||||
ssa.Id{nil, "String"}: newMethod(i.reflectPackage, rtypeType, "String"),
|
"String": newMethod(i.reflectPackage, rtypeType, "String"),
|
||||||
}
|
}
|
||||||
i.errorMethods = ssa.MethodSet{
|
i.errorMethods = ssa.MethodSet{
|
||||||
ssa.Id{nil, "Error"}: newMethod(i.reflectPackage, errorType, "Error"),
|
"Error": newMethod(i.reflectPackage, errorType, "Error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
11
ssa/print.go
11
ssa/print.go
|
|
@ -13,13 +13,6 @@ import (
|
||||||
"code.google.com/p/go.tools/go/types"
|
"code.google.com/p/go.tools/go/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (id Id) String() string {
|
|
||||||
if id.Pkg == nil {
|
|
||||||
return id.Name
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%s/%s", id.Pkg.Path(), id.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// relName returns the name of v relative to i.
|
// relName returns the name of v relative to i.
|
||||||
// In most cases, this is identical to v.Name(), but for references to
|
// In most cases, this is identical to v.Name(), but for references to
|
||||||
// Functions (including methods) and Globals, the FullName is used
|
// Functions (including methods) and Globals, the FullName is used
|
||||||
|
|
@ -397,11 +390,11 @@ func (p *Package) DumpTo(w io.Writer) {
|
||||||
// entire ssa.MethodSet by using the
|
// entire ssa.MethodSet by using the
|
||||||
// types.MethodSet if possible.
|
// types.MethodSet if possible.
|
||||||
mset := p.Prog.MethodSet(types.NewPointer(mem.Type()))
|
mset := p.Prog.MethodSet(types.NewPointer(mem.Type()))
|
||||||
var keys ids
|
var keys []string
|
||||||
for id := range mset {
|
for id := range mset {
|
||||||
keys = append(keys, id)
|
keys = append(keys, id)
|
||||||
}
|
}
|
||||||
sort.Sort(keys)
|
sort.Strings(keys)
|
||||||
for _, id := range keys {
|
for _, id := range keys {
|
||||||
method := mset[id]
|
method := mset[id]
|
||||||
// TODO(adonovan): show pointerness of receiver of declared method, not the index
|
// TODO(adonovan): show pointerness of receiver of declared method, not the index
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ func (prog *Program) MethodSet(typ types.Type) MethodSet {
|
||||||
tmset := typ.MethodSet()
|
tmset := typ.MethodSet()
|
||||||
for i, n := 0, tmset.Len(); i < n; i++ {
|
for i, n := 0, tmset.Len(); i < n; i++ {
|
||||||
obj := tmset.At(i)
|
obj := tmset.At(i)
|
||||||
mset[makeId(obj.Func.Name(), obj.Func.Pkg())] = makeMethod(prog, typ, obj)
|
mset[obj.Func.Id()] = makeMethod(prog, typ, obj)
|
||||||
}
|
}
|
||||||
prog.methodSets.Set(typ, mset)
|
prog.methodSets.Set(typ, mset)
|
||||||
return mset
|
return mset
|
||||||
|
|
@ -112,21 +112,8 @@ func promotionWrapper(prog *Program, typ types.Type, obj *types.Method) *Functio
|
||||||
old := obj.Func.Type().(*types.Signature)
|
old := obj.Func.Type().(*types.Signature)
|
||||||
sig := types.NewSignature(types.NewVar(token.NoPos, nil, "recv", typ), old.Params(), old.Results(), old.IsVariadic())
|
sig := types.NewSignature(types.NewVar(token.NoPos, nil, "recv", typ), old.Params(), old.Results(), old.IsVariadic())
|
||||||
|
|
||||||
promotedRecv := obj.Func.Type().(*types.Signature).Recv()
|
|
||||||
|
|
||||||
// TODO(adonovan): Interface method receivers used to be nil, but
|
|
||||||
// aren't anymore. Nil them again so this code works for now. Fix.
|
|
||||||
var promotedRecvString string
|
|
||||||
if _, ok := promotedRecv.Type().Underlying().(*types.Interface); ok {
|
|
||||||
promotedRecv = nil
|
|
||||||
promotedRecvString = "INTERFACE?"
|
|
||||||
} else {
|
|
||||||
promotedRecvString = promotedRecv.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(adonovan): include implicit field path in description.
|
// TODO(adonovan): include implicit field path in description.
|
||||||
description := fmt.Sprintf("promotion wrapper for (%s).%s",
|
description := fmt.Sprintf("promotion wrapper for (%s).%s", old.Recv(), obj.Func.Name())
|
||||||
promotedRecvString, obj.Func.Name())
|
|
||||||
|
|
||||||
if prog.mode&LogSource != 0 {
|
if prog.mode&LogSource != 0 {
|
||||||
defer logStack("make %s to (%s)", description, typ)()
|
defer logStack("make %s to (%s)", description, typ)()
|
||||||
|
|
@ -164,7 +151,7 @@ func promotionWrapper(prog *Program, typ types.Type, obj *types.Method) *Functio
|
||||||
// address of implicit C field.
|
// address of implicit C field.
|
||||||
|
|
||||||
var c Call
|
var c Call
|
||||||
if promotedRecv != nil { // concrete method TODO(gri): temporary hack
|
if _, ok := old.Recv().Type().Underlying().(*types.Interface); !ok { // concrete method
|
||||||
if !isPointer(old.Recv().Type()) {
|
if !isPointer(old.Recv().Type()) {
|
||||||
v = emitLoad(fn, v)
|
v = emitLoad(fn, v)
|
||||||
}
|
}
|
||||||
|
|
@ -222,7 +209,7 @@ func createParams(fn *Function) {
|
||||||
//
|
//
|
||||||
// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu)
|
// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu)
|
||||||
//
|
//
|
||||||
func interfaceMethodWrapper(prog *Program, typ types.Type, id Id) *Function {
|
func interfaceMethodWrapper(prog *Program, typ types.Type, id string) *Function {
|
||||||
index, meth := interfaceMethodIndex(typ.Underlying().(*types.Interface), id)
|
index, meth := interfaceMethodIndex(typ.Underlying().(*types.Interface), id)
|
||||||
prog.methodsMu.Lock()
|
prog.methodsMu.Lock()
|
||||||
defer prog.methodsMu.Unlock()
|
defer prog.methodsMu.Unlock()
|
||||||
|
|
|
||||||
30
ssa/ssa.go
30
ssa/ssa.go
|
|
@ -63,26 +63,6 @@ type Member interface {
|
||||||
Token() token.Token // token.{VAR,FUNC,CONST,TYPE}
|
Token() token.Token // token.{VAR,FUNC,CONST,TYPE}
|
||||||
}
|
}
|
||||||
|
|
||||||
// An Id identifies the name of a field of a struct type, or the name
|
|
||||||
// of a method of an interface or a named type.
|
|
||||||
//
|
|
||||||
// For exported names, i.e. those beginning with a Unicode upper-case
|
|
||||||
// letter, a simple string is unambiguous.
|
|
||||||
//
|
|
||||||
// However, a method set or struct may contain multiple unexported
|
|
||||||
// names with identical spelling that are logically distinct because
|
|
||||||
// they originate in different packages. Unexported names must
|
|
||||||
// therefore be disambiguated by their package too.
|
|
||||||
//
|
|
||||||
// The Pkg field of an Id is therefore nil iff the name is exported.
|
|
||||||
//
|
|
||||||
// This type is suitable for use as a map key because the equivalence
|
|
||||||
// relation == is consistent with identifier equality.
|
|
||||||
type Id struct {
|
|
||||||
Pkg *types.Package
|
|
||||||
Name string
|
|
||||||
}
|
|
||||||
|
|
||||||
// A MethodSet contains all the methods for a particular type T.
|
// A MethodSet contains all the methods for a particular type T.
|
||||||
// The method sets for T and *T are distinct entities.
|
// The method sets for T and *T are distinct entities.
|
||||||
//
|
//
|
||||||
|
|
@ -90,7 +70,10 @@ type Id struct {
|
||||||
// T. The method set of *T may contain synthetic indirection methods
|
// T. The method set of *T may contain synthetic indirection methods
|
||||||
// that wrap methods whose receiver type is T.
|
// that wrap methods whose receiver type is T.
|
||||||
//
|
//
|
||||||
type MethodSet map[Id]*Function
|
// The keys of a method set are strings returned by the types.Id()
|
||||||
|
// function.
|
||||||
|
//
|
||||||
|
type MethodSet map[string]*Function
|
||||||
|
|
||||||
// A Type is a Member of a Package representing a package-level named type.
|
// A Type is a Member of a Package representing a package-level named type.
|
||||||
//
|
//
|
||||||
|
|
@ -1284,9 +1267,8 @@ func (c *CallCommon) StaticCallee() *Function {
|
||||||
|
|
||||||
// MethodId returns the Id for the method called by c, which must
|
// MethodId returns the Id for the method called by c, which must
|
||||||
// have "invoke" mode.
|
// have "invoke" mode.
|
||||||
func (c *CallCommon) MethodId() Id {
|
func (c *CallCommon) MethodId() string {
|
||||||
m := c.Recv.Type().Underlying().(*types.Interface).Method(c.Method)
|
return c.Recv.Type().Underlying().(*types.Interface).Method(c.Method).Id()
|
||||||
return makeId(m.Name(), m.Pkg())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Description returns a description of the mode of this call suitable
|
// Description returns a description of the mode of this call suitable
|
||||||
|
|
|
||||||
35
ssa/util.go
35
ssa/util.go
|
|
@ -57,10 +57,10 @@ func deref(typ types.Type) types.Type {
|
||||||
// within the set of explicitly declared concrete methods of named
|
// within the set of explicitly declared concrete methods of named
|
||||||
// type typ. If not found, panic ensues.
|
// type typ. If not found, panic ensues.
|
||||||
//
|
//
|
||||||
func namedTypeMethodIndex(typ *types.Named, id Id) (int, *types.Func) {
|
func namedTypeMethodIndex(typ *types.Named, id string) (int, *types.Func) {
|
||||||
for i, n := 0, typ.NumMethods(); i < n; i++ {
|
for i, n := 0, typ.NumMethods(); i < n; i++ {
|
||||||
m := typ.Method(i)
|
m := typ.Method(i)
|
||||||
if makeId(m.Name(), m.Pkg()) == id {
|
if m.Id() == id {
|
||||||
return i, m
|
return i, m
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -71,10 +71,10 @@ func namedTypeMethodIndex(typ *types.Named, id Id) (int, *types.Func) {
|
||||||
// within the method-set of interface type typ. If not found, panic
|
// within the method-set of interface type typ. If not found, panic
|
||||||
// ensues.
|
// ensues.
|
||||||
//
|
//
|
||||||
func interfaceMethodIndex(typ *types.Interface, id Id) (int, *types.Func) {
|
func interfaceMethodIndex(typ *types.Interface, id string) (int, *types.Func) {
|
||||||
for i, n := 0, typ.NumMethods(); i < n; i++ {
|
for i, n := 0, typ.NumMethods(); i < n; i++ {
|
||||||
m := typ.Method(i)
|
m := typ.Method(i)
|
||||||
if makeId(m.Name(), m.Pkg()) == id {
|
if m.Id() == id {
|
||||||
return i, m
|
return i, m
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -94,7 +94,7 @@ outer:
|
||||||
xm := x.Method(i)
|
xm := x.Method(i)
|
||||||
for j, m := 0, y.NumMethods(); j < m; j++ {
|
for j, m := 0, y.NumMethods(); j < m; j++ {
|
||||||
ym := y.Method(j)
|
ym := y.Method(j)
|
||||||
if makeId(xm.Name(), xm.Pkg()) == makeId(ym.Name(), ym.Pkg()) {
|
if xm.Id() == ym.Id() {
|
||||||
if !types.IsIdentical(xm.Type(), ym.Type()) {
|
if !types.IsIdentical(xm.Type(), ym.Type()) {
|
||||||
return false // common name but conflicting types
|
return false // common name but conflicting types
|
||||||
}
|
}
|
||||||
|
|
@ -156,31 +156,6 @@ func DefaultType(typ types.Type) types.Type {
|
||||||
return typ
|
return typ
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeId returns the Id (name, pkg) if the name is exported or
|
|
||||||
// (name, nil) otherwise.
|
|
||||||
//
|
|
||||||
func makeId(name string, pkg *types.Package) (id Id) {
|
|
||||||
id.Name = name
|
|
||||||
if !ast.IsExported(name) {
|
|
||||||
id.Pkg = pkg
|
|
||||||
if pkg.Path() == "" {
|
|
||||||
panic("empty types.Package.Path()")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type ids []Id // a sortable slice of Id
|
|
||||||
|
|
||||||
func (p ids) Len() int { return len(p) }
|
|
||||||
func (p ids) Less(i, j int) bool {
|
|
||||||
x, y := p[i], p[j]
|
|
||||||
// TODO(adonovan): opt: where's Go's 3-valued strings.Compare function?
|
|
||||||
return x.Pkg.Path() < y.Pkg.Path() ||
|
|
||||||
x.Pkg.Path() == y.Pkg.Path() && x.Name < y.Name
|
|
||||||
}
|
|
||||||
func (p ids) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
|
||||||
|
|
||||||
// logStack prints the formatted "start" message to stderr and
|
// logStack prints the formatted "start" message to stderr and
|
||||||
// returns a closure that prints the corresponding "end" message.
|
// returns a closure that prints the corresponding "end" message.
|
||||||
// Call using 'defer logStack(...)()' to show builder stack on panic.
|
// Call using 'defer logStack(...)()' to show builder stack on panic.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue