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:
parent
5b27bc1db9
commit
8cd6c3be05
|
|
@ -59,12 +59,29 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) {
|
||||||
var objList []Object
|
var objList []Object
|
||||||
var objMap = make(map[Object]*decl)
|
var objMap = make(map[Object]*decl)
|
||||||
var methods []*mdecl
|
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)
|
objList = append(objList, obj)
|
||||||
objMap[obj] = &decl{fileScope, typ, init}
|
objMap[obj] = &decl{fileScope, typ, init}
|
||||||
// TODO(gri) move check.declare call here
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
|
|
@ -104,6 +121,10 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) {
|
||||||
name := imp.name
|
name := imp.name
|
||||||
if s.Name != nil {
|
if s.Name != nil {
|
||||||
name = s.Name.Name
|
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)
|
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
|
// declare all constants
|
||||||
for i, name := range s.Names {
|
for i, name := range s.Names {
|
||||||
obj := NewConst(name.Pos(), pkg, name.Name, nil, exact.MakeInt64(int64(iota)))
|
obj := NewConst(name.Pos(), pkg, name.Name, nil, exact.MakeInt64(int64(iota)))
|
||||||
check.declare(pkg.scope, name, obj)
|
|
||||||
|
|
||||||
var init ast.Expr
|
var init ast.Expr
|
||||||
if i < len(last.Values) {
|
if i < len(last.Values) {
|
||||||
init = last.Values[i]
|
init = last.Values[i]
|
||||||
}
|
}
|
||||||
add(obj, last.Type, init)
|
|
||||||
|
declare(name, obj, last.Type, init)
|
||||||
}
|
}
|
||||||
|
|
||||||
// arity of lhs and rhs must match
|
// 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 {
|
for i, name := range s.Names {
|
||||||
obj := NewVar(name.Pos(), pkg, name.Name, nil)
|
obj := NewVar(name.Pos(), pkg, name.Name, nil)
|
||||||
lhs[i] = obj
|
lhs[i] = obj
|
||||||
check.declare(pkg.scope, name, obj)
|
|
||||||
|
|
||||||
var init ast.Expr
|
var init ast.Expr
|
||||||
switch len(s.Values) {
|
switch len(s.Values) {
|
||||||
|
|
@ -185,7 +205,8 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) {
|
||||||
init = s.Values[i]
|
init = s.Values[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
add(obj, s.Type, init)
|
|
||||||
|
declare(name, obj, s.Type, init)
|
||||||
}
|
}
|
||||||
|
|
||||||
// report if there are too many initialization expressions
|
// report if there are too many initialization expressions
|
||||||
|
|
@ -206,8 +227,7 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) {
|
||||||
|
|
||||||
case *ast.TypeSpec:
|
case *ast.TypeSpec:
|
||||||
obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil)
|
obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil)
|
||||||
check.declare(pkg.scope, s.Name, obj)
|
declare(s.Name, obj, s.Type, nil)
|
||||||
add(obj, s.Type, nil)
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
check.invalidAST(s.Pos(), "unknown ast.Spec node %T", s)
|
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 := NewFunc(d.Name.Pos(), pkg, d.Name.Name, nil)
|
||||||
obj.decl = d
|
obj.decl = d
|
||||||
if obj.name == "init" {
|
declare(d.Name, obj, nil, nil)
|
||||||
// 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)
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
check.invalidAST(d.Pos(), "unknown ast.Decl node %T", d)
|
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 _, scope := range scopes {
|
||||||
for _, obj := range scope.entries {
|
for _, obj := range scope.entries {
|
||||||
if alt := pkg.scope.Lookup(nil, obj.Name()); alt != nil {
|
if alt := pkg.scope.Lookup(nil, obj.Name()); alt != nil {
|
||||||
// TODO(gri) better error message
|
check.errorf(alt.Pos(), "%s already declared in this file through import of package %s", obj.Name(), obj.Pkg().Name())
|
||||||
check.errorf(alt.Pos(), "%s redeclared in this block by 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.
|
// 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.objMap = objMap // indicate that we are checking global declarations (objects may not have a type yet)
|
||||||
check.topScope = pkg.scope
|
|
||||||
for _, obj := range objList {
|
for _, obj := range objList {
|
||||||
if obj.Type() == nil {
|
if obj.Type() == nil {
|
||||||
check.declareObject(obj, nil, false)
|
check.declareObject(obj, nil, false)
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import (
|
||||||
// reflect defines a type "flag" which shows up in the gc export data
|
// reflect defines a type "flag" which shows up in the gc export data
|
||||||
"reflect"
|
"reflect"
|
||||||
. "reflect"
|
. "reflect"
|
||||||
|
init /* ERROR "cannot declare init" */ "fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// reflect.flag must not be visible in this package
|
// reflect.flag must not be visible in this package
|
||||||
|
|
@ -21,7 +22,7 @@ type flag int
|
||||||
type _ reflect /* ERROR "not exported" */ .flag
|
type _ reflect /* ERROR "not exported" */ .flag
|
||||||
|
|
||||||
// dot-imported exported objects may conflict with local objects
|
// 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
|
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
|
// invalid array types
|
||||||
type (
|
type (
|
||||||
iA0 [... /* ERROR "invalid use of '...'" */ ]byte
|
iA0 [... /* ERROR "invalid use of '...'" */ ]byte
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue