go.tools/go/types: remove iota from all parameter lists (cleanup)

Instead of passing around iota everywhere, keep track of the
current value in the checker, and update it when entering
different declarations. This is less explicit, but the improvement
over all code is so significant that it is worth it.

R=adonovan
CC=golang-dev
https://golang.org/cl/10814044
This commit is contained in:
Robert Griesemer 2013-07-03 10:06:09 -07:00
parent b58f98e9c2
commit f052654314
10 changed files with 187 additions and 141 deletions

View File

@ -89,7 +89,7 @@ func (check *checker) assignMulti(lhs []Object, rhs []ast.Expr) {
if len(lhs) == len(rhs) { if len(lhs) == len(rhs) {
var x operand var x operand
for i, e := range rhs { for i, e := range rhs {
check.expr(&x, e, -1) check.expr(&x, e)
if x.mode == invalid { if x.mode == invalid {
goto Error goto Error
} }
@ -106,7 +106,7 @@ func (check *checker) assignMulti(lhs []Object, rhs []ast.Expr) {
// Start with rhs so we have expression types // Start with rhs so we have expression types
// for declarations with implicit types. // for declarations with implicit types.
var x operand var x operand
check.expr(&x, rhs[0], -1) check.expr(&x, rhs[0])
if x.mode == invalid { if x.mode == invalid {
goto Error goto Error
} }

View File

@ -16,12 +16,11 @@ import (
// TODO(gri): Several built-ins are missing assignment checks. As a result, // TODO(gri): Several built-ins are missing assignment checks. As a result,
// non-constant shift arguments may not be properly type-checked. // non-constant shift arguments may not be properly type-checked.
// builtin typechecks a built-in call. The built-in type is bin, and iota is the current // builtin typechecks a built-in call. The built-in type is bin, and the result
// value of iota or -1 if iota doesn't have a value in the current context. The result // of the call is returned via x. If the call has type errors, the returned x is
// of the call is returned via x. If the call has type errors, the returned x is marked // marked as invalid (x.mode == invalid).
// as invalid (x.mode == invalid).
// //
func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota int) { func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin) {
args := call.Args args := call.Args
id := bin.id id := bin.id
@ -50,7 +49,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota
// respective cases below do the work // respective cases below do the work
default: default:
// argument must be an expression // argument must be an expression
check.expr(x, arg0, iota) check.expr(x, arg0)
if x.mode == invalid { if x.mode == invalid {
goto Error goto Error
} }
@ -65,7 +64,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota
} }
resultTyp := x.typ resultTyp := x.typ
for _, arg := range args[1:] { for _, arg := range args[1:] {
check.expr(x, arg, iota) check.expr(x, arg)
if x.mode == invalid { if x.mode == invalid {
goto Error goto Error
} }
@ -134,7 +133,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota
} }
var y operand var y operand
check.expr(&y, args[1], iota) check.expr(&y, args[1])
if y.mode == invalid { if y.mode == invalid {
goto Error goto Error
} }
@ -196,7 +195,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota
case _Copy: case _Copy:
var y operand var y operand
check.expr(&y, args[1], iota) check.expr(&y, args[1])
if y.mode == invalid { if y.mode == invalid {
goto Error goto Error
} }
@ -233,7 +232,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota
check.invalidArg(x.pos(), "%s is not a map", x) check.invalidArg(x.pos(), "%s is not a map", x)
goto Error goto Error
} }
check.expr(x, args[1], iota) check.expr(x, args[1])
if x.mode == invalid { if x.mode == invalid {
goto Error goto Error
} }
@ -271,7 +270,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota
x.typ = Typ[k] x.typ = Typ[k]
case _Make: case _Make:
resultTyp := check.typ(arg0, iota, nil, false) resultTyp := check.typ(arg0, nil, false)
if resultTyp == Typ[Invalid] { if resultTyp == Typ[Invalid] {
goto Error goto Error
} }
@ -291,7 +290,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota
} }
var sizes []int64 // constant integer arguments, if any var sizes []int64 // constant integer arguments, if any
for _, arg := range args[1:] { for _, arg := range args[1:] {
if s, ok := check.index(arg, -1, iota); ok && s >= 0 { if s, ok := check.index(arg, -1); ok && s >= 0 {
sizes = append(sizes, s) sizes = append(sizes, s)
} }
} }
@ -303,7 +302,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota
x.typ = resultTyp x.typ = resultTyp
case _New: case _New:
resultTyp := check.typ(arg0, iota, nil, false) resultTyp := check.typ(arg0, nil, false)
if resultTyp == Typ[Invalid] { if resultTyp == Typ[Invalid] {
goto Error goto Error
} }
@ -315,7 +314,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota
case _Print, _Println: case _Print, _Println:
for _, arg := range args { for _, arg := range args {
check.expr(x, arg, iota) check.expr(x, arg)
if x.mode == invalid { if x.mode == invalid {
goto Error goto Error
} }
@ -337,7 +336,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota
check.invalidArg(arg0.Pos(), "%s is not a selector expression", arg0) check.invalidArg(arg0.Pos(), "%s is not a selector expression", arg0)
goto Error goto Error
} }
check.expr(x, arg.X, iota) check.expr(x, arg.X)
if x.mode == invalid { if x.mode == invalid {
goto Error goto Error
} }
@ -397,7 +396,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota
var t operand var t operand
x1 := x x1 := x
for _, arg := range args { for _, arg := range args {
check.rawExpr(x1, arg, nil, iota) // permit trace for types, e.g.: new(trace(T)) check.rawExpr(x1, arg, nil) // permit trace for types, e.g.: new(trace(T))
check.dump("%s: %s", x1.pos(), x1) check.dump("%s: %s", x1.pos(), x1)
x1 = &t // use incoming x only for first argument x1 = &t // use incoming x only for first argument
} }

View File

@ -11,19 +11,19 @@ import (
"go/token" "go/token"
) )
func (check *checker) call(x *operand, e *ast.CallExpr, iota int) { func (check *checker) call(x *operand, e *ast.CallExpr) {
check.exprOrType(x, e.Fun, iota) check.exprOrType(x, e.Fun)
if x.mode == invalid { if x.mode == invalid {
// We don't have a valid call or conversion but we have list of arguments. // We don't have a valid call or conversion but we have list of arguments.
// Typecheck them independently for better partial type information in // Typecheck them independently for better partial type information in
// the presence of type errors. // the presence of type errors.
for _, arg := range e.Args { for _, arg := range e.Args {
check.expr(x, arg, iota) check.expr(x, arg)
} }
goto Error goto Error
} else if x.mode == typexpr { } else if x.mode == typexpr {
check.conversion(x, e, x.typ, iota) check.conversion(x, e, x.typ)
} else if sig, ok := x.typ.Underlying().(*Signature); ok { } else if sig, ok := x.typ.Underlying().(*Signature); ok {
// check parameters // check parameters
@ -52,7 +52,7 @@ func (check *checker) call(x *operand, e *ast.CallExpr, iota int) {
n := 0 // parameter count n := 0 // parameter count
if call != nil { if call != nil {
// We have a single argument that is a function call. // We have a single argument that is a function call.
check.expr(x, call, iota) check.expr(x, call)
if x.mode == invalid { if x.mode == invalid {
goto Error // TODO(gri): we can do better goto Error // TODO(gri): we can do better
} }
@ -104,7 +104,7 @@ func (check *checker) call(x *operand, e *ast.CallExpr, iota int) {
} }
} else if bin, ok := x.typ.(*Builtin); ok { } else if bin, ok := x.typ.(*Builtin); ok {
check.builtin(x, e, bin, iota) check.builtin(x, e, bin)
} else { } else {
check.invalidOp(x.pos(), "cannot call non-function %s", x) check.invalidOp(x.pos(), "cannot call non-function %s", x)
@ -153,7 +153,7 @@ func (check *checker) argument(sig *Signature, i int, arg ast.Expr, x *operand,
z.typ = par.typ z.typ = par.typ
if arg != nil { if arg != nil {
check.expr(x, arg, -1) check.expr(x, arg)
} }
if x.mode == invalid { if x.mode == invalid {
return // ignore this argument return // ignore this argument
@ -176,7 +176,7 @@ func (check *checker) argument(sig *Signature, i int, arg ast.Expr, x *operand,
} }
} }
func (check *checker) selector(x *operand, e *ast.SelectorExpr, iota int) { func (check *checker) selector(x *operand, e *ast.SelectorExpr) {
// these must be declared before the "goto Error" statements // these must be declared before the "goto Error" statements
var ( var (
obj Object obj Object
@ -230,7 +230,7 @@ func (check *checker) selector(x *operand, e *ast.SelectorExpr, iota int) {
} }
} }
check.exprOrType(x, e.X, iota) check.exprOrType(x, e.X)
if x.mode == invalid { if x.mode == invalid {
goto Error goto Error
} }

View File

@ -48,6 +48,7 @@ type checker struct {
objMap map[Object]*decl // if set we are in the package-global declaration phase (otherwise all objects seen must be declared) objMap map[Object]*decl // if set we are in the package-global declaration phase (otherwise all objects seen must be declared)
topScope *Scope // topScope for lookups, non-global declarations topScope *Scope // topScope for lookups, non-global declarations
iota exact.Value // value of iota in a constant declaration; nil otherwise
// functions // functions
funclist []function // list of functions/methods with correct signatures and non-empty bodies funclist []function // list of functions/methods with correct signatures and non-empty bodies

View File

@ -12,12 +12,12 @@ import (
"code.google.com/p/go.tools/go/exact" "code.google.com/p/go.tools/go/exact"
) )
// conversion typechecks the type conversion conv to type typ. iota is the current // conversion typechecks the type conversion conv to type typ.
// value of iota or -1 if iota doesn't have a value in the current context. The result // The result of the conversion is returned via x.
// of the conversion is returned via x. If the conversion has type errors, the returned // If the conversion has type errors, the returned
// x is marked as invalid (x.mode == invalid). // x is marked as invalid (x.mode == invalid).
// //
func (check *checker) conversion(x *operand, conv *ast.CallExpr, typ Type, iota int) { func (check *checker) conversion(x *operand, conv *ast.CallExpr, typ Type) {
// all conversions have one argument // all conversions have one argument
if len(conv.Args) != 1 { if len(conv.Args) != 1 {
check.invalidOp(conv.Pos(), "%s conversion requires exactly one argument", conv) check.invalidOp(conv.Pos(), "%s conversion requires exactly one argument", conv)
@ -25,7 +25,7 @@ func (check *checker) conversion(x *operand, conv *ast.CallExpr, typ Type, iota
} }
// evaluate argument // evaluate argument
check.expr(x, conv.Args[0], iota) check.expr(x, conv.Args[0])
if x.mode == invalid { if x.mode == invalid {
goto Error goto Error
} }

View File

@ -17,7 +17,6 @@ import (
// - don't print error messages referring to invalid types (they are likely spurious errors) // - don't print error messages referring to invalid types (they are likely spurious errors)
// - simplify invalid handling: maybe just use Typ[Invalid] as marker, get rid of invalid Mode for values? // - simplify invalid handling: maybe just use Typ[Invalid] as marker, get rid of invalid Mode for values?
// - rethink error handling: should all callers check if x.mode == valid after making a call? // - rethink error handling: should all callers check if x.mode == valid after making a call?
// - at the moment, iota is passed around almost everywhere - in many places we know it cannot be used
// - consider storing error messages in invalid operands for better error messages/debugging output // - consider storing error messages in invalid operands for better error messages/debugging output
// TODO(gri) Test issues // TODO(gri) Test issues
@ -40,9 +39,6 @@ of an outer composite literal; it is used to type-check composite literal
elements that have no explicit type specification in the source elements that have no explicit type specification in the source
(e.g.: []T{{...}, {...}}, the hint is the type T in this case). (e.g.: []T{{...}, {...}}, the hint is the type T in this case).
If an iota argument >= 0 is present, it is the value of iota for the
specific expression.
All expressions are checked via rawExpr, which dispatches according All expressions are checked via rawExpr, which dispatches according
to expression kind. Upon returning, rawExpr is recording the types and to expression kind. Upon returning, rawExpr is recording the types and
constant values for all expressions that have an untyped type (those types constant values for all expressions that have an untyped type (those types
@ -611,11 +607,11 @@ var binaryOpPredicates = opPredicates{
token.LOR: isBoolean, token.LOR: isBoolean,
} }
func (check *checker) binary(x *operand, lhs, rhs ast.Expr, op token.Token, iota int) { func (check *checker) binary(x *operand, lhs, rhs ast.Expr, op token.Token) {
var y operand var y operand
check.expr(x, lhs, iota) check.expr(x, lhs)
check.expr(&y, rhs, iota) check.expr(&y, rhs)
if x.mode == invalid { if x.mode == invalid {
return return
@ -686,10 +682,9 @@ func (check *checker) binary(x *operand, lhs, rhs ast.Expr, op token.Token, iota
// index checks an index/size expression arg for validity. // index checks an index/size expression arg for validity.
// If length >= 0, it is the upper bound for arg. // If length >= 0, it is the upper bound for arg.
// TODO(gri): Do we need iota? func (check *checker) index(arg ast.Expr, length int64) (i int64, ok bool) {
func (check *checker) index(arg ast.Expr, length int64, iota int) (i int64, ok bool) {
var x operand var x operand
check.expr(&x, arg, iota) check.expr(&x, arg)
// an untyped constant must be representable as Int // an untyped constant must be representable as Int
check.convertUntyped(&x, Typ[Int]) check.convertUntyped(&x, Typ[Int])
@ -726,7 +721,7 @@ func (check *checker) index(arg ast.Expr, length int64, iota int) (i int64, ok b
// the literal length if known (length >= 0). It returns the length of the // the literal length if known (length >= 0). It returns the length of the
// literal (maximum index value + 1). // literal (maximum index value + 1).
// //
func (check *checker) indexedElts(elts []ast.Expr, typ Type, length int64, iota int) int64 { func (check *checker) indexedElts(elts []ast.Expr, typ Type, length int64) int64 {
visited := make(map[int64]bool, len(elts)) visited := make(map[int64]bool, len(elts))
var index, max int64 var index, max int64
for _, e := range elts { for _, e := range elts {
@ -734,7 +729,7 @@ func (check *checker) indexedElts(elts []ast.Expr, typ Type, length int64, iota
validIndex := false validIndex := false
eval := e eval := e
if kv, _ := e.(*ast.KeyValueExpr); kv != nil { if kv, _ := e.(*ast.KeyValueExpr); kv != nil {
if i, ok := check.index(kv.Key, length, iota); ok { if i, ok := check.index(kv.Key, length); ok {
if i >= 0 { if i >= 0 {
index = i index = i
} }
@ -761,7 +756,7 @@ func (check *checker) indexedElts(elts []ast.Expr, typ Type, length int64, iota
// check element against composite literal element type // check element against composite literal element type
var x operand var x operand
check.exprWithHint(&x, eval, typ, iota) check.exprWithHint(&x, eval, typ)
if !check.assignment(&x, typ) && x.mode != invalid { if !check.assignment(&x, typ) && x.mode != invalid {
check.errorf(x.pos(), "cannot use %s as %s value in array or slice literal", &x, typ) check.errorf(x.pos(), "cannot use %s as %s value in array or slice literal", &x, typ)
} }
@ -810,9 +805,8 @@ func (check *checker) callExpr(x *operand, ignore *bool) {
// rawExpr typechecks expression e and initializes x with the expression // rawExpr typechecks expression e and initializes x with the expression
// value or type. If an error occurred, x.mode is set to invalid. // value or type. If an error occurred, x.mode is set to invalid.
// If hint != nil, it is the type of a composite literal element. // If hint != nil, it is the type of a composite literal element.
// iota >= 0 indicates that the expression is part of a constant declaration.
// //
func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) { func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type) {
// make sure x has a valid state for deferred functions in case of bailout // make sure x has a valid state for deferred functions in case of bailout
// (was issue 5770) // (was issue 5770)
x.mode = invalid x.mode = invalid
@ -832,7 +826,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) {
goto Error // error was reported before goto Error // error was reported before
case *ast.Ident: case *ast.Ident:
check.ident(x, e, iota, nil, false) check.ident(x, e, nil, false)
case *ast.Ellipsis: case *ast.Ellipsis:
// ellipses are handled explicitly where they are legal // ellipses are handled explicitly where they are legal
@ -848,7 +842,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) {
} }
case *ast.FuncLit: case *ast.FuncLit:
if sig, ok := check.typ(e.Type, iota, nil, false).(*Signature); ok { if sig, ok := check.typ(e.Type, nil, false).(*Signature); ok {
x.mode = value x.mode = value
x.typ = sig x.typ = sig
check.later(nil, sig, e.Body) check.later(nil, sig, e.Body)
@ -869,12 +863,12 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) {
// We have an "open" [...]T array type. // We have an "open" [...]T array type.
// Create a new ArrayType with unknown length (-1) // Create a new ArrayType with unknown length (-1)
// and finish setting it up after analyzing the literal. // and finish setting it up after analyzing the literal.
typ = &Array{len: -1, elt: check.typ(atyp.Elt, iota, nil, false)} typ = &Array{len: -1, elt: check.typ(atyp.Elt, nil, false)}
openArray = true openArray = true
} }
} }
if typ == nil { if typ == nil {
typ = check.typ(e.Type, iota, nil, false) typ = check.typ(e.Type, nil, false)
} }
} }
if typ == nil { if typ == nil {
@ -915,7 +909,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) {
continue continue
} }
visited[i] = true visited[i] = true
check.expr(x, kv.Value, iota) check.expr(x, kv.Value)
etyp := fld.typ etyp := fld.typ
if !check.assignment(x, etyp) { if !check.assignment(x, etyp) {
if x.mode != invalid { if x.mode != invalid {
@ -931,7 +925,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) {
check.errorf(kv.Pos(), "mixture of field:value and value elements in struct literal") check.errorf(kv.Pos(), "mixture of field:value and value elements in struct literal")
continue continue
} }
check.expr(x, e, iota) check.expr(x, e)
if i >= len(fields) { if i >= len(fields) {
check.errorf(x.pos(), "too many values in struct literal") check.errorf(x.pos(), "too many values in struct literal")
break // cannot continue break // cannot continue
@ -952,14 +946,14 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) {
} }
case *Array: case *Array:
n := check.indexedElts(e.Elts, utyp.elt, utyp.len, iota) n := check.indexedElts(e.Elts, utyp.elt, utyp.len)
// if we have an "open" [...]T array, set the length now that we know it // if we have an "open" [...]T array, set the length now that we know it
if openArray { if openArray {
utyp.len = n utyp.len = n
} }
case *Slice: case *Slice:
check.indexedElts(e.Elts, utyp.elt, -1, iota) check.indexedElts(e.Elts, utyp.elt, -1)
case *Map: case *Map:
visited := make(map[interface{}]bool, len(e.Elts)) visited := make(map[interface{}]bool, len(e.Elts))
@ -969,7 +963,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) {
check.errorf(e.Pos(), "missing key in map literal") check.errorf(e.Pos(), "missing key in map literal")
continue continue
} }
check.expr(x, kv.Key, iota) check.expr(x, kv.Key)
if !check.assignment(x, utyp.key) { if !check.assignment(x, utyp.key) {
if x.mode != invalid { if x.mode != invalid {
check.errorf(x.pos(), "cannot use %s as %s key in map literal", x, utyp.key) check.errorf(x.pos(), "cannot use %s as %s key in map literal", x, utyp.key)
@ -983,7 +977,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) {
} }
visited[x.val] = true visited[x.val] = true
} }
check.exprWithHint(x, kv.Value, utyp.elt, iota) check.exprWithHint(x, kv.Value, utyp.elt)
if !check.assignment(x, utyp.elt) { if !check.assignment(x, utyp.elt) {
if x.mode != invalid { if x.mode != invalid {
check.errorf(x.pos(), "cannot use %s as %s value in map literal", x, utyp.elt) check.errorf(x.pos(), "cannot use %s as %s value in map literal", x, utyp.elt)
@ -1001,13 +995,13 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) {
x.typ = typ x.typ = typ
case *ast.ParenExpr: case *ast.ParenExpr:
check.rawExpr(x, e.X, nil, iota) check.rawExpr(x, e.X, nil)
case *ast.SelectorExpr: case *ast.SelectorExpr:
check.selector(x, e, iota) check.selector(x, e)
case *ast.IndexExpr: case *ast.IndexExpr:
check.expr(x, e.X, iota) check.expr(x, e.X)
if x.mode == invalid { if x.mode == invalid {
goto Error goto Error
} }
@ -1051,7 +1045,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) {
case *Map: case *Map:
var key operand var key operand
check.expr(&key, e.Index, iota) check.expr(&key, e.Index)
if !check.assignment(&key, typ.key) { if !check.assignment(&key, typ.key) {
if key.mode != invalid { if key.mode != invalid {
check.invalidOp(key.pos(), "cannot use %s as map index of type %s", &key, typ.key) check.invalidOp(key.pos(), "cannot use %s as map index of type %s", &key, typ.key)
@ -1074,11 +1068,11 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) {
return return
} }
check.index(e.Index, length, iota) check.index(e.Index, length)
// ok to continue // ok to continue
case *ast.SliceExpr: case *ast.SliceExpr:
check.expr(x, e.X, iota) check.expr(x, e.X)
if x.mode == invalid { if x.mode == invalid {
goto Error goto Error
} }
@ -1134,14 +1128,14 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) {
lo := int64(0) lo := int64(0)
if e.Low != nil { if e.Low != nil {
if i, ok := check.index(e.Low, length, iota); ok && i >= 0 { if i, ok := check.index(e.Low, length); ok && i >= 0 {
lo = i lo = i
} }
} }
hi := int64(-1) hi := int64(-1)
if e.High != nil { if e.High != nil {
if i, ok := check.index(e.High, length, iota); ok && i >= 0 { if i, ok := check.index(e.High, length); ok && i >= 0 {
hi = i hi = i
} }
} else if length >= 0 { } else if length >= 0 {
@ -1154,7 +1148,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) {
} }
case *ast.TypeAssertExpr: case *ast.TypeAssertExpr:
check.expr(x, e.X, iota) check.expr(x, e.X)
if x.mode == invalid { if x.mode == invalid {
goto Error goto Error
} }
@ -1168,7 +1162,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) {
check.invalidAST(e.Pos(), "use of .(type) outside type switch") check.invalidAST(e.Pos(), "use of .(type) outside type switch")
goto Error goto Error
} }
typ := check.typ(e.Type, iota, nil, false) typ := check.typ(e.Type, nil, false)
if typ == Typ[Invalid] { if typ == Typ[Invalid] {
goto Error goto Error
} }
@ -1192,10 +1186,10 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) {
x.typ = typ x.typ = typ
case *ast.CallExpr: case *ast.CallExpr:
check.call(x, e, iota) check.call(x, e)
case *ast.StarExpr: case *ast.StarExpr:
check.exprOrType(x, e.X, iota) check.exprOrType(x, e.X)
switch x.mode { switch x.mode {
case invalid: case invalid:
goto Error goto Error
@ -1212,7 +1206,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) {
} }
case *ast.UnaryExpr: case *ast.UnaryExpr:
check.expr(x, e.X, iota) check.expr(x, e.X)
if x.mode == invalid { if x.mode == invalid {
goto Error goto Error
} }
@ -1222,7 +1216,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) {
} }
case *ast.BinaryExpr: case *ast.BinaryExpr:
check.binary(x, e.X, e.Y, e.Op, iota) check.binary(x, e.X, e.Y, e.Op)
if x.mode == invalid { if x.mode == invalid {
goto Error goto Error
} }
@ -1235,7 +1229,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) {
case *ast.ArrayType, *ast.StructType, *ast.FuncType, case *ast.ArrayType, *ast.StructType, *ast.FuncType,
*ast.InterfaceType, *ast.MapType, *ast.ChanType: *ast.InterfaceType, *ast.MapType, *ast.ChanType:
x.mode = typexpr x.mode = typexpr
x.typ = check.typ(e, iota, nil, false) x.typ = check.typ(e, nil, false)
// check.typ is already notifying clients // check.typ is already notifying clients
// of e's type; don't do it a 2nd time // of e's type; don't do it a 2nd time
ignore = true ignore = true
@ -1258,10 +1252,9 @@ Error:
// expr typechecks expression e and initializes x with the expression value. // expr typechecks expression e and initializes x with the expression value.
// If an error occurred, x.mode is set to invalid. // If an error occurred, x.mode is set to invalid.
// iota >= 0 indicates that the expression is part of a constant declaration.
// //
func (check *checker) expr(x *operand, e ast.Expr, iota int) { func (check *checker) expr(x *operand, e ast.Expr) {
check.rawExpr(x, e, nil, iota) check.rawExpr(x, e, nil)
switch x.mode { switch x.mode {
case novalue: case novalue:
check.errorf(x.pos(), "%s used as value", x) check.errorf(x.pos(), "%s used as value", x)
@ -1275,11 +1268,10 @@ func (check *checker) expr(x *operand, e ast.Expr, iota int) {
// exprWithHint typechecks expression e and initializes x with the expression value. // exprWithHint typechecks expression e and initializes x with the expression value.
// If an error occurred, x.mode is set to invalid. // If an error occurred, x.mode is set to invalid.
// If hint != nil, it is the type of a composite literal element. // If hint != nil, it is the type of a composite literal element.
// iota >= 0 indicates that the expression is part of a constant declaration.
// //
func (check *checker) exprWithHint(x *operand, e ast.Expr, hint Type, iota int) { func (check *checker) exprWithHint(x *operand, e ast.Expr, hint Type) {
assert(hint != nil) assert(hint != nil)
check.rawExpr(x, e, hint, iota) check.rawExpr(x, e, hint)
switch x.mode { switch x.mode {
case novalue: case novalue:
check.errorf(x.pos(), "%s used as value", x) check.errorf(x.pos(), "%s used as value", x)
@ -1292,10 +1284,9 @@ func (check *checker) exprWithHint(x *operand, e ast.Expr, hint Type, iota int)
// exprOrType typechecks expression or type e and initializes x with the expression value or type. // exprOrType typechecks expression or type e and initializes x with the expression value or type.
// If an error occurred, x.mode is set to invalid. // If an error occurred, x.mode is set to invalid.
// iota >= 0 indicates that the expression is part of a constant declaration.
// //
func (check *checker) exprOrType(x *operand, e ast.Expr, iota int) { func (check *checker) exprOrType(x *operand, e ast.Expr) {
check.rawExpr(x, e, nil, iota) check.rawExpr(x, e, nil)
if x.mode == novalue { if x.mode == novalue {
check.errorf(x.pos(), "%s used as value or type", x) check.errorf(x.pos(), "%s used as value or type", x)
x.mode = invalid x.mode = invalid

View File

@ -335,7 +335,7 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) {
// - done by the caller for now // - done by the caller for now
} }
// declareObject declares obj in the top-most scope. // declareObject completes the declaration of obj in its respective file scope.
// See declareType for the details on def and cycleOk. // See declareType for the details on def and cycleOk.
func (check *checker) declareObject(obj Object, def *Named, cycleOk bool) { func (check *checker) declareObject(obj Object, def *Named, cycleOk bool) {
d := check.objMap[obj] d := check.objMap[obj]
@ -344,6 +344,10 @@ func (check *checker) declareObject(obj Object, def *Named, cycleOk bool) {
oldScope := check.topScope oldScope := check.topScope
check.topScope = d.file // for lookup check.topScope = d.file // for lookup
// save current iota
oldIota := check.iota
check.iota = nil
switch obj := obj.(type) { switch obj := obj.(type) {
case *Const: case *Const:
check.declareConst(obj, d.typ, d.init) check.declareConst(obj, d.typ, d.init)
@ -357,6 +361,7 @@ func (check *checker) declareObject(obj Object, def *Named, cycleOk bool) {
unreachable() unreachable()
} }
check.iota = oldIota
check.topScope = oldScope check.topScope = oldScope
} }
@ -367,12 +372,14 @@ func (check *checker) declareConst(obj *Const, typ, init ast.Expr) {
return return
} }
obj.visited = true obj.visited = true
iota, ok := exact.Int64Val(obj.val) // set in phase 1
assert(ok) // use the correct value of iota
assert(check.iota == nil)
check.iota = obj.val
// determine type, if any // determine type, if any
if typ != nil { if typ != nil {
obj.typ = check.typ(typ, int(iota), nil, false) obj.typ = check.typ(typ, nil, false)
} }
var x operand var x operand
@ -381,12 +388,13 @@ func (check *checker) declareConst(obj *Const, typ, init ast.Expr) {
goto Error // error reported before goto Error // error reported before
} }
check.expr(&x, init, int(iota)) check.expr(&x, init)
if x.mode == invalid { if x.mode == invalid {
goto Error goto Error
} }
check.assign(obj, &x) check.assign(obj, &x)
check.iota = nil
return return
Error: Error:
@ -395,6 +403,7 @@ Error:
} else { } else {
obj.val = exact.MakeUnknown() obj.val = exact.MakeUnknown()
} }
check.iota = nil
} }
func (check *checker) declareVar(obj *Var, typ, init ast.Expr) { func (check *checker) declareVar(obj *Var, typ, init ast.Expr) {
@ -405,9 +414,12 @@ func (check *checker) declareVar(obj *Var, typ, init ast.Expr) {
} }
obj.visited = true obj.visited = true
// var declarations cannot use iota
assert(check.iota == nil)
// determine type, if any // determine type, if any
if typ != nil { if typ != nil {
obj.typ = check.typ(typ, -1, nil, false) obj.typ = check.typ(typ, nil, false)
} }
if init == nil { if init == nil {
@ -424,7 +436,7 @@ func (check *checker) declareVar(obj *Var, typ, init ast.Expr) {
} }
var x operand var x operand
check.expr(&x, init, -1) check.expr(&x, init)
if x.mode == invalid { if x.mode == invalid {
goto Error goto Error
} }
@ -477,6 +489,9 @@ Error:
func (check *checker) declareType(obj *TypeName, typ ast.Expr, def *Named, cycleOk bool) { func (check *checker) declareType(obj *TypeName, typ ast.Expr, def *Named, cycleOk bool) {
assert(obj.Type() == nil) assert(obj.Type() == nil)
// type declarations cannot use iota
assert(check.iota == nil)
named := &Named{obj: obj} named := &Named{obj: obj}
obj.typ = named // make sure recursive type declarations terminate obj.typ = named // make sure recursive type declarations terminate
@ -497,7 +512,7 @@ func (check *checker) declareType(obj *TypeName, typ ast.Expr, def *Named, cycle
// ) // )
// //
// When we declare obj = C, typ is the identifier A which is incomplete. // When we declare obj = C, typ is the identifier A which is incomplete.
u := check.typ(typ, -1, named, cycleOk) u := check.typ(typ, named, cycleOk)
// Determine the unnamed underlying type. // Determine the unnamed underlying type.
// In the above example, the underlying type of A was (temporarily) set // In the above example, the underlying type of A was (temporarily) set
@ -549,7 +564,7 @@ func (check *checker) declareType(obj *TypeName, typ ast.Expr, def *Named, cycle
oldScope := check.topScope oldScope := check.topScope
check.topScope = fileScope check.topScope = fileScope
sig := check.typ(m.decl.Type, -1, nil, cycleOk).(*Signature) sig := check.typ(m.decl.Type, nil, cycleOk).(*Signature)
params, _ := check.collectParams(sig.scope, m.decl.Recv, false) params, _ := check.collectParams(sig.scope, m.decl.Recv, false)
check.topScope = oldScope // reset topScope check.topScope = oldScope // reset topScope
@ -566,12 +581,15 @@ func (check *checker) declareType(obj *TypeName, typ ast.Expr, def *Named, cycle
} }
func (check *checker) declareFunc(obj *Func) { func (check *checker) declareFunc(obj *Func) {
// func declarations cannot use iota
assert(check.iota == nil)
fdecl := obj.decl fdecl := obj.decl
// methods are typechecked when their receivers are typechecked // methods are typechecked when their receivers are typechecked
// TODO(gri) there is no reason to make this a special case: receivers are simply parameters // TODO(gri) there is no reason to make this a special case: receivers are simply parameters
if fdecl.Recv == nil { if fdecl.Recv == nil {
obj.typ = Typ[Invalid] // guard against cycles obj.typ = Typ[Invalid] // guard against cycles
sig := check.typ(fdecl.Type, -1, nil, false).(*Signature) sig := check.typ(fdecl.Type, nil, false).(*Signature)
if obj.name == "init" && (sig.params.Len() > 0 || sig.results.Len() > 0) { if 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") check.errorf(fdecl.Pos(), "func init must have no arguments and no return values")
// ok to continue // ok to continue

View File

@ -41,14 +41,14 @@ func (check *checker) assignment(x *operand, to Type) bool {
// if its type is not set, it is deduced from the type of x or set to Typ[Invalid] in // if its type is not set, it is deduced from the type of x or set to Typ[Invalid] in
// case of an error. // case of an error.
// //
func (check *checker) assign1to1(lhs, rhs ast.Expr, x *operand, decl bool, iota int, isConst bool) { func (check *checker) assign1to1(lhs, rhs ast.Expr, x *operand, decl bool, isConst bool) {
assert(!isConst || decl) assert(!isConst || decl)
// Start with rhs so we have an expression type // Start with rhs so we have an expression type
// for declarations with implicit type. // for declarations with implicit type.
if x == nil { if x == nil {
x = new(operand) x = new(operand)
check.expr(x, rhs, iota) check.expr(x, rhs)
// don't exit for declarations - we need the lhs first // don't exit for declarations - we need the lhs first
if x.mode == invalid && !decl { if x.mode == invalid && !decl {
return return
@ -70,7 +70,7 @@ func (check *checker) assign1to1(lhs, rhs ast.Expr, x *operand, decl bool, iota
} }
var z operand var z operand
check.expr(&z, lhs, -1) check.expr(&z, lhs)
if z.mode == invalid || z.typ == Typ[Invalid] { if z.mode == invalid || z.typ == Typ[Invalid] {
return return
} }
@ -174,7 +174,7 @@ func (check *checker) assign1to1(lhs, rhs ast.Expr, x *operand, decl bool, iota
// of the corresponding rhs expressions, or set to Typ[Invalid] in case of an error. // of the corresponding rhs expressions, or set to Typ[Invalid] in case of an error.
// Precondition: len(lhs) > 0 . // Precondition: len(lhs) > 0 .
// //
func (check *checker) assignNtoM(lhs, rhs []ast.Expr, decl bool, iota int, isConst bool) { func (check *checker) assignNtoM(lhs, rhs []ast.Expr, decl bool, isConst bool) {
assert(len(lhs) > 0) assert(len(lhs) > 0)
assert(!isConst || decl) assert(!isConst || decl)
@ -182,7 +182,7 @@ func (check *checker) assignNtoM(lhs, rhs []ast.Expr, decl bool, iota int, isCon
// matching pair as an individual pair. // matching pair as an individual pair.
if len(lhs) == len(rhs) { if len(lhs) == len(rhs) {
for i, e := range rhs { for i, e := range rhs {
check.assign1to1(lhs[i], e, nil, decl, iota, isConst) check.assign1to1(lhs[i], e, nil, decl, isConst)
} }
return return
} }
@ -195,7 +195,7 @@ func (check *checker) assignNtoM(lhs, rhs []ast.Expr, decl bool, iota int, isCon
// Start with rhs so we have expression types // Start with rhs so we have expression types
// for declarations with implicit types. // for declarations with implicit types.
var x operand var x operand
check.expr(&x, rhs[0], iota) check.expr(&x, rhs[0])
if x.mode == invalid { if x.mode == invalid {
goto Error goto Error
} }
@ -207,7 +207,7 @@ func (check *checker) assignNtoM(lhs, rhs []ast.Expr, decl bool, iota int, isCon
obj := t.At(i) obj := t.At(i)
x.expr = nil // TODO(gri) should do better here x.expr = nil // TODO(gri) should do better here
x.typ = obj.typ x.typ = obj.typ
check.assign1to1(lhs[i], nil, &x, decl, iota, isConst) check.assign1to1(lhs[i], nil, &x, decl, isConst)
} }
return return
} }
@ -215,10 +215,10 @@ func (check *checker) assignNtoM(lhs, rhs []ast.Expr, decl bool, iota int, isCon
if x.mode == valueok && len(lhs) == 2 { if x.mode == valueok && len(lhs) == 2 {
// comma-ok expression // comma-ok expression
x.mode = value x.mode = value
check.assign1to1(lhs[0], nil, &x, decl, iota, isConst) check.assign1to1(lhs[0], nil, &x, decl, isConst)
x.typ = Typ[UntypedBool] x.typ = Typ[UntypedBool]
check.assign1to1(lhs[1], nil, &x, decl, iota, isConst) check.assign1to1(lhs[1], nil, &x, decl, isConst)
return return
} }
} }
@ -307,6 +307,10 @@ func (check *checker) closeScope() {
// stmt typechecks statement s. // stmt typechecks statement s.
func (check *checker) stmt(s ast.Stmt) { func (check *checker) stmt(s ast.Stmt) {
// statements cannot use iota in general
// (constant declarations set it explicitly)
assert(check.iota == nil)
switch s := s.(type) { switch s := s.(type) {
case *ast.BadStmt, *ast.EmptyStmt: case *ast.BadStmt, *ast.EmptyStmt:
// ignore // ignore
@ -335,7 +339,7 @@ func (check *checker) stmt(s ast.Stmt) {
// (Caution: This evaluates e.Fun twice, once here and once // (Caution: This evaluates e.Fun twice, once here and once
// below as part of s.X. This has consequences for // below as part of s.X. This has consequences for
// check.callIdent. Perhaps this can be avoided.) // check.callIdent. Perhaps this can be avoided.)
check.expr(&x, e.Fun, -1) check.expr(&x, e.Fun)
if x.mode != invalid { if x.mode != invalid {
if b, ok := x.typ.(*Builtin); ok && !b.isStatement { if b, ok := x.typ.(*Builtin); ok && !b.isStatement {
used = false used = false
@ -351,15 +355,15 @@ func (check *checker) stmt(s ast.Stmt) {
check.errorf(s.Pos(), "%s not used", s.X) check.errorf(s.Pos(), "%s not used", s.X)
// ok to continue // ok to continue
} }
check.rawExpr(&x, s.X, nil, -1) check.rawExpr(&x, s.X, nil)
if x.mode == typexpr { if x.mode == typexpr {
check.errorf(x.pos(), "%s is not an expression", &x) check.errorf(x.pos(), "%s is not an expression", &x)
} }
case *ast.SendStmt: case *ast.SendStmt:
var ch, x operand var ch, x operand
check.expr(&ch, s.Chan, -1) check.expr(&ch, s.Chan)
check.expr(&x, s.Value, -1) check.expr(&x, s.Value)
if ch.mode == invalid || x.mode == invalid { if ch.mode == invalid || x.mode == invalid {
return return
} }
@ -382,11 +386,11 @@ func (check *checker) stmt(s ast.Stmt) {
} }
var x operand var x operand
Y := &ast.BasicLit{ValuePos: s.X.Pos(), Kind: token.INT, Value: "1"} // use x's position Y := &ast.BasicLit{ValuePos: s.X.Pos(), Kind: token.INT, Value: "1"} // use x's position
check.binary(&x, s.X, Y, op, -1) check.binary(&x, s.X, Y, op)
if x.mode == invalid { if x.mode == invalid {
return return
} }
check.assign1to1(s.X, nil, &x, false, -1, false) check.assign1to1(s.X, nil, &x, false, false)
case *ast.AssignStmt: case *ast.AssignStmt:
switch s.Tok { switch s.Tok {
@ -418,7 +422,7 @@ func (check *checker) stmt(s ast.Stmt) {
check.declareShort(check.topScope, lhs) // scope starts after the assignment check.declareShort(check.topScope, lhs) // scope starts after the assignment
} else { } else {
check.assignNtoM(s.Lhs, s.Rhs, s.Tok == token.DEFINE, -1, false) check.assignNtoM(s.Lhs, s.Rhs, s.Tok == token.DEFINE, false)
} }
default: default:
@ -457,21 +461,21 @@ func (check *checker) stmt(s ast.Stmt) {
return return
} }
var x operand var x operand
check.binary(&x, s.Lhs[0], s.Rhs[0], op, -1) check.binary(&x, s.Lhs[0], s.Rhs[0], op)
if x.mode == invalid { if x.mode == invalid {
return return
} }
check.assign1to1(s.Lhs[0], nil, &x, false, -1, false) check.assign1to1(s.Lhs[0], nil, &x, false, false)
} }
case *ast.GoStmt: case *ast.GoStmt:
var x operand var x operand
check.call(&x, s.Call, -1) check.call(&x, s.Call)
// TODO(gri) If a builtin is called, the builtin must be valid this context. // TODO(gri) If a builtin is called, the builtin must be valid this context.
case *ast.DeferStmt: case *ast.DeferStmt:
var x operand var x operand
check.call(&x, s.Call, -1) check.call(&x, s.Call)
// TODO(gri) If a builtin is called, the builtin must be valid this context. // TODO(gri) If a builtin is called, the builtin must be valid this context.
case *ast.ReturnStmt: case *ast.ReturnStmt:
@ -508,7 +512,7 @@ func (check *checker) stmt(s ast.Stmt) {
} }
if len(s.Results) > 0 || !named { if len(s.Results) > 0 || !named {
// TODO(gri) assignNtoM should perhaps not require len(lhs) > 0 // TODO(gri) assignNtoM should perhaps not require len(lhs) > 0
check.assignNtoM(lhs, s.Results, false, -1, false) check.assignNtoM(lhs, s.Results, false, false)
} }
} else if len(s.Results) > 0 { } else if len(s.Results) > 0 {
check.errorf(s.Pos(), "no result values expected") check.errorf(s.Pos(), "no result values expected")
@ -526,7 +530,7 @@ func (check *checker) stmt(s ast.Stmt) {
check.openScope(s) check.openScope(s)
check.optionalStmt(s.Init) check.optionalStmt(s.Init)
var x operand var x operand
check.expr(&x, s.Cond, -1) check.expr(&x, s.Cond)
if x.mode != invalid && !isBoolean(x.typ) { if x.mode != invalid && !isBoolean(x.typ) {
check.errorf(s.Cond.Pos(), "non-boolean condition in if statement") check.errorf(s.Cond.Pos(), "non-boolean condition in if statement")
} }
@ -545,7 +549,7 @@ func (check *checker) stmt(s ast.Stmt) {
check.callIdent(ident, Universe.Lookup(nil, "true")) check.callIdent(ident, Universe.Lookup(nil, "true"))
tag = ident tag = ident
} }
check.expr(&x, tag, -1) check.expr(&x, tag)
check.multipleDefaults(s.Body.List) check.multipleDefaults(s.Body.List)
// TODO(gri) check also correct use of fallthrough // TODO(gri) check also correct use of fallthrough
@ -559,7 +563,7 @@ func (check *checker) stmt(s ast.Stmt) {
for _, expr := range clause.List { for _, expr := range clause.List {
x := x // copy of x (don't modify original) x := x // copy of x (don't modify original)
var y operand var y operand
check.expr(&y, expr, -1) check.expr(&y, expr)
if y.mode == invalid { if y.mode == invalid {
continue // error reported before continue // error reported before
} }
@ -645,7 +649,7 @@ func (check *checker) stmt(s ast.Stmt) {
return return
} }
var x operand var x operand
check.expr(&x, expr.X, -1) check.expr(&x, expr.X)
if x.mode == invalid { if x.mode == invalid {
return return
} }
@ -717,7 +721,7 @@ func (check *checker) stmt(s ast.Stmt) {
check.optionalStmt(s.Init) check.optionalStmt(s.Init)
if s.Cond != nil { if s.Cond != nil {
var x operand var x operand
check.expr(&x, s.Cond, -1) check.expr(&x, s.Cond)
if x.mode != invalid && !isBoolean(x.typ) { if x.mode != invalid && !isBoolean(x.typ) {
check.errorf(s.Cond.Pos(), "non-boolean condition in for statement") check.errorf(s.Cond.Pos(), "non-boolean condition in for statement")
} }
@ -731,7 +735,7 @@ func (check *checker) stmt(s ast.Stmt) {
// check expression to iterate over // check expression to iterate over
decl := s.Tok == token.DEFINE decl := s.Tok == token.DEFINE
var x operand var x operand
check.expr(&x, s.X, -1) check.expr(&x, s.X)
if x.mode == invalid { if x.mode == invalid {
// if we don't have a declaration, we can still check the loop's body // if we don't have a declaration, we can still check the loop's body
if !decl { if !decl {
@ -792,7 +796,7 @@ func (check *checker) stmt(s ast.Stmt) {
if s.Key != nil { if s.Key != nil {
x.typ = key x.typ = key
x.expr = s.Key x.expr = s.Key
check.assign1to1(s.Key, nil, &x, decl, -1, false) check.assign1to1(s.Key, nil, &x, decl, false)
} else { } else {
check.invalidAST(s.Pos(), "range clause requires index iteration variable") check.invalidAST(s.Pos(), "range clause requires index iteration variable")
// ok to continue // ok to continue
@ -800,7 +804,7 @@ func (check *checker) stmt(s ast.Stmt) {
if s.Value != nil { if s.Value != nil {
x.typ = val x.typ = val
x.expr = s.Value x.expr = s.Value
check.assign1to1(s.Value, nil, &x, decl, -1, false) check.assign1to1(s.Value, nil, &x, decl, false)
} }
check.stmt(s.Body) check.stmt(s.Body)

View File

@ -231,8 +231,43 @@ const (
type A [iota /* ERROR "cannot use iota" */ ]int type A [iota /* ERROR "cannot use iota" */ ]int
// constant expressions with operands accross different
// constant declarations must use the right iota values
const (
_c0 = iota
_c1
_c2
_x = _c2 + _d1 + _e0 // 3
)
const (
_d0 = iota
_d1
)
const (
_e0 = iota
)
var _ = assert(_x == 3)
// special cases // special cases
const ( const (
_n0 = nil /* ERROR "invalid constant type" */ _n0 = nil /* ERROR "invalid constant type" */
_n1 = [ /* ERROR "not constant" */ ]int{} _n1 = [ /* ERROR "not constant" */ ]int{}
) )
// iotas must not be usable in expressions outside constant declarations
type _ [iota /* ERROR "iota outside constant decl" */ ]byte
var _ = iota /* ERROR "iota outside constant decl" */
func _() {
_ = iota /* ERROR "iota outside constant decl" */
const _ = iota
_ = iota /* ERROR "iota outside constant decl" */
}
func _() {
iota := 123
const x = iota /* ERROR "is not constant" */
var y = iota
}

View File

@ -16,10 +16,9 @@ import (
// ident typechecks identifier e and initializes x with the value or type of e. // ident typechecks identifier e and initializes x with the value or type of e.
// If an error occurred, x.mode is set to invalid. // If an error occurred, x.mode is set to invalid.
// iota >= 0 indicates that the expression is part of a constant declaration.
// For the meaning of def and cycleOk, see check.typ, below. // For the meaning of def and cycleOk, see check.typ, below.
// //
func (check *checker) ident(x *operand, e *ast.Ident, iota int, def *Named, cycleOk bool) { func (check *checker) ident(x *operand, e *ast.Ident, def *Named, cycleOk bool) {
x.mode = invalid x.mode = invalid
x.expr = e x.expr = e
@ -56,11 +55,11 @@ func (check *checker) ident(x *operand, e *ast.Ident, iota int, def *Named, cycl
return return
} }
if obj == universeIota { if obj == universeIota {
if iota < 0 { if check.iota == nil {
check.invalidAST(e.Pos(), "cannot use iota outside constant declaration") check.errorf(e.Pos(), "cannot use iota outside constant declaration")
return return
} }
x.val = exact.MakeInt64(int64(iota)) x.val = check.iota
} else { } else {
x.val = obj.val // may be nil if we don't know the constant value x.val = obj.val // may be nil if we don't know the constant value
} }
@ -93,14 +92,13 @@ func (check *checker) ident(x *operand, e *ast.Ident, iota int, def *Named, cycl
// typ typechecks the type expression e and initializes x with the type of e. // typ typechecks the type expression e and initializes x with the type of e.
// If an error occurred, x.mode is set to invalid. // If an error occurred, x.mode is set to invalid.
// iota >= 0 indicates that the expression is part of a constant declaration.
// If def != nil, e is the type specification for the named type def, declared // If def != nil, e is the type specification for the named type def, declared
// in a type declaration, and def.underlying will be set to the type of e before // in a type declaration, and def.underlying will be set to the type of e before
// any components of e are typechecked. // any components of e are typechecked.
// If cycleOk is set, e (or elements of e) may refer to a named type that is not // If cycleOk is set, e (or elements of e) may refer to a named type that is not
// yet completely set up. // yet completely set up.
// //
func (check *checker) typ(e ast.Expr, iota int, def *Named, cycleOk bool) (res Type) { func (check *checker) typ(e ast.Expr, def *Named, cycleOk bool) (res Type) {
if trace { if trace {
check.trace(e.Pos(), "%s", e) check.trace(e.Pos(), "%s", e)
defer check.untrace("=> %s", res) defer check.untrace("=> %s", res)
@ -117,7 +115,7 @@ func (check *checker) typ(e ast.Expr, iota int, def *Named, cycleOk bool) (res T
switch e := e.(type) { switch e := e.(type) {
case *ast.Ident: case *ast.Ident:
var x operand var x operand
check.ident(&x, e, iota, def, cycleOk) check.ident(&x, e, def, cycleOk)
switch x.mode { switch x.mode {
case typexpr: case typexpr:
@ -132,7 +130,7 @@ func (check *checker) typ(e ast.Expr, iota int, def *Named, cycleOk bool) (res T
case *ast.SelectorExpr: case *ast.SelectorExpr:
var x operand var x operand
check.selector(&x, e, iota) check.selector(&x, e)
switch x.mode { switch x.mode {
case typexpr: case typexpr:
@ -146,12 +144,12 @@ func (check *checker) typ(e ast.Expr, iota int, def *Named, cycleOk bool) (res T
} }
case *ast.ParenExpr: case *ast.ParenExpr:
return check.typ(e.X, iota, def, cycleOk) return check.typ(e.X, def, cycleOk)
case *ast.ArrayType: case *ast.ArrayType:
if e.Len != nil { if e.Len != nil {
var x operand var x operand
check.expr(&x, e.Len, iota) check.expr(&x, e.Len)
if x.mode != constant { if x.mode != constant {
if x.mode != invalid { if x.mode != invalid {
check.errorf(x.pos(), "array length %s must be constant", &x) check.errorf(x.pos(), "array length %s must be constant", &x)
@ -174,7 +172,7 @@ func (check *checker) typ(e ast.Expr, iota int, def *Named, cycleOk bool) (res T
} }
typ.len = n typ.len = n
typ.elt = check.typ(e.Elt, iota, nil, cycleOk) typ.elt = check.typ(e.Elt, nil, cycleOk)
return typ return typ
} else { } else {
@ -183,7 +181,7 @@ func (check *checker) typ(e ast.Expr, iota int, def *Named, cycleOk bool) (res T
def.underlying = typ def.underlying = typ
} }
typ.elt = check.typ(e.Elt, iota, nil, true) typ.elt = check.typ(e.Elt, nil, true)
return typ return typ
} }
@ -202,7 +200,7 @@ func (check *checker) typ(e ast.Expr, iota int, def *Named, cycleOk bool) (res T
def.underlying = typ def.underlying = typ
} }
typ.base = check.typ(e.X, iota, nil, true) typ.base = check.typ(e.X, nil, true)
return typ return typ
case *ast.FuncType: case *ast.FuncType:
@ -238,8 +236,8 @@ func (check *checker) typ(e ast.Expr, iota int, def *Named, cycleOk bool) (res T
def.underlying = typ def.underlying = typ
} }
typ.key = check.typ(e.Key, iota, nil, true) typ.key = check.typ(e.Key, nil, true)
typ.elt = check.typ(e.Value, iota, nil, true) typ.elt = check.typ(e.Value, nil, true)
return typ return typ
case *ast.ChanType: case *ast.ChanType:
@ -249,7 +247,7 @@ func (check *checker) typ(e ast.Expr, iota int, def *Named, cycleOk bool) (res T
} }
typ.dir = e.Dir typ.dir = e.Dir
typ.elt = check.typ(e.Value, iota, nil, true) typ.elt = check.typ(e.Value, nil, true)
return typ return typ
default: default:
@ -265,7 +263,7 @@ func (check *checker) typ(e ast.Expr, iota int, def *Named, cycleOk bool) (res T
// //
func (check *checker) typOrNil(e ast.Expr) Type { func (check *checker) typOrNil(e ast.Expr) Type {
var x operand var x operand
check.rawExpr(&x, e, nil, -1) check.rawExpr(&x, e, nil)
switch x.mode { switch x.mode {
case invalid: case invalid:
// ignore - error reported before // ignore - error reported before
@ -302,7 +300,7 @@ func (check *checker) collectParams(scope *Scope, list *ast.FieldList, variadicO
} }
// the parser ensures that f.Tag is nil and we don't // the parser ensures that f.Tag is nil and we don't
// care if a constructed AST contains a non-nil tag // care if a constructed AST contains a non-nil tag
typ := check.typ(ftype, -1, nil, true) typ := check.typ(ftype, nil, true)
if len(field.Names) > 0 { if len(field.Names) > 0 {
// named parameter // named parameter
for _, name := range field.Names { for _, name := range field.Names {
@ -337,7 +335,7 @@ func (check *checker) collectMethods(list *ast.FieldList, cycleOk bool) (methods
} }
scope := NewScope(nil) scope := NewScope(nil)
for _, f := range list.List { for _, f := range list.List {
typ := check.typ(f.Type, -1, nil, cycleOk) typ := check.typ(f.Type, nil, cycleOk)
// the parser ensures that f.Tag is nil and we don't // the parser ensures that f.Tag is nil and we don't
// care if a constructed AST contains a non-nil tag // care if a constructed AST contains a non-nil tag
if len(f.Names) > 0 { if len(f.Names) > 0 {
@ -413,7 +411,7 @@ func (check *checker) collectFields(list *ast.FieldList, cycleOk bool) (fields [
} }
for _, f := range list.List { for _, f := range list.List {
typ = check.typ(f.Type, -1, nil, cycleOk) typ = check.typ(f.Type, nil, cycleOk)
tag = check.tag(f.Tag) tag = check.tag(f.Tag)
if len(f.Names) > 0 { if len(f.Names) > 0 {
// named fields // named fields