1
0
mirror of https://github.com/golang/go synced 2024-10-01 05:38:32 -06:00

go.types/go/types: document primary vs. secondary Package distinction.

And: add accessor to get the primary from a secondary Package.

This change documents a surprising fact about the current
go/types resolver implementation, namely that each ast.ImportSpec
    import "fmt"
creates a new ("secondary") Package object for fmt with the
same String, Name, Path and Scope as the canonical ("primary")
fmt package, but with a different identity.

This change also adds an accessor Package.Primary() that
returns the primary package associated with a secondary
package object, if any.

IMHO the current design is wrong, and the resolver should not
create secondary packages at all.  Even if a package is
imported under a non-default name, as in
    import f "fmt"
    ...
    f.Print
we should just regard f as a reference to the existing package
"fmt", not as the defining identifier for a secondary package.
What we would lose by such a change (the connection of the two
f's in 'f.Print' and 'import f "fmt"') seems a small price to
pay.

This CL is thus just a minimal change to permit clients to
make progress under the status quo.

R=r, gri, crawshaw
CC=golang-dev
https://golang.org/cl/13626043
This commit is contained in:
Alan Donovan 2013-09-10 14:11:17 -04:00
parent 6bc6da88ec
commit 9a9fb35468
2 changed files with 23 additions and 1 deletions

View File

@ -129,6 +129,20 @@ func (obj *object) sameId(pkg *Package, name string) bool {
// re-exported packages; or as a result of type-checking a package // re-exported packages; or as a result of type-checking a package
// that contains errors. // that contains errors.
// //
// There are two kinds of Package objects, primary and secondary.
// A primary Package has no declaring identifier, and is referenced by
// each ast.File.Name within that package.
// A secondary Package object is created for each ast.ImportSpec that
// imports it; its declaring identifier is the ImportSpec.Name (if
// any), and each qualified reference (e.g. fmt.Println) is a
// reference to a secondary Package.
// The Primary() method of a secondary package returns its primary
// package; called on a primary package, it returns nil.
// The Path(), Name() and Scope() attributes of primary and secondary
// Packages are equal.
// TODO(gri): consider whether this distinction carries its weight;
// adonovan thinks not.
//
type Package struct { type Package struct {
object object
path string // import path, "" for current (non-imported) package path string // import path, "" for current (non-imported) package
@ -136,10 +150,11 @@ type Package struct {
imports map[string]*Package // map of import paths to imported packages imports map[string]*Package // map of import paths to imported packages
complete bool // if set, this package is complete complete bool // if set, this package is complete
fake bool // if set, this package is fake (internal use only) fake bool // if set, this package is fake (internal use only)
primary *Package // associated primary package (nil => self)
} }
func NewPackage(pos token.Pos, path, name string, scope *Scope, imports map[string]*Package) *Package { func NewPackage(pos token.Pos, path, name string, scope *Scope, imports map[string]*Package) *Package {
obj := &Package{object{nil, pos, nil, name, Typ[Invalid]}, path, scope, imports, false, false} obj := &Package{object{nil, pos, nil, name, Typ[Invalid]}, path, scope, imports, false, false, nil}
obj.pkg = obj obj.pkg = obj
return obj return obj
} }
@ -149,6 +164,12 @@ func (obj *Package) Path() string { return obj.path }
func (obj *Package) Scope() *Scope { return obj.scope } func (obj *Package) Scope() *Scope { return obj.scope }
func (obj *Package) Imports() map[string]*Package { return obj.imports } func (obj *Package) Imports() map[string]*Package { return obj.imports }
func (obj *Package) Complete() bool { return obj.complete } func (obj *Package) Complete() bool { return obj.complete }
func (obj *Package) Primary() *Package {
if obj.primary != nil {
return obj.primary
}
return obj
}
// MarkComplete marks a package as complete. // MarkComplete marks a package as complete.
func (obj *Package) MarkComplete() { obj.complete = true } func (obj *Package) MarkComplete() { obj.complete = true }

View File

@ -192,6 +192,7 @@ func (check *checker) resolveFiles(files []*ast.File) {
} }
imp2 := NewPackage(s.Pos(), path, name, imp.scope, nil) imp2 := NewPackage(s.Pos(), path, name, imp.scope, nil)
imp2.primary = imp
imp2.complete = imp.complete imp2.complete = imp.complete
imp2.fake = imp.fake imp2.fake = imp.fake
if s.Name != nil { if s.Name != nil {