go/ssa: treat declared init functions less specially
Before this change, declared init functions were not package members; this choice dates from when go/types did not create Func objects for them. Now, they have an Object. They appear in Members, keyed by "init#%d" (sequence number) for uniqueness. They can be enumerated. They can be looked up from a *types.Func via (*Program).FuncValue. Caveat: fn.Object.Name() no longer equals fn.Name() in all cases. NB: incompatible API change! (Your build will not break though.) Change-Id: I2de873079fd57329e6c2f55a282940f6699a77a1 Reviewed-on: https://go-review.googlesource.com/6950 Reviewed-by: Robert Griesemer <gri@golang.org> Reviewed-by: Peter Collingbourne <pcc@google.com>
This commit is contained in:
parent
4744be3abc
commit
9957739054
|
@ -2125,24 +2125,12 @@ func (b *builder) buildFuncDecl(pkg *Package, decl *ast.FuncDecl) {
|
|||
if isBlankIdent(id) {
|
||||
return // discard
|
||||
}
|
||||
var fn *Function
|
||||
fn := pkg.values[pkg.info.Defs[id]].(*Function)
|
||||
if decl.Recv == nil && id.Name == "init" {
|
||||
pkg.ninit++
|
||||
fn = &Function{
|
||||
name: fmt.Sprintf("init#%d", pkg.ninit),
|
||||
Signature: new(types.Signature),
|
||||
pos: decl.Name.NamePos,
|
||||
Pkg: pkg,
|
||||
Prog: pkg.Prog,
|
||||
syntax: decl,
|
||||
}
|
||||
|
||||
var v Call
|
||||
v.Call.Value = fn
|
||||
v.setType(types.NewTuple())
|
||||
pkg.init.emit(&v)
|
||||
} else {
|
||||
fn = pkg.values[pkg.info.Defs[id]].(*Function)
|
||||
}
|
||||
b.buildFunction(fn)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ package ssa
|
|||
// See builder.go for explanation.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"os"
|
||||
|
@ -88,10 +89,15 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
|
|||
pkg.Members[name] = g
|
||||
|
||||
case *types.Func:
|
||||
sig := obj.Type().(*types.Signature)
|
||||
if sig.Recv() == nil && name == "init" {
|
||||
pkg.ninit++
|
||||
name = fmt.Sprintf("init#%d", pkg.ninit)
|
||||
}
|
||||
fn := &Function{
|
||||
name: name,
|
||||
object: obj,
|
||||
Signature: obj.Type().(*types.Signature),
|
||||
Signature: sig,
|
||||
syntax: syntax,
|
||||
pos: obj.Pos(),
|
||||
Pkg: pkg,
|
||||
|
@ -102,7 +108,7 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
|
|||
}
|
||||
|
||||
pkg.values[obj] = fn
|
||||
if fn.Signature.Recv() == nil {
|
||||
if sig.Recv() == nil {
|
||||
pkg.Members[name] = fn // package-level function
|
||||
}
|
||||
|
||||
|
@ -148,9 +154,6 @@ func membersFromDecl(pkg *Package, decl ast.Decl) {
|
|||
|
||||
case *ast.FuncDecl:
|
||||
id := decl.Name
|
||||
if decl.Recv == nil && id.Name == "init" {
|
||||
return // no object
|
||||
}
|
||||
if !isBlankIdent(id) {
|
||||
memberFromObject(pkg, pkg.info.Defs[id], decl)
|
||||
}
|
||||
|
|
|
@ -505,8 +505,13 @@ func sanityCheckPackage(pkg *Package) {
|
|||
continue // not all members have typechecker objects
|
||||
}
|
||||
if obj.Name() != name {
|
||||
panic(fmt.Sprintf("%s: %T.Object().Name() = %s, want %s",
|
||||
pkg.Object.Path(), mem, obj.Name(), name))
|
||||
if obj.Name() == "init" && strings.HasPrefix(mem.Name(), "init#") {
|
||||
// Ok. The name of a declared init function varies between
|
||||
// its types.Func ("init") and its ssa.Function ("init#%d").
|
||||
} else {
|
||||
panic(fmt.Sprintf("%s: %T.Object().Name() = %s, want %s",
|
||||
pkg.Object.Path(), mem, obj.Name(), name))
|
||||
}
|
||||
}
|
||||
if obj.Pos() != mem.Pos() {
|
||||
panic(fmt.Sprintf("%s Pos=%d obj.Pos=%d", mem, mem.Pos(), obj.Pos()))
|
||||
|
|
|
@ -144,7 +144,7 @@ func findNamedFunc(pkg *Package, pos token.Pos) *Function {
|
|||
// - e is a reference to nil or a built-in function.
|
||||
// - the value was optimised away.
|
||||
//
|
||||
// If e is an addressable expression used an an lvalue context,
|
||||
// If e is an addressable expression used in an lvalue context,
|
||||
// value is the address denoted by e, and isAddr is true.
|
||||
//
|
||||
// The types of e (or &e, if isAddr) and the result are equal
|
||||
|
|
|
@ -40,10 +40,14 @@ type Program struct {
|
|||
// declares. These may be accessed directly via Members, or via the
|
||||
// type-specific accessor methods Func, Type, Var and Const.
|
||||
//
|
||||
// Members also contains entries for "init" (the synthetic package
|
||||
// initializer) and "init#%d", the nth declared init function,
|
||||
// and unspecified other things too.
|
||||
//
|
||||
type Package struct {
|
||||
Prog *Program // the owning program
|
||||
Object *types.Package // the type checker's package object for this package
|
||||
Members map[string]Member // all package members keyed by name
|
||||
Members map[string]Member // all package members keyed by name (incl. init and init#%d)
|
||||
values map[types.Object]Value // package members (incl. types and methods), keyed by object
|
||||
init *Function // Func("init"); the package's init function
|
||||
debug bool // include full debug info in this package
|
||||
|
@ -281,6 +285,10 @@ type Node interface {
|
|||
// If the function is a method (Signature.Recv() != nil) then the first
|
||||
// element of Params is the receiver parameter.
|
||||
//
|
||||
// A Go package may declare many functions called "init".
|
||||
// For each one, Object().Name() returns "init" but Name() returns
|
||||
// "init#1", etc, in declaration order.
|
||||
//
|
||||
// Pos() returns the declaring ast.FuncLit.Type.Func or the position
|
||||
// of the ast.FuncDecl.Name, if the function was explicit in the
|
||||
// source. Synthetic wrappers, for which Synthetic != "", may share
|
||||
|
|
Loading…
Reference in New Issue