1
0
mirror of https://github.com/golang/go synced 2024-11-18 19:54:44 -07:00

go.tools/go/types: remove need for global initializer map

Another step towards resolving issue 7114.

LGTM=adonovan
R=adonovan
CC=golang-codereviews
https://golang.org/cl/72260043
This commit is contained in:
Robert Griesemer 2014-03-07 11:03:08 -08:00
parent 6bd3206b1f
commit f06b7e1853
3 changed files with 20 additions and 37 deletions

View File

@ -62,8 +62,7 @@ type checker struct {
funcs []funcInfo // list of functions/methods with correct signatures and non-empty bodies
delayed []func() // delayed checks that require fully setup types
objMap map[Object]*declInfo // if set we are in the package-level declaration phase (otherwise all objects seen must be declared)
initMap map[Object]*declInfo // map of variables/functions with init expressions/bodies
objMap map[Object]*declInfo // map of package-level objects to declaration info
// context within which the current object is type-checked
// (valid only for the duration of type-checking a specific object)
@ -192,22 +191,22 @@ func (check *checker) files(files []*ast.File) (err error) {
}
// addDeclDep adds the dependency edge (check.decl -> to)
// if check.decl exists and to has an init expression.
// if check.decl exists and to has an initializer.
func (check *checker) addDeclDep(to Object) {
from := check.decl
if from == nil {
return // not in a package-level init expression
}
init := check.initMap[to]
if init == nil {
return // to does not have a package-level init expression
decl := check.objMap[to]
if 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] = init
m[to] = decl
}
func (check *checker) recordTypeAndValue(x ast.Expr, typ Type, val exact.Value) {

View File

@ -43,12 +43,8 @@ func (check *checker) objDecl(obj Object, def *Named, path []*TypeName) {
}
d := check.objMap[obj]
if debug && d == nil {
if check.objMap == nil {
check.dump("%s: %s should have been declared (we are inside a function)", obj.Pos(), obj)
unreachable()
}
check.dump("%s: %s should have been forward-declared", obj.Pos(), obj)
if d == nil {
check.dump("%s: %s should have been declared", obj.Pos(), obj)
unreachable()
}

View File

@ -29,6 +29,12 @@ type declInfo struct {
mark int // see check.dependencies
}
// hasInitializer reports whether the declared object has an initialization
// expression or function body.
func (d *declInfo) hasInitializer() bool {
return d.init != nil || d.fdecl != nil && d.fdecl.Body != nil
}
// 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
@ -87,10 +93,7 @@ func (check *checker) resolveFiles(files []*ast.File) {
// independent of source order. Associate methods with receiver
// base type names.
var (
objMap = make(map[Object]*declInfo) // corresponding declaration info
initMap = make(map[Object]*declInfo) // declaration info for objects with initializers
)
var objMap = make(map[Object]*declInfo) // corresponding declaration info
// declare declares obj in the package scope, records its ident -> obj mapping,
// and updates objMap. The object must not be a function or method.
@ -248,9 +251,6 @@ func (check *checker) resolveFiles(files []*ast.File) {
d := &declInfo{file: fileScope, typ: last.Type, init: init}
declare(name, obj, d)
// all constants have an initializer
initMap[obj] = d
}
check.arityMatch(s, last)
@ -275,9 +275,9 @@ func (check *checker) resolveFiles(files []*ast.File) {
lhs[i] = obj
d := d1
var init ast.Expr
if d == nil {
// individual assignments
var init ast.Expr
if i < len(s.Values) {
init = s.Values[i]
}
@ -285,11 +285,6 @@ func (check *checker) resolveFiles(files []*ast.File) {
}
declare(name, obj, d)
// remember variable if it has an initializer
if d1 != nil || init != nil {
initMap[obj] = d
}
}
check.arityMatch(s, nil)
@ -340,10 +335,6 @@ func (check *checker) resolveFiles(files []*ast.File) {
}
info := &declInfo{file: fileScope, fdecl: d}
objMap[obj] = info
// remember function if it has a body (= initializer)
if d.Body != nil {
initMap[obj] = info
}
default:
check.invalidAST(d.Pos(), "unknown ast.Decl node %T", d)
@ -364,13 +355,11 @@ func (check *checker) resolveFiles(files []*ast.File) {
// Phase 3: Typecheck all objects in objMap, but not function bodies.
check.initMap = initMap
check.objMap = objMap // indicate that we are checking package-level declarations (objects may not have a type yet)
check.objMap = objMap
typePath := make([]*TypeName, 0, 8) // pre-allocate space for type declaration paths so that the underlying array is reused
for _, obj := range objectsOf(check.objMap) {
check.objDecl(obj, nil, typePath)
}
check.objMap = nil // not needed anymore
// At this point we may have a non-empty check.methods map; this means that not all
// entries were deleted at the end of typeDecl because the respective receiver base
@ -389,15 +378,14 @@ func (check *checker) resolveFiles(files []*ast.File) {
// may introduce dependencies
initPath := make([]Object, 0, 8) // pre-allocate space for initialization paths so that the underlying array is reused
for _, obj := range objectsOf(initMap) {
for _, obj := range objectsOf(objMap) {
switch obj.(type) {
case *Const, *Var:
if init := initMap[obj]; init != nil {
check.dependencies(obj, init, initPath)
if d := objMap[obj]; d.hasInitializer() {
check.dependencies(obj, d, initPath)
}
}
}
check.initMap = nil // not needed anymore
// Phase 6: Check for declared but not used packages and function variables.
// Note: must happen after checking all functions because function bodies