diff --git a/go/types/check.go b/go/types/check.go index 92980214..3ad2889c 100644 --- a/go/types/check.go +++ b/go/types/check.go @@ -10,6 +10,7 @@ import ( "fmt" "go/ast" "go/token" + "sort" "code.google.com/p/go.tools/go/exact" ) @@ -84,16 +85,10 @@ func (check *checker) addDeclDep(to Object) { if from == nil { return // not in a package-level init expression } - decl := check.objMap[to] - if decl == nil || !decl.hasInitializer() { + if decl := check.objMap[to]; decl == nil || !decl.hasInitializer() { return // to is not a package-level object or has no initializer } - m := from.deps - if m == nil { - m = make(map[Object]*declInfo) - from.deps = m - } - m[to] = decl + from.addDep(to) } func (check *checker) assocMethod(tname string, meth *Func) { @@ -205,6 +200,17 @@ func (check *checker) handleBailout(err *error) { } } +func mapObjects(m map[Object]*declInfo) []Object { + list := make([]Object, len(m)) + i := 0 + for obj := range m { + list[i] = obj + i++ + } + sort.Sort(inSourceOrder(list)) + return list +} + // Files checks the provided files as part of the checker's package. func (check *checker) Files(files []*ast.File) (err error) { defer check.handleBailout(&err) @@ -213,7 +219,8 @@ func (check *checker) Files(files []*ast.File) (err error) { check.collectObjects() - objList := objectsOf(check.objMap) + objList := mapObjects(check.objMap) + check.packageObjects(objList) check.functionBodies() diff --git a/go/types/resolver.go b/go/types/resolver.go index 6dea18b4..18f9b8b1 100644 --- a/go/types/resolver.go +++ b/go/types/resolver.go @@ -25,8 +25,8 @@ type declInfo struct { init ast.Expr // init expression, or nil fdecl *ast.FuncDecl // func declaration, or nil - deps map[Object]*declInfo // init dependencies; lazily allocated - mark int // see check.dependencies + deps map[Object]bool // init dependencies; lazily allocated + mark int // see check.dependencies } // hasInitializer reports whether the declared object has an initialization @@ -35,6 +35,16 @@ func (d *declInfo) hasInitializer() bool { return d.init != nil || d.fdecl != nil && d.fdecl.Body != nil } +// addDep adds obj as a dependency to d. +func (d *declInfo) addDep(obj Object) { + m := d.deps + if m == nil { + m = make(map[Object]bool) + d.deps = m + } + m[obj] = true +} + // arityMatch checks that the lhs and rhs of a const or var decl // have the appropriate number of names and init exprs. For const // decls, init is the value spec providing the init exprs; for @@ -378,8 +388,8 @@ func (check *checker) initDependencies(objList []Object) { for _, obj := range objList { switch obj.(type) { case *Const, *Var: - if d := check.objMap[obj]; d.hasInitializer() { - check.dependencies(obj, d, initPath) + if check.objMap[obj].hasInitializer() { + check.dependencies(obj, initPath) } } } @@ -427,16 +437,11 @@ func (check *checker) unusedImports() { } } -// TODO(gri) Instead of this support function, introduce type -// that combines an map[Object]*declInfo and []Object so that -// we can encapsulate this and don't have to depend on correct -// Pos() information. - -// objectsOf returns the keys of m in source order. -func objectsOf(m map[Object]*declInfo) []Object { - list := make([]Object, len(m)) +func setObjects(set map[Object]bool) []Object { + list := make([]Object, len(set)) i := 0 - for obj := range m { + for obj := range set { + // we don't care about the map element value list[i] = obj i++ } @@ -444,6 +449,11 @@ func objectsOf(m map[Object]*declInfo) []Object { return list } +// TODO(gri) Instead of this support function, introduce type +// that combines an map[Object]*declInfo and []Object so that +// we can encapsulate this and don't have to depend on correct +// Pos() information. + // inSourceOrder implements the sort.Sort interface. type inSourceOrder []Object @@ -455,8 +465,7 @@ func (a inSourceOrder) Swap(i, j int) { a[i], a[j] = a[j], a[i] } // manner and appends the encountered variables in postorder to the Info.InitOrder list. // As a result, that list ends up being sorted topologically in the order of dependencies. // -// The current node is represented by the pair (obj, init); and path contains all nodes -// on the path to the current node (excluding the current node). +// Path contains all nodes on the path to the current node obj (excluding obj). // // To detect cyles, the nodes are marked as follows: Initially, all nodes are unmarked // (declInfo.mark == 0). On the way down, a node is appended to the path, and the node @@ -474,7 +483,8 @@ func (a inSourceOrder) Swap(i, j int) { a[i], a[j] = a[j], a[i] } // start of the cycle in the path. The tail of the path (path[mark-1:]) contains all // nodes of the cycle. // -func (check *checker) dependencies(obj Object, init *declInfo, path []Object) { +func (check *checker) dependencies(obj Object, path []Object) { + init := check.objMap[obj] if init.mark < 0 { return // finished } @@ -516,9 +526,8 @@ func (check *checker) dependencies(obj Object, init *declInfo, path []Object) { path = append(path, obj) // len(path) > 0 init.mark = len(path) // init.mark > 0 - for _, obj := range objectsOf(init.deps) { - dep := init.deps[obj] - check.dependencies(obj, dep, path) + for _, obj := range setObjects(init.deps) { + check.dependencies(obj, path) } init.mark = -1 // init.mark < 0