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>
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 @@
 	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 @@
 // See builder.go for explanation.
 
 import (
+	"fmt"
 	"go/ast"
 	"go/token"
 	"os"
@@ -88,10 +89,15 @@
 		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 @@
 		}
 
 		pkg.values[obj] = fn
-		if fn.Signature.Recv() == nil {
+		if sig.Recv() == nil {
 			pkg.Members[name] = fn // package-level function
 		}
 
@@ -148,9 +154,6 @@
 
 	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 @@
 			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 @@
 //    - 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 @@
 // 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 @@
 // 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