aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Donovan <adonovan@google.com>2015-03-05 14:35:50 -0500
committerAlan Donovan <adonovan@google.com>2015-03-05 20:09:21 +0000
commit9957739054eda1f0e99582dad0d702da8a3d7d66 (patch)
tree0f622f3822a3fbaaa0587f75233e2752f997ab7f
parent4744be3abc70249546ce31c32fa9b5a5e96b5ad1 (diff)
downloadtools-9957739054eda1f0e99582dad0d702da8a3d7d66.tar.gz
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>
-rw-r--r--go/ssa/builder.go14
-rw-r--r--go/ssa/create.go13
-rw-r--r--go/ssa/sanity.go9
-rw-r--r--go/ssa/source.go2
-rw-r--r--go/ssa/ssa.go10
5 files changed, 26 insertions, 22 deletions
diff --git a/go/ssa/builder.go b/go/ssa/builder.go
index 3e70a85..f4418df 100644
--- a/go/ssa/builder.go
+++ b/go/ssa/builder.go
@@ -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)
}
diff --git a/go/ssa/create.go b/go/ssa/create.go
index c2985eb..0c25bf5 100644
--- a/go/ssa/create.go
+++ b/go/ssa/create.go
@@ -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)
}
diff --git a/go/ssa/sanity.go b/go/ssa/sanity.go
index 3fd6747..b0593d0 100644
--- a/go/ssa/sanity.go
+++ b/go/ssa/sanity.go
@@ -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()))
diff --git a/go/ssa/source.go b/go/ssa/source.go
index 02b0260..0566d23 100644
--- a/go/ssa/source.go
+++ b/go/ssa/source.go
@@ -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
diff --git a/go/ssa/ssa.go b/go/ssa/ssa.go
index afffb3f..75fdff8 100644
--- a/go/ssa/ssa.go
+++ b/go/ssa/ssa.go
@@ -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