From d203f128e2788ad61f53d815b6cf11ed981c68ba Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Fri, 19 Jul 2013 19:38:16 -0400 Subject: [PATCH] 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 --- ssa/builder.go | 6 +++--- ssa/create.go | 6 +++++- ssa/interp/reflect.go | 14 +++++++------- ssa/print.go | 11 ++--------- ssa/promote.go | 21 ++++----------------- ssa/ssa.go | 30 ++++++------------------------ ssa/util.go | 35 +++++------------------------------ 7 files changed, 32 insertions(+), 91 deletions(-) diff --git a/ssa/builder.go b/ssa/builder.go index efd5eb85..ad1e370c 100644 --- a/ssa/builder.go +++ b/ssa/builder.go @@ -681,7 +681,7 @@ func (b *builder) expr(fn *Function, e ast.Expr) Value { 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. 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. // -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) // Consult method-set of X. @@ -831,7 +831,7 @@ func (b *builder) setCallFunc(fn *Function, e *ast.CallExpr, c *CallCommon) { 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. diff --git a/ssa/create.go b/ssa/create.go index af42c969..ab252d25 100644 --- a/ssa/create.go +++ b/ssa/create.go @@ -118,6 +118,10 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) { pkg.values[obj] = fn pkg.Members[name] = fn } else { + // TODO(adonovan): interface methods now have + // objects, but we probably don't want to call + // memberFromObject for them. + // Method declaration. // TODO(adonovan) Move this test elsewhere. if _, ok := recv.Type().Underlying().(*types.Interface); ok { @@ -125,7 +129,7 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) { } _, method := namedTypeMethodIndex( deref(recv.Type()).(*types.Named), - makeId(name, pkg.Object)) + types.Id(pkg.Object, name)) pkg.Prog.concreteMethods[method] = fn } diff --git a/ssa/interp/reflect.go b/ssa/interp/reflect.go index e8cdfd51..3e3dd9c3 100644 --- a/ssa/interp/reflect.go +++ b/ssa/interp/reflect.go @@ -409,14 +409,14 @@ func initReflect(i *interpreter) { } i.rtypeMethods = ssa.MethodSet{ - ssa.Id{nil, "Bits"}: newMethod(i.reflectPackage, rtypeType, "Bits"), - ssa.Id{nil, "Elem"}: newMethod(i.reflectPackage, rtypeType, "Elem"), - ssa.Id{nil, "Kind"}: newMethod(i.reflectPackage, rtypeType, "Kind"), - ssa.Id{nil, "NumOut"}: newMethod(i.reflectPackage, rtypeType, "NumOut"), - ssa.Id{nil, "Out"}: newMethod(i.reflectPackage, rtypeType, "Out"), - ssa.Id{nil, "String"}: newMethod(i.reflectPackage, rtypeType, "String"), + "Bits": newMethod(i.reflectPackage, rtypeType, "Bits"), + "Elem": newMethod(i.reflectPackage, rtypeType, "Elem"), + "Kind": newMethod(i.reflectPackage, rtypeType, "Kind"), + "NumOut": newMethod(i.reflectPackage, rtypeType, "NumOut"), + "Out": newMethod(i.reflectPackage, rtypeType, "Out"), + "String": newMethod(i.reflectPackage, rtypeType, "String"), } i.errorMethods = ssa.MethodSet{ - ssa.Id{nil, "Error"}: newMethod(i.reflectPackage, errorType, "Error"), + "Error": newMethod(i.reflectPackage, errorType, "Error"), } } diff --git a/ssa/print.go b/ssa/print.go index f75068aa..d7e1bdb9 100644 --- a/ssa/print.go +++ b/ssa/print.go @@ -13,13 +13,6 @@ import ( "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. // In most cases, this is identical to v.Name(), but for references to // 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 // types.MethodSet if possible. mset := p.Prog.MethodSet(types.NewPointer(mem.Type())) - var keys ids + var keys []string for id := range mset { keys = append(keys, id) } - sort.Sort(keys) + sort.Strings(keys) for _, id := range keys { method := mset[id] // TODO(adonovan): show pointerness of receiver of declared method, not the index diff --git a/ssa/promote.go b/ssa/promote.go index 05dd719d..d48b3469 100644 --- a/ssa/promote.go +++ b/ssa/promote.go @@ -57,7 +57,7 @@ func (prog *Program) MethodSet(typ types.Type) MethodSet { tmset := typ.MethodSet() for i, n := 0, tmset.Len(); i < n; 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) return mset @@ -112,21 +112,8 @@ func promotionWrapper(prog *Program, typ types.Type, obj *types.Method) *Functio old := obj.Func.Type().(*types.Signature) 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. - description := fmt.Sprintf("promotion wrapper for (%s).%s", - promotedRecvString, obj.Func.Name()) + description := fmt.Sprintf("promotion wrapper for (%s).%s", old.Recv(), obj.Func.Name()) if prog.mode&LogSource != 0 { 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. 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()) { v = emitLoad(fn, v) } @@ -222,7 +209,7 @@ func createParams(fn *Function) { // // 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) prog.methodsMu.Lock() defer prog.methodsMu.Unlock() diff --git a/ssa/ssa.go b/ssa/ssa.go index bd4b4723..514c38f7 100644 --- a/ssa/ssa.go +++ b/ssa/ssa.go @@ -63,26 +63,6 @@ type Member interface { 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. // 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 // 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. // @@ -1284,9 +1267,8 @@ func (c *CallCommon) StaticCallee() *Function { // MethodId returns the Id for the method called by c, which must // have "invoke" mode. -func (c *CallCommon) MethodId() Id { - m := c.Recv.Type().Underlying().(*types.Interface).Method(c.Method) - return makeId(m.Name(), m.Pkg()) +func (c *CallCommon) MethodId() string { + return c.Recv.Type().Underlying().(*types.Interface).Method(c.Method).Id() } // Description returns a description of the mode of this call suitable diff --git a/ssa/util.go b/ssa/util.go index bba95b24..bb7d5b0e 100644 --- a/ssa/util.go +++ b/ssa/util.go @@ -57,10 +57,10 @@ func deref(typ types.Type) types.Type { // within the set of explicitly declared concrete methods of named // 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++ { m := typ.Method(i) - if makeId(m.Name(), m.Pkg()) == id { + if m.Id() == id { 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 // 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++ { m := typ.Method(i) - if makeId(m.Name(), m.Pkg()) == id { + if m.Id() == id { return i, m } } @@ -94,7 +94,7 @@ outer: xm := x.Method(i) for j, m := 0, y.NumMethods(); j < m; 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()) { return false // common name but conflicting types } @@ -156,31 +156,6 @@ func DefaultType(typ types.Type) types.Type { 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 // returns a closure that prints the corresponding "end" message. // Call using 'defer logStack(...)()' to show builder stack on panic.