mirror of
https://github.com/golang/go
synced 2024-11-18 18:04:46 -07:00
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)
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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"),
|
||||
}
|
||||
}
|
||||
|
11
ssa/print.go
11
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
|
||||
|
@ -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()
|
||||
|
30
ssa/ssa.go
30
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
|
||||
|
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
|
||||
// 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.
|
||||
|
Loading…
Reference in New Issue
Block a user