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:
parent
6bd3206b1f
commit
f06b7e1853
@ -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) {
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user