mirror of
https://github.com/golang/go
synced 2024-10-01 03:28: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:
parent
6bc6da88ec
commit
9a9fb35468
@ -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
|
||||
// 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 {
|
||||
object
|
||||
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
|
||||
complete bool // if set, this package is complete
|
||||
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 {
|
||||
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
|
||||
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) Imports() map[string]*Package { return obj.imports }
|
||||
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.
|
||||
func (obj *Package) MarkComplete() { obj.complete = true }
|
||||
|
@ -192,6 +192,7 @@ func (check *checker) resolveFiles(files []*ast.File) {
|
||||
}
|
||||
|
||||
imp2 := NewPackage(s.Pos(), path, name, imp.scope, nil)
|
||||
imp2.primary = imp
|
||||
imp2.complete = imp.complete
|
||||
imp2.fake = imp.fake
|
||||
if s.Name != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user