From 9957739054eda1f0e99582dad0d702da8a3d7d66 Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Thu, 5 Mar 2015 14:35:50 -0500 Subject: 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 Reviewed-by: Peter Collingbourne --- go/ssa/builder.go | 14 +------------- go/ssa/create.go | 13 ++++++++----- go/ssa/sanity.go | 9 +++++++-- go/ssa/source.go | 2 +- go/ssa/ssa.go | 10 +++++++++- 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 -- cgit v1.2.3