go.tools/go/types: check for non-func init declarations

R=adonovan
CC=golang-dev
https://golang.org/cl/11075043
This commit is contained in:
Robert Griesemer 2013-07-09 21:13:37 -07:00
parent 5b27bc1db9
commit 8cd6c3be05
2 changed files with 45 additions and 22 deletions

View File

@ -59,12 +59,29 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) {
var objList []Object
var objMap = make(map[Object]*decl)
var methods []*mdecl
var fileScope *Scope // current file scope, used by add
var fileScope *Scope // current file scope, used by collect
declare := func(ident *ast.Ident, obj Object, typ, init ast.Expr) {
assert(ident.Name == obj.Name())
// spec: "A package-scope or file-scope identifier with name init
// may only be declared to be a function with this (func()) signature."
if ident.Name == "init" {
f, _ := obj.(*Func)
if f == nil {
check.callIdent(ident, nil)
check.errorf(ident.Pos(), "cannot declare init - must be func")
return
}
// don't declare init functions in the package scope - they are invisible
f.parent = pkg.scope
check.callIdent(ident, obj)
} else {
check.declare(pkg.scope, ident, obj)
}
add := func(obj Object, typ, init ast.Expr) {
objList = append(objList, obj)
objMap[obj] = &decl{fileScope, typ, init}
// TODO(gri) move check.declare call here
}
for _, file := range files {
@ -104,6 +121,10 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) {
name := imp.name
if s.Name != nil {
name = s.Name.Name
if name == "init" {
check.errorf(s.Name.Pos(), "cannot declare init - must be func")
continue
}
}
imp2 := NewPackage(s.Pos(), path, name, imp.scope, nil, imp.complete)
@ -143,13 +164,13 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) {
// declare all constants
for i, name := range s.Names {
obj := NewConst(name.Pos(), pkg, name.Name, nil, exact.MakeInt64(int64(iota)))
check.declare(pkg.scope, name, obj)
var init ast.Expr
if i < len(last.Values) {
init = last.Values[i]
}
add(obj, last.Type, init)
declare(name, obj, last.Type, init)
}
// arity of lhs and rhs must match
@ -170,7 +191,6 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) {
for i, name := range s.Names {
obj := NewVar(name.Pos(), pkg, name.Name, nil)
lhs[i] = obj
check.declare(pkg.scope, name, obj)
var init ast.Expr
switch len(s.Values) {
@ -185,7 +205,8 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) {
init = s.Values[i]
}
}
add(obj, s.Type, init)
declare(name, obj, s.Type, init)
}
// report if there are too many initialization expressions
@ -206,8 +227,7 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) {
case *ast.TypeSpec:
obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil)
check.declare(pkg.scope, s.Name, obj)
add(obj, s.Type, nil)
declare(s.Name, obj, s.Type, nil)
default:
check.invalidAST(s.Pos(), "unknown ast.Spec node %T", s)
@ -222,14 +242,7 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) {
}
obj := NewFunc(d.Name.Pos(), pkg, d.Name.Name, nil)
obj.decl = d
if obj.name == "init" {
// init functions are not visible - don't declare them in package scope
obj.parent = pkg.scope
check.callIdent(d.Name, obj)
} else {
check.declare(pkg.scope, d.Name, obj)
}
add(obj, nil, nil)
declare(d.Name, obj, nil, nil)
default:
check.invalidAST(d.Pos(), "unknown ast.Decl node %T", d)
@ -241,8 +254,7 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) {
for _, scope := range scopes {
for _, obj := range scope.entries {
if alt := pkg.scope.Lookup(nil, obj.Name()); alt != nil {
// TODO(gri) better error message
check.errorf(alt.Pos(), "%s redeclared in this block by import of package %s", obj.Name(), obj.Pkg().Name())
check.errorf(alt.Pos(), "%s already declared in this file through import of package %s", obj.Name(), obj.Pkg().Name())
}
}
}
@ -306,8 +318,7 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) {
// Phase 4) Typecheck all objects in objList but not function bodies.
check.objMap = objMap // indicate we are doing global declarations (objects may not have a type yet)
check.topScope = pkg.scope
check.objMap = objMap // indicate that we are checking global declarations (objects may not have a type yet)
for _, obj := range objList {
if obj.Type() == nil {
check.declareObject(obj, nil, false)

View File

@ -14,6 +14,7 @@ import (
// reflect defines a type "flag" which shows up in the gc export data
"reflect"
. "reflect"
init /* ERROR "cannot declare init" */ "fmt"
)
// reflect.flag must not be visible in this package
@ -21,7 +22,7 @@ type flag int
type _ reflect /* ERROR "not exported" */ .flag
// dot-imported exported objects may conflict with local objects
type Value /* ERROR "redeclared in this block by import" */ struct{}
type Value /* ERROR "already declared in this file" */ struct{}
const pi = 3.1415
@ -50,6 +51,17 @@ type (
)
// declarations of init
const _, init /* ERROR "cannot declare init" */ , _ = 0, 1, 2
type init /* ERROR "cannot declare init" */ struct{}
var _, init /* ERROR "cannot declare init" */ int
func init() {}
func _() { const init = 0 }
func _() { type init int }
func _() { var init int }
// invalid array types
type (
iA0 [... /* ERROR "invalid use of '...'" */ ]byte