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:
Alan Donovan 2013-07-19 19:38:16 -04:00
parent d722d82c52
commit d203f128e2
7 changed files with 32 additions and 91 deletions

View File

@ -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.

View File

@ -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
} }

View File

@ -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"),
} }
} }

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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.