go.tools/go/types: various cleanups - no semantic changes
- split resolver.go into resolver.go and decl.go - renamed types.go -> type.go - renamed objects.go -> object.go LGTM=adonovan R=adonovan CC=golang-codereviews https://golang.org/cl/58010043
This commit is contained in:
parent
efd232e270
commit
c4535ece1b
|
@ -0,0 +1,369 @@
|
|||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/token"
|
||||
|
||||
"code.google.com/p/go.tools/go/exact"
|
||||
)
|
||||
|
||||
func (check *checker) reportAltDecl(obj Object) {
|
||||
if pos := obj.Pos(); pos.IsValid() {
|
||||
// We use "other" rather than "previous" here because
|
||||
// the first declaration seen may not be textually
|
||||
// earlier in the source.
|
||||
check.errorf(pos, "\tother declaration of %s", obj.Name()) // secondary error, \t indented
|
||||
}
|
||||
}
|
||||
|
||||
func (check *checker) declare(scope *Scope, id *ast.Ident, obj Object) {
|
||||
if alt := scope.Insert(obj); alt != nil {
|
||||
check.errorf(obj.Pos(), "%s redeclared in this block", obj.Name())
|
||||
check.reportAltDecl(alt)
|
||||
return
|
||||
}
|
||||
if id != nil {
|
||||
check.recordObject(id, obj)
|
||||
}
|
||||
}
|
||||
|
||||
// objDecl type-checks the declaration of obj in its respective file scope.
|
||||
// See typeDecl for the details on def and cycleOk.
|
||||
func (check *checker) objDecl(obj Object, def *Named, cycleOk bool) {
|
||||
d := check.objMap[obj]
|
||||
|
||||
// adjust file scope for current object
|
||||
oldScope := check.topScope
|
||||
check.topScope = d.file // for lookup
|
||||
|
||||
// save current iota
|
||||
oldIota := check.iota
|
||||
check.iota = nil
|
||||
|
||||
// save current decl
|
||||
oldDecl := check.decl
|
||||
check.decl = nil
|
||||
|
||||
switch obj := obj.(type) {
|
||||
case *Const:
|
||||
check.constDecl(obj, d.typ, d.init)
|
||||
case *Var:
|
||||
check.decl = d // new package-level var decl
|
||||
check.varDecl(obj, d.lhs, d.typ, d.init)
|
||||
case *TypeName:
|
||||
check.typeDecl(obj, d.typ, def, cycleOk)
|
||||
case *Func:
|
||||
check.funcDecl(obj, d)
|
||||
default:
|
||||
unreachable()
|
||||
}
|
||||
|
||||
check.decl = oldDecl
|
||||
check.iota = oldIota
|
||||
check.topScope = oldScope
|
||||
}
|
||||
|
||||
func (check *checker) constDecl(obj *Const, typ, init ast.Expr) {
|
||||
if obj.visited {
|
||||
check.errorf(obj.Pos(), "illegal cycle in initialization of constant %s", obj.name)
|
||||
obj.typ = Typ[Invalid]
|
||||
return
|
||||
}
|
||||
obj.visited = true
|
||||
|
||||
// use the correct value of iota
|
||||
assert(check.iota == nil)
|
||||
check.iota = obj.val
|
||||
|
||||
// determine type, if any
|
||||
if typ != nil {
|
||||
t := check.typ(typ, nil, false)
|
||||
if !isConstType(t) {
|
||||
check.errorf(typ.Pos(), "invalid constant type %s", t)
|
||||
obj.typ = Typ[Invalid]
|
||||
check.iota = nil
|
||||
return
|
||||
}
|
||||
obj.typ = t
|
||||
}
|
||||
|
||||
// check initialization
|
||||
var x operand
|
||||
if init != nil {
|
||||
check.expr(&x, init)
|
||||
}
|
||||
check.initConst(obj, &x)
|
||||
|
||||
check.iota = nil
|
||||
}
|
||||
|
||||
// TODO(gri) document arguments
|
||||
func (check *checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) {
|
||||
if obj.visited {
|
||||
check.errorf(obj.Pos(), "illegal cycle in initialization of variable %s", obj.name)
|
||||
obj.typ = Typ[Invalid]
|
||||
return
|
||||
}
|
||||
obj.visited = true
|
||||
|
||||
// var declarations cannot use iota
|
||||
assert(check.iota == nil)
|
||||
|
||||
// determine type, if any
|
||||
if typ != nil {
|
||||
obj.typ = check.typ(typ, nil, false)
|
||||
}
|
||||
|
||||
// check initialization
|
||||
if init == nil {
|
||||
if typ == nil {
|
||||
// error reported before by arityMatch
|
||||
obj.typ = Typ[Invalid]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if lhs == nil || len(lhs) == 1 {
|
||||
assert(lhs == nil || lhs[0] == obj)
|
||||
var x operand
|
||||
check.expr(&x, init)
|
||||
check.initVar(obj, &x)
|
||||
return
|
||||
}
|
||||
|
||||
if debug {
|
||||
// obj must be one of lhs
|
||||
found := false
|
||||
for _, lhs := range lhs {
|
||||
if obj == lhs {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
panic("inconsistent lhs")
|
||||
}
|
||||
}
|
||||
check.initVars(lhs, []ast.Expr{init}, token.NoPos)
|
||||
}
|
||||
|
||||
func (check *checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, cycleOk bool) {
|
||||
assert(obj.Type() == nil)
|
||||
|
||||
// type declarations cannot use iota
|
||||
assert(check.iota == nil)
|
||||
|
||||
named := &Named{obj: obj}
|
||||
obj.typ = named // make sure recursive type declarations terminate
|
||||
|
||||
// If this type (named) defines the type of another (def) type declaration,
|
||||
// set def's underlying type to this type so that we can resolve the true
|
||||
// underlying of def later.
|
||||
if def != nil {
|
||||
def.underlying = named
|
||||
}
|
||||
|
||||
// Typecheck typ - it may be a named type that is not yet complete.
|
||||
// For instance, consider:
|
||||
//
|
||||
// type (
|
||||
// A B
|
||||
// B *C
|
||||
// C A
|
||||
// )
|
||||
//
|
||||
// When we declare object C, typ is the identifier A which is incomplete.
|
||||
u := check.typ(typ, named, cycleOk)
|
||||
|
||||
// Determine the unnamed underlying type.
|
||||
// In the above example, the underlying type of A was (temporarily) set
|
||||
// to B whose underlying type was set to *C. Such "forward chains" always
|
||||
// end in an unnamed type (cycles are terminated with an invalid type).
|
||||
for {
|
||||
n, _ := u.(*Named)
|
||||
if n == nil {
|
||||
break
|
||||
}
|
||||
u = n.underlying
|
||||
}
|
||||
named.underlying = u
|
||||
|
||||
// the underlying type has been determined
|
||||
named.complete = true
|
||||
|
||||
// type-check signatures of associated methods
|
||||
methods := check.methods[obj.name]
|
||||
if len(methods) == 0 {
|
||||
return // no methods
|
||||
}
|
||||
|
||||
// spec: "For a base type, the non-blank names of methods bound
|
||||
// to it must be unique."
|
||||
// => use an objset to determine redeclarations
|
||||
var mset objset
|
||||
|
||||
// spec: "If the base type is a struct type, the non-blank method
|
||||
// and field names must be distinct."
|
||||
// => pre-populate the objset to find conflicts
|
||||
// TODO(gri) consider keeping the objset with the struct instead
|
||||
if t, _ := named.underlying.(*Struct); t != nil {
|
||||
for _, fld := range t.fields {
|
||||
if fld.name != "_" {
|
||||
assert(mset.insert(fld) == nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check each method
|
||||
for _, m := range methods {
|
||||
if m.name != "_" {
|
||||
if alt := mset.insert(m); alt != nil {
|
||||
switch alt.(type) {
|
||||
case *Var:
|
||||
check.errorf(m.pos, "field and method with the same name %s", m.name)
|
||||
case *Func:
|
||||
check.errorf(m.pos, "method %s already declared for %s", m.name, named)
|
||||
default:
|
||||
unreachable()
|
||||
}
|
||||
check.reportAltDecl(alt)
|
||||
continue
|
||||
}
|
||||
}
|
||||
check.recordObject(check.objMap[m].fdecl.Name, m)
|
||||
check.objDecl(m, nil, true)
|
||||
// Methods with blank _ names cannot be found.
|
||||
// Don't add them to the method list.
|
||||
if m.name != "_" {
|
||||
named.methods = append(named.methods, m)
|
||||
}
|
||||
}
|
||||
|
||||
delete(check.methods, obj.name) // we don't need them anymore
|
||||
}
|
||||
|
||||
type funcInfo struct {
|
||||
name string // for tracing only
|
||||
info *declInfo // for cycle detection
|
||||
sig *Signature
|
||||
body *ast.BlockStmt
|
||||
}
|
||||
|
||||
func (check *checker) funcDecl(obj *Func, info *declInfo) {
|
||||
// func declarations cannot use iota
|
||||
assert(check.iota == nil)
|
||||
|
||||
obj.typ = Typ[Invalid] // guard against cycles
|
||||
fdecl := info.fdecl
|
||||
sig := check.funcType(fdecl.Recv, fdecl.Type, nil)
|
||||
if sig.recv == nil && obj.name == "init" && (sig.params.Len() > 0 || sig.results.Len() > 0) {
|
||||
check.errorf(fdecl.Pos(), "func init must have no arguments and no return values")
|
||||
// ok to continue
|
||||
}
|
||||
obj.typ = sig
|
||||
|
||||
// function body must be type-checked after global declarations
|
||||
// (functions implemented elsewhere have no body)
|
||||
if !check.conf.IgnoreFuncBodies && fdecl.Body != nil {
|
||||
check.funcList = append(check.funcList, funcInfo{obj.name, info, sig, fdecl.Body})
|
||||
}
|
||||
}
|
||||
|
||||
func (check *checker) declStmt(decl ast.Decl) {
|
||||
pkg := check.pkg
|
||||
|
||||
switch d := decl.(type) {
|
||||
case *ast.BadDecl:
|
||||
// ignore
|
||||
|
||||
case *ast.GenDecl:
|
||||
var last *ast.ValueSpec // last ValueSpec with type or init exprs seen
|
||||
for iota, spec := range d.Specs {
|
||||
switch s := spec.(type) {
|
||||
case *ast.ValueSpec:
|
||||
switch d.Tok {
|
||||
case token.CONST:
|
||||
// determine which init exprs to use
|
||||
switch {
|
||||
case s.Type != nil || len(s.Values) > 0:
|
||||
last = s
|
||||
case last == nil:
|
||||
last = new(ast.ValueSpec) // make sure last exists
|
||||
}
|
||||
|
||||
// declare all constants
|
||||
lhs := make([]*Const, len(s.Names))
|
||||
for i, name := range s.Names {
|
||||
obj := NewConst(name.Pos(), pkg, name.Name, nil, exact.MakeInt64(int64(iota)))
|
||||
lhs[i] = obj
|
||||
|
||||
var init ast.Expr
|
||||
if i < len(last.Values) {
|
||||
init = last.Values[i]
|
||||
}
|
||||
|
||||
check.constDecl(obj, last.Type, init)
|
||||
}
|
||||
|
||||
check.arityMatch(s, last)
|
||||
|
||||
for i, name := range s.Names {
|
||||
check.declare(check.topScope, name, lhs[i])
|
||||
}
|
||||
|
||||
case token.VAR:
|
||||
lhs0 := make([]*Var, len(s.Names))
|
||||
for i, name := range s.Names {
|
||||
lhs0[i] = NewVar(name.Pos(), pkg, name.Name, nil)
|
||||
}
|
||||
|
||||
// initialize all variables
|
||||
for i, obj := range lhs0 {
|
||||
var lhs []*Var
|
||||
var init ast.Expr
|
||||
switch len(s.Values) {
|
||||
case len(s.Names):
|
||||
// lhs and rhs match
|
||||
init = s.Values[i]
|
||||
case 1:
|
||||
// rhs is expected to be a multi-valued expression
|
||||
lhs = lhs0
|
||||
init = s.Values[0]
|
||||
default:
|
||||
if i < len(s.Values) {
|
||||
init = s.Values[i]
|
||||
}
|
||||
}
|
||||
check.varDecl(obj, lhs, s.Type, init)
|
||||
}
|
||||
|
||||
check.arityMatch(s, nil)
|
||||
|
||||
// declare all variables
|
||||
// (only at this point are the variable scopes (parents) set)
|
||||
for i, name := range s.Names {
|
||||
check.declare(check.topScope, name, lhs0[i])
|
||||
}
|
||||
|
||||
default:
|
||||
check.invalidAST(s.Pos(), "invalid token %s", d.Tok)
|
||||
}
|
||||
|
||||
case *ast.TypeSpec:
|
||||
obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil)
|
||||
check.declare(check.topScope, s.Name, obj)
|
||||
check.typeDecl(obj, s.Type, nil, false)
|
||||
|
||||
default:
|
||||
check.invalidAST(s.Pos(), "const, type, or var declaration expected")
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
check.invalidAST(d.Pos(), "unknown ast.Decl node %T", d)
|
||||
}
|
||||
}
|
|
@ -17,26 +17,6 @@ import (
|
|||
"code.google.com/p/go.tools/go/exact"
|
||||
)
|
||||
|
||||
func (check *checker) reportAltDecl(obj Object) {
|
||||
if pos := obj.Pos(); pos.IsValid() {
|
||||
// We use "other" rather than "previous" here because
|
||||
// the first declaration seen may not be textually
|
||||
// earlier in the source.
|
||||
check.errorf(pos, "\tother declaration of %s", obj.Name()) // secondary error, \t indented
|
||||
}
|
||||
}
|
||||
|
||||
func (check *checker) declare(scope *Scope, id *ast.Ident, obj Object) {
|
||||
if alt := scope.Insert(obj); alt != nil {
|
||||
check.errorf(obj.Pos(), "%s redeclared in this block", obj.Name())
|
||||
check.reportAltDecl(alt)
|
||||
return
|
||||
}
|
||||
if id != nil {
|
||||
check.recordObject(id, obj)
|
||||
}
|
||||
}
|
||||
|
||||
// A declInfo describes a package-level const, type, var, or func declaration.
|
||||
type declInfo struct {
|
||||
file *Scope // scope of file containing this declaration
|
||||
|
@ -49,13 +29,6 @@ type declInfo struct {
|
|||
mark int // see check.dependencies
|
||||
}
|
||||
|
||||
type funcInfo struct {
|
||||
name string // for tracing only
|
||||
info *declInfo // for cycle detection
|
||||
sig *Signature
|
||||
body *ast.BlockStmt
|
||||
}
|
||||
|
||||
// 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
|
||||
|
@ -564,333 +537,3 @@ func (check *checker) dependencies(obj Object, init *declInfo, path []Object) {
|
|||
check.Info.InitOrder = append(check.Info.InitOrder, &Initializer{initLhs, init.init})
|
||||
}
|
||||
}
|
||||
|
||||
// objDecl type-checks the declaration of obj in its respective file scope.
|
||||
// See typeDecl for the details on def and cycleOk.
|
||||
func (check *checker) objDecl(obj Object, def *Named, cycleOk bool) {
|
||||
d := check.objMap[obj]
|
||||
|
||||
// adjust file scope for current object
|
||||
oldScope := check.topScope
|
||||
check.topScope = d.file // for lookup
|
||||
|
||||
// save current iota
|
||||
oldIota := check.iota
|
||||
check.iota = nil
|
||||
|
||||
// save current decl
|
||||
oldDecl := check.decl
|
||||
check.decl = nil
|
||||
|
||||
switch obj := obj.(type) {
|
||||
case *Const:
|
||||
check.constDecl(obj, d.typ, d.init)
|
||||
case *Var:
|
||||
check.decl = d // new package-level var decl
|
||||
check.varDecl(obj, d.lhs, d.typ, d.init)
|
||||
case *TypeName:
|
||||
check.typeDecl(obj, d.typ, def, cycleOk)
|
||||
case *Func:
|
||||
check.funcDecl(obj, d)
|
||||
default:
|
||||
unreachable()
|
||||
}
|
||||
|
||||
check.decl = oldDecl
|
||||
check.iota = oldIota
|
||||
check.topScope = oldScope
|
||||
}
|
||||
|
||||
func (check *checker) constDecl(obj *Const, typ, init ast.Expr) {
|
||||
if obj.visited {
|
||||
check.errorf(obj.Pos(), "illegal cycle in initialization of constant %s", obj.name)
|
||||
obj.typ = Typ[Invalid]
|
||||
return
|
||||
}
|
||||
obj.visited = true
|
||||
|
||||
// use the correct value of iota
|
||||
assert(check.iota == nil)
|
||||
check.iota = obj.val
|
||||
|
||||
// determine type, if any
|
||||
if typ != nil {
|
||||
t := check.typ(typ, nil, false)
|
||||
if !isConstType(t) {
|
||||
check.errorf(typ.Pos(), "invalid constant type %s", t)
|
||||
obj.typ = Typ[Invalid]
|
||||
check.iota = nil
|
||||
return
|
||||
}
|
||||
obj.typ = t
|
||||
}
|
||||
|
||||
// check initialization
|
||||
var x operand
|
||||
if init != nil {
|
||||
check.expr(&x, init)
|
||||
}
|
||||
check.initConst(obj, &x)
|
||||
|
||||
check.iota = nil
|
||||
}
|
||||
|
||||
// TODO(gri) document arguments
|
||||
func (check *checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) {
|
||||
if obj.visited {
|
||||
check.errorf(obj.Pos(), "illegal cycle in initialization of variable %s", obj.name)
|
||||
obj.typ = Typ[Invalid]
|
||||
return
|
||||
}
|
||||
obj.visited = true
|
||||
|
||||
// var declarations cannot use iota
|
||||
assert(check.iota == nil)
|
||||
|
||||
// determine type, if any
|
||||
if typ != nil {
|
||||
obj.typ = check.typ(typ, nil, false)
|
||||
}
|
||||
|
||||
// check initialization
|
||||
if init == nil {
|
||||
if typ == nil {
|
||||
// error reported before by arityMatch
|
||||
obj.typ = Typ[Invalid]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if lhs == nil || len(lhs) == 1 {
|
||||
assert(lhs == nil || lhs[0] == obj)
|
||||
var x operand
|
||||
check.expr(&x, init)
|
||||
check.initVar(obj, &x)
|
||||
return
|
||||
}
|
||||
|
||||
if debug {
|
||||
// obj must be one of lhs
|
||||
found := false
|
||||
for _, lhs := range lhs {
|
||||
if obj == lhs {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
panic("inconsistent lhs")
|
||||
}
|
||||
}
|
||||
check.initVars(lhs, []ast.Expr{init}, token.NoPos)
|
||||
}
|
||||
|
||||
func (check *checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, cycleOk bool) {
|
||||
assert(obj.Type() == nil)
|
||||
|
||||
// type declarations cannot use iota
|
||||
assert(check.iota == nil)
|
||||
|
||||
named := &Named{obj: obj}
|
||||
obj.typ = named // make sure recursive type declarations terminate
|
||||
|
||||
// If this type (named) defines the type of another (def) type declaration,
|
||||
// set def's underlying type to this type so that we can resolve the true
|
||||
// underlying of def later.
|
||||
if def != nil {
|
||||
def.underlying = named
|
||||
}
|
||||
|
||||
// Typecheck typ - it may be a named type that is not yet complete.
|
||||
// For instance, consider:
|
||||
//
|
||||
// type (
|
||||
// A B
|
||||
// B *C
|
||||
// C A
|
||||
// )
|
||||
//
|
||||
// When we declare object C, typ is the identifier A which is incomplete.
|
||||
u := check.typ(typ, named, cycleOk)
|
||||
|
||||
// Determine the unnamed underlying type.
|
||||
// In the above example, the underlying type of A was (temporarily) set
|
||||
// to B whose underlying type was set to *C. Such "forward chains" always
|
||||
// end in an unnamed type (cycles are terminated with an invalid type).
|
||||
for {
|
||||
n, _ := u.(*Named)
|
||||
if n == nil {
|
||||
break
|
||||
}
|
||||
u = n.underlying
|
||||
}
|
||||
named.underlying = u
|
||||
|
||||
// the underlying type has been determined
|
||||
named.complete = true
|
||||
|
||||
// type-check signatures of associated methods
|
||||
methods := check.methods[obj.name]
|
||||
if len(methods) == 0 {
|
||||
return // no methods
|
||||
}
|
||||
|
||||
// spec: "For a base type, the non-blank names of methods bound
|
||||
// to it must be unique."
|
||||
// => use an objset to determine redeclarations
|
||||
var mset objset
|
||||
|
||||
// spec: "If the base type is a struct type, the non-blank method
|
||||
// and field names must be distinct."
|
||||
// => pre-populate the objset to find conflicts
|
||||
// TODO(gri) consider keeping the objset with the struct instead
|
||||
if t, _ := named.underlying.(*Struct); t != nil {
|
||||
for _, fld := range t.fields {
|
||||
if fld.name != "_" {
|
||||
assert(mset.insert(fld) == nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check each method
|
||||
for _, m := range methods {
|
||||
if m.name != "_" {
|
||||
if alt := mset.insert(m); alt != nil {
|
||||
switch alt.(type) {
|
||||
case *Var:
|
||||
check.errorf(m.pos, "field and method with the same name %s", m.name)
|
||||
case *Func:
|
||||
check.errorf(m.pos, "method %s already declared for %s", m.name, named)
|
||||
default:
|
||||
unreachable()
|
||||
}
|
||||
check.reportAltDecl(alt)
|
||||
continue
|
||||
}
|
||||
}
|
||||
check.recordObject(check.objMap[m].fdecl.Name, m)
|
||||
check.objDecl(m, nil, true)
|
||||
// Methods with blank _ names cannot be found.
|
||||
// Don't add them to the method list.
|
||||
if m.name != "_" {
|
||||
named.methods = append(named.methods, m)
|
||||
}
|
||||
}
|
||||
|
||||
delete(check.methods, obj.name) // we don't need them anymore
|
||||
}
|
||||
|
||||
func (check *checker) funcDecl(obj *Func, info *declInfo) {
|
||||
// func declarations cannot use iota
|
||||
assert(check.iota == nil)
|
||||
|
||||
obj.typ = Typ[Invalid] // guard against cycles
|
||||
fdecl := info.fdecl
|
||||
sig := check.funcType(fdecl.Recv, fdecl.Type, nil)
|
||||
if sig.recv == nil && obj.name == "init" && (sig.params.Len() > 0 || sig.results.Len() > 0) {
|
||||
check.errorf(fdecl.Pos(), "func init must have no arguments and no return values")
|
||||
// ok to continue
|
||||
}
|
||||
obj.typ = sig
|
||||
|
||||
// function body must be type-checked after global declarations
|
||||
// (functions implemented elsewhere have no body)
|
||||
if !check.conf.IgnoreFuncBodies && fdecl.Body != nil {
|
||||
check.funcList = append(check.funcList, funcInfo{obj.name, info, sig, fdecl.Body})
|
||||
}
|
||||
}
|
||||
|
||||
func (check *checker) declStmt(decl ast.Decl) {
|
||||
pkg := check.pkg
|
||||
|
||||
switch d := decl.(type) {
|
||||
case *ast.BadDecl:
|
||||
// ignore
|
||||
|
||||
case *ast.GenDecl:
|
||||
var last *ast.ValueSpec // last ValueSpec with type or init exprs seen
|
||||
for iota, spec := range d.Specs {
|
||||
switch s := spec.(type) {
|
||||
case *ast.ValueSpec:
|
||||
switch d.Tok {
|
||||
case token.CONST:
|
||||
// determine which init exprs to use
|
||||
switch {
|
||||
case s.Type != nil || len(s.Values) > 0:
|
||||
last = s
|
||||
case last == nil:
|
||||
last = new(ast.ValueSpec) // make sure last exists
|
||||
}
|
||||
|
||||
// declare all constants
|
||||
lhs := make([]*Const, len(s.Names))
|
||||
for i, name := range s.Names {
|
||||
obj := NewConst(name.Pos(), pkg, name.Name, nil, exact.MakeInt64(int64(iota)))
|
||||
lhs[i] = obj
|
||||
|
||||
var init ast.Expr
|
||||
if i < len(last.Values) {
|
||||
init = last.Values[i]
|
||||
}
|
||||
|
||||
check.constDecl(obj, last.Type, init)
|
||||
}
|
||||
|
||||
check.arityMatch(s, last)
|
||||
|
||||
for i, name := range s.Names {
|
||||
check.declare(check.topScope, name, lhs[i])
|
||||
}
|
||||
|
||||
case token.VAR:
|
||||
lhs0 := make([]*Var, len(s.Names))
|
||||
for i, name := range s.Names {
|
||||
lhs0[i] = NewVar(name.Pos(), pkg, name.Name, nil)
|
||||
}
|
||||
|
||||
// initialize all variables
|
||||
for i, obj := range lhs0 {
|
||||
var lhs []*Var
|
||||
var init ast.Expr
|
||||
switch len(s.Values) {
|
||||
case len(s.Names):
|
||||
// lhs and rhs match
|
||||
init = s.Values[i]
|
||||
case 1:
|
||||
// rhs is expected to be a multi-valued expression
|
||||
lhs = lhs0
|
||||
init = s.Values[0]
|
||||
default:
|
||||
if i < len(s.Values) {
|
||||
init = s.Values[i]
|
||||
}
|
||||
}
|
||||
check.varDecl(obj, lhs, s.Type, init)
|
||||
}
|
||||
|
||||
check.arityMatch(s, nil)
|
||||
|
||||
// declare all variables
|
||||
// (only at this point are the variable scopes (parents) set)
|
||||
for i, name := range s.Names {
|
||||
check.declare(check.topScope, name, lhs0[i])
|
||||
}
|
||||
|
||||
default:
|
||||
check.invalidAST(s.Pos(), "invalid token %s", d.Tok)
|
||||
}
|
||||
|
||||
case *ast.TypeSpec:
|
||||
obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil)
|
||||
check.declare(check.topScope, s.Name, obj)
|
||||
check.typeDecl(obj, s.Type, nil, false)
|
||||
|
||||
default:
|
||||
check.invalidAST(s.Pos(), "const, type, or var declaration expected")
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
check.invalidAST(d.Pos(), "unknown ast.Decl node %T", d)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue