1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
7 // This file implements the CREATE phase of IR construction.
8 // See builder.go for explanation.
18 "golang.org/x/tools/go/types/typeutil"
21 // NewProgram returns a new IR Program.
23 // mode controls diagnostics and checking during IR construction.
25 func NewProgram(fset *token.FileSet, mode BuilderMode) *Program {
28 imported: make(map[string]*Package),
29 packages: make(map[*types.Package]*Package),
30 thunks: make(map[selectionKey]*Function),
31 bounds: make(map[*types.Func]*Function),
35 h := typeutil.MakeHasher() // protected by methodsMu, in effect
36 prog.methodSets.SetHasher(h)
37 prog.canon.SetHasher(h)
42 // memberFromObject populates package pkg with a member for the
43 // typechecker object obj.
45 // For objects from Go source code, syntax is the associated syntax
46 // tree (for funcs and vars only); it will be used during the build
49 func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
51 switch obj := obj.(type) {
53 if pkg.Pkg != types.Unsafe {
54 panic("unexpected builtin object: " + obj.String())
58 pkg.Members[name] = &Type{
66 Value: NewConst(obj.Val(), obj.Type()),
69 pkg.values[obj] = c.Value
77 typ: types.NewPointer(obj.Type()), // address
83 sig := obj.Type().(*types.Signature)
84 if sig.Recv() == nil && name == "init" {
86 name = fmt.Sprintf("init#%d", pkg.ninit)
97 fn.initHTML(pkg.printFunc)
99 fn.Synthetic = "loaded from gc object file"
101 fn.functionBody = new(functionBody)
105 pkg.Functions = append(pkg.Functions, fn)
106 if sig.Recv() == nil {
107 pkg.Members[name] = fn // package-level function
110 default: // (incl. *types.Package)
111 panic("unexpected Object type: " + obj.String())
115 // membersFromDecl populates package pkg with members for each
116 // typechecker object (var, func, const or type) associated with the
119 func membersFromDecl(pkg *Package, decl ast.Decl) {
120 switch decl := decl.(type) {
121 case *ast.GenDecl: // import, const, type or var
124 for _, spec := range decl.Specs {
125 for _, id := range spec.(*ast.ValueSpec).Names {
126 if !isBlankIdent(id) {
127 memberFromObject(pkg, pkg.info.Defs[id], nil)
133 for _, spec := range decl.Specs {
134 for _, id := range spec.(*ast.ValueSpec).Names {
135 if !isBlankIdent(id) {
136 memberFromObject(pkg, pkg.info.Defs[id], spec)
142 for _, spec := range decl.Specs {
143 id := spec.(*ast.TypeSpec).Name
144 if !isBlankIdent(id) {
145 memberFromObject(pkg, pkg.info.Defs[id], nil)
152 if !isBlankIdent(id) {
153 memberFromObject(pkg, pkg.info.Defs[id], decl)
158 // CreatePackage constructs and returns an IR Package from the
159 // specified type-checked, error-free file ASTs, and populates its
162 // importable determines whether this package should be returned by a
163 // subsequent call to ImportedPackage(pkg.Path()).
165 // The real work of building IR form for each function is not done
166 // until a subsequent call to Package.Build().
168 func (prog *Program) CreatePackage(pkg *types.Package, files []*ast.File, info *types.Info, importable bool) *Package {
171 Members: make(map[string]Member),
172 values: make(map[types.Object]Value),
174 info: info, // transient (CREATE and BUILD phases)
175 files: files, // transient (CREATE and BUILD phases)
176 printFunc: prog.PrintFunc,
179 // Add init() function.
182 Signature: new(types.Signature),
183 Synthetic: "package initializer",
186 functionBody: new(functionBody),
188 p.init.initHTML(prog.PrintFunc)
189 p.Members[p.init.name] = p.init
190 p.Functions = append(p.Functions, p.init)
193 // Allocate all package members: vars, funcs, consts and types.
195 // Go source package.
196 for _, file := range files {
197 for _, decl := range file.Decls {
198 membersFromDecl(p, decl)
202 // GC-compiled binary package (or "unsafe")
204 // No position information.
205 scope := p.Pkg.Scope()
206 for _, name := range scope.Names() {
207 obj := scope.Lookup(name)
208 memberFromObject(p, obj, nil)
209 if obj, ok := obj.(*types.TypeName); ok {
210 if named, ok := obj.Type().(*types.Named); ok {
211 for i, n := 0, named.NumMethods(); i < n; i++ {
212 memberFromObject(p, named.Method(i), nil)
219 // Add initializer guard variable.
220 initguard := &Global{
223 typ: types.NewPointer(tBool),
225 p.Members[initguard.Name()] = initguard
227 if prog.mode&GlobalDebug != 0 {
231 if prog.mode&PrintPackages != 0 {
238 prog.imported[p.Pkg.Path()] = p
240 prog.packages[p.Pkg] = p
245 // printMu serializes printing of Packages/Functions to stdout.
246 var printMu sync.Mutex
248 // AllPackages returns a new slice containing all packages in the
249 // program prog in unspecified order.
251 func (prog *Program) AllPackages() []*Package {
252 pkgs := make([]*Package, 0, len(prog.packages))
253 for _, pkg := range prog.packages {
254 pkgs = append(pkgs, pkg)
259 // ImportedPackage returns the importable Package whose PkgPath
260 // is path, or nil if no such Package has been created.
262 // A parameter to CreatePackage determines whether a package should be
263 // considered importable. For example, no import declaration can resolve
264 // to the ad-hoc main package created by 'go build foo.go'.
266 // TODO(adonovan): rethink this function and the "importable" concept;
267 // most packages are importable. This function assumes that all
268 // types.Package.Path values are unique within the ir.Program, which is
269 // false---yet this function remains very convenient.
270 // Clients should use (*Program).Package instead where possible.
271 // IR doesn't really need a string-keyed map of packages.
273 func (prog *Program) ImportedPackage(path string) *Package {
274 return prog.imported[path]