go.tools/go/types: simplified init dependency data structures
Preparation for fixing issue 7158. LGTM=adonovan R=adonovan CC=golang-codereviews https://golang.org/cl/83160045
This commit is contained in:
parent
fb8f3e8fbf
commit
d7048bec64
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue