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"
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/token"
|
"go/token"
|
||||||
|
"sort"
|
||||||
|
|
||||||
"code.google.com/p/go.tools/go/exact"
|
"code.google.com/p/go.tools/go/exact"
|
||||||
)
|
)
|
||||||
|
|
@ -84,16 +85,10 @@ func (check *checker) addDeclDep(to Object) {
|
||||||
if from == nil {
|
if from == nil {
|
||||||
return // not in a package-level init expression
|
return // not in a package-level init expression
|
||||||
}
|
}
|
||||||
decl := check.objMap[to]
|
if decl := check.objMap[to]; decl == nil || !decl.hasInitializer() {
|
||||||
if decl == nil || !decl.hasInitializer() {
|
|
||||||
return // to is not a package-level object or has no initializer
|
return // to is not a package-level object or has no initializer
|
||||||
}
|
}
|
||||||
m := from.deps
|
from.addDep(to)
|
||||||
if m == nil {
|
|
||||||
m = make(map[Object]*declInfo)
|
|
||||||
from.deps = m
|
|
||||||
}
|
|
||||||
m[to] = decl
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (check *checker) assocMethod(tname string, meth *Func) {
|
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.
|
// Files checks the provided files as part of the checker's package.
|
||||||
func (check *checker) Files(files []*ast.File) (err error) {
|
func (check *checker) Files(files []*ast.File) (err error) {
|
||||||
defer check.handleBailout(&err)
|
defer check.handleBailout(&err)
|
||||||
|
|
@ -213,7 +219,8 @@ func (check *checker) Files(files []*ast.File) (err error) {
|
||||||
|
|
||||||
check.collectObjects()
|
check.collectObjects()
|
||||||
|
|
||||||
objList := objectsOf(check.objMap)
|
objList := mapObjects(check.objMap)
|
||||||
|
|
||||||
check.packageObjects(objList)
|
check.packageObjects(objList)
|
||||||
|
|
||||||
check.functionBodies()
|
check.functionBodies()
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,8 @@ type declInfo struct {
|
||||||
init ast.Expr // init expression, or nil
|
init ast.Expr // init expression, or nil
|
||||||
fdecl *ast.FuncDecl // func declaration, or nil
|
fdecl *ast.FuncDecl // func declaration, or nil
|
||||||
|
|
||||||
deps map[Object]*declInfo // init dependencies; lazily allocated
|
deps map[Object]bool // init dependencies; lazily allocated
|
||||||
mark int // see check.dependencies
|
mark int // see check.dependencies
|
||||||
}
|
}
|
||||||
|
|
||||||
// hasInitializer reports whether the declared object has an initialization
|
// 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
|
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
|
// arityMatch checks that the lhs and rhs of a const or var decl
|
||||||
// have the appropriate number of names and init exprs. For const
|
// have the appropriate number of names and init exprs. For const
|
||||||
// decls, init is the value spec providing the init exprs; for
|
// 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 {
|
for _, obj := range objList {
|
||||||
switch obj.(type) {
|
switch obj.(type) {
|
||||||
case *Const, *Var:
|
case *Const, *Var:
|
||||||
if d := check.objMap[obj]; d.hasInitializer() {
|
if check.objMap[obj].hasInitializer() {
|
||||||
check.dependencies(obj, d, initPath)
|
check.dependencies(obj, initPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -427,16 +437,11 @@ func (check *checker) unusedImports() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(gri) Instead of this support function, introduce type
|
func setObjects(set map[Object]bool) []Object {
|
||||||
// that combines an map[Object]*declInfo and []Object so that
|
list := make([]Object, len(set))
|
||||||
// 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))
|
|
||||||
i := 0
|
i := 0
|
||||||
for obj := range m {
|
for obj := range set {
|
||||||
|
// we don't care about the map element value
|
||||||
list[i] = obj
|
list[i] = obj
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
@ -444,6 +449,11 @@ func objectsOf(m map[Object]*declInfo) []Object {
|
||||||
return list
|
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.
|
// inSourceOrder implements the sort.Sort interface.
|
||||||
type inSourceOrder []Object
|
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.
|
// 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.
|
// 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
|
// Path contains all nodes on the path to the current node obj (excluding obj).
|
||||||
// on the path to the current node (excluding the current node).
|
|
||||||
//
|
//
|
||||||
// To detect cyles, the nodes are marked as follows: Initially, all nodes are unmarked
|
// 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
|
// (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
|
// start of the cycle in the path. The tail of the path (path[mark-1:]) contains all
|
||||||
// nodes of the cycle.
|
// 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 {
|
if init.mark < 0 {
|
||||||
return // finished
|
return // finished
|
||||||
}
|
}
|
||||||
|
|
@ -516,9 +526,8 @@ func (check *checker) dependencies(obj Object, init *declInfo, path []Object) {
|
||||||
|
|
||||||
path = append(path, obj) // len(path) > 0
|
path = append(path, obj) // len(path) > 0
|
||||||
init.mark = len(path) // init.mark > 0
|
init.mark = len(path) // init.mark > 0
|
||||||
for _, obj := range objectsOf(init.deps) {
|
for _, obj := range setObjects(init.deps) {
|
||||||
dep := init.deps[obj]
|
check.dependencies(obj, path)
|
||||||
check.dependencies(obj, dep, path)
|
|
||||||
}
|
}
|
||||||
init.mark = -1 // init.mark < 0
|
init.mark = -1 // init.mark < 0
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue