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:
parent
b58f98e9c2
commit
f052654314
|
|
@ -89,7 +89,7 @@ func (check *checker) assignMulti(lhs []Object, rhs []ast.Expr) {
|
|||
if len(lhs) == len(rhs) {
|
||||
var x operand
|
||||
for i, e := range rhs {
|
||||
check.expr(&x, e, -1)
|
||||
check.expr(&x, e)
|
||||
if x.mode == invalid {
|
||||
goto Error
|
||||
}
|
||||
|
|
@ -106,7 +106,7 @@ func (check *checker) assignMulti(lhs []Object, rhs []ast.Expr) {
|
|||
// Start with rhs so we have expression types
|
||||
// for declarations with implicit types.
|
||||
var x operand
|
||||
check.expr(&x, rhs[0], -1)
|
||||
check.expr(&x, rhs[0])
|
||||
if x.mode == invalid {
|
||||
goto Error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,12 +16,11 @@ import (
|
|||
// TODO(gri): Several built-ins are missing assignment checks. As a result,
|
||||
// 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
|
||||
// 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 marked
|
||||
// as invalid (x.mode == invalid).
|
||||
// builtin typechecks a built-in call. The built-in type is bin, and the result
|
||||
// of the call is returned via x. If the call has type errors, the returned x is
|
||||
// marked 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
|
||||
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
|
||||
default:
|
||||
// argument must be an expression
|
||||
check.expr(x, arg0, iota)
|
||||
check.expr(x, arg0)
|
||||
if x.mode == invalid {
|
||||
goto Error
|
||||
}
|
||||
|
|
@ -65,7 +64,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota
|
|||
}
|
||||
resultTyp := x.typ
|
||||
for _, arg := range args[1:] {
|
||||
check.expr(x, arg, iota)
|
||||
check.expr(x, arg)
|
||||
if x.mode == invalid {
|
||||
goto Error
|
||||
}
|
||||
|
|
@ -134,7 +133,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota
|
|||
}
|
||||
|
||||
var y operand
|
||||
check.expr(&y, args[1], iota)
|
||||
check.expr(&y, args[1])
|
||||
if y.mode == invalid {
|
||||
goto Error
|
||||
}
|
||||
|
|
@ -196,7 +195,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota
|
|||
|
||||
case _Copy:
|
||||
var y operand
|
||||
check.expr(&y, args[1], iota)
|
||||
check.expr(&y, args[1])
|
||||
if y.mode == invalid {
|
||||
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)
|
||||
goto Error
|
||||
}
|
||||
check.expr(x, args[1], iota)
|
||||
check.expr(x, args[1])
|
||||
if x.mode == invalid {
|
||||
goto Error
|
||||
}
|
||||
|
|
@ -271,7 +270,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota
|
|||
x.typ = Typ[k]
|
||||
|
||||
case _Make:
|
||||
resultTyp := check.typ(arg0, iota, nil, false)
|
||||
resultTyp := check.typ(arg0, nil, false)
|
||||
if resultTyp == Typ[Invalid] {
|
||||
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
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
@ -303,7 +302,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota
|
|||
x.typ = resultTyp
|
||||
|
||||
case _New:
|
||||
resultTyp := check.typ(arg0, iota, nil, false)
|
||||
resultTyp := check.typ(arg0, nil, false)
|
||||
if resultTyp == Typ[Invalid] {
|
||||
goto Error
|
||||
}
|
||||
|
|
@ -315,7 +314,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota
|
|||
|
||||
case _Print, _Println:
|
||||
for _, arg := range args {
|
||||
check.expr(x, arg, iota)
|
||||
check.expr(x, arg)
|
||||
if x.mode == invalid {
|
||||
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)
|
||||
goto Error
|
||||
}
|
||||
check.expr(x, arg.X, iota)
|
||||
check.expr(x, arg.X)
|
||||
if x.mode == invalid {
|
||||
goto Error
|
||||
}
|
||||
|
|
@ -397,7 +396,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota
|
|||
var t operand
|
||||
x1 := x
|
||||
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)
|
||||
x1 = &t // use incoming x only for first argument
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,19 +11,19 @@ import (
|
|||
"go/token"
|
||||
)
|
||||
|
||||
func (check *checker) call(x *operand, e *ast.CallExpr, iota int) {
|
||||
check.exprOrType(x, e.Fun, iota)
|
||||
func (check *checker) call(x *operand, e *ast.CallExpr) {
|
||||
check.exprOrType(x, e.Fun)
|
||||
if x.mode == invalid {
|
||||
// We don't have a valid call or conversion but we have list of arguments.
|
||||
// Typecheck them independently for better partial type information in
|
||||
// the presence of type errors.
|
||||
for _, arg := range e.Args {
|
||||
check.expr(x, arg, iota)
|
||||
check.expr(x, arg)
|
||||
}
|
||||
goto Error
|
||||
|
||||
} 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 {
|
||||
// check parameters
|
||||
|
|
@ -52,7 +52,7 @@ func (check *checker) call(x *operand, e *ast.CallExpr, iota int) {
|
|||
n := 0 // parameter count
|
||||
if call != nil {
|
||||
// We have a single argument that is a function call.
|
||||
check.expr(x, call, iota)
|
||||
check.expr(x, call)
|
||||
if x.mode == invalid {
|
||||
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 {
|
||||
check.builtin(x, e, bin, iota)
|
||||
check.builtin(x, e, bin)
|
||||
|
||||
} else {
|
||||
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
|
||||
|
||||
if arg != nil {
|
||||
check.expr(x, arg, -1)
|
||||
check.expr(x, arg)
|
||||
}
|
||||
if x.mode == invalid {
|
||||
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
|
||||
var (
|
||||
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 {
|
||||
goto Error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
topScope *Scope // topScope for lookups, non-global declarations
|
||||
iota exact.Value // value of iota in a constant declaration; nil otherwise
|
||||
|
||||
// functions
|
||||
funclist []function // list of functions/methods with correct signatures and non-empty bodies
|
||||
|
|
|
|||
|
|
@ -12,12 +12,12 @@ import (
|
|||
"code.google.com/p/go.tools/go/exact"
|
||||
)
|
||||
|
||||
// conversion typechecks the type conversion conv to type typ. iota is the current
|
||||
// value of iota or -1 if iota doesn't have a value in the current context. The result
|
||||
// of the conversion is returned via x. If the conversion has type errors, the returned
|
||||
// conversion typechecks the type conversion conv to type typ.
|
||||
// The result of the conversion is returned via x.
|
||||
// If the conversion has type errors, the returned
|
||||
// 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
|
||||
if len(conv.Args) != 1 {
|
||||
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
|
||||
check.expr(x, conv.Args[0], iota)
|
||||
check.expr(x, conv.Args[0])
|
||||
if x.mode == invalid {
|
||||
goto Error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import (
|
|||
// - 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?
|
||||
// - 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
|
||||
|
||||
// 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
|
||||
(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
|
||||
to expression kind. Upon returning, rawExpr is recording the types and
|
||||
constant values for all expressions that have an untyped type (those types
|
||||
|
|
@ -611,11 +607,11 @@ var binaryOpPredicates = opPredicates{
|
|||
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
|
||||
|
||||
check.expr(x, lhs, iota)
|
||||
check.expr(&y, rhs, iota)
|
||||
check.expr(x, lhs)
|
||||
check.expr(&y, rhs)
|
||||
|
||||
if x.mode == invalid {
|
||||
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.
|
||||
// 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, iota int) (i int64, ok bool) {
|
||||
func (check *checker) index(arg ast.Expr, length int64) (i int64, ok bool) {
|
||||
var x operand
|
||||
check.expr(&x, arg, iota)
|
||||
check.expr(&x, arg)
|
||||
|
||||
// an untyped constant must be representable as 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
|
||||
// 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))
|
||||
var index, max int64
|
||||
for _, e := range elts {
|
||||
|
|
@ -734,7 +729,7 @@ func (check *checker) indexedElts(elts []ast.Expr, typ Type, length int64, iota
|
|||
validIndex := false
|
||||
eval := e
|
||||
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 {
|
||||
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
|
||||
var x operand
|
||||
check.exprWithHint(&x, eval, typ, iota)
|
||||
check.exprWithHint(&x, eval, typ)
|
||||
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)
|
||||
}
|
||||
|
|
@ -810,9 +805,8 @@ func (check *checker) callExpr(x *operand, ignore *bool) {
|
|||
// rawExpr typechecks expression e and initializes x with the expression
|
||||
// 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.
|
||||
// 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
|
||||
// (was issue 5770)
|
||||
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
|
||||
|
||||
case *ast.Ident:
|
||||
check.ident(x, e, iota, nil, false)
|
||||
check.ident(x, e, nil, false)
|
||||
|
||||
case *ast.Ellipsis:
|
||||
// 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:
|
||||
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.typ = sig
|
||||
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.
|
||||
// Create a new ArrayType with unknown length (-1)
|
||||
// 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
|
||||
}
|
||||
}
|
||||
if typ == nil {
|
||||
typ = check.typ(e.Type, iota, nil, false)
|
||||
typ = check.typ(e.Type, nil, false)
|
||||
}
|
||||
}
|
||||
if typ == nil {
|
||||
|
|
@ -915,7 +909,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) {
|
|||
continue
|
||||
}
|
||||
visited[i] = true
|
||||
check.expr(x, kv.Value, iota)
|
||||
check.expr(x, kv.Value)
|
||||
etyp := fld.typ
|
||||
if !check.assignment(x, etyp) {
|
||||
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")
|
||||
continue
|
||||
}
|
||||
check.expr(x, e, iota)
|
||||
check.expr(x, e)
|
||||
if i >= len(fields) {
|
||||
check.errorf(x.pos(), "too many values in struct literal")
|
||||
break // cannot continue
|
||||
|
|
@ -952,14 +946,14 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) {
|
|||
}
|
||||
|
||||
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 openArray {
|
||||
utyp.len = n
|
||||
}
|
||||
|
||||
case *Slice:
|
||||
check.indexedElts(e.Elts, utyp.elt, -1, iota)
|
||||
check.indexedElts(e.Elts, utyp.elt, -1)
|
||||
|
||||
case *Map:
|
||||
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")
|
||||
continue
|
||||
}
|
||||
check.expr(x, kv.Key, iota)
|
||||
check.expr(x, kv.Key)
|
||||
if !check.assignment(x, utyp.key) {
|
||||
if x.mode != invalid {
|
||||
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
|
||||
}
|
||||
check.exprWithHint(x, kv.Value, utyp.elt, iota)
|
||||
check.exprWithHint(x, kv.Value, utyp.elt)
|
||||
if !check.assignment(x, utyp.elt) {
|
||||
if x.mode != invalid {
|
||||
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
|
||||
|
||||
case *ast.ParenExpr:
|
||||
check.rawExpr(x, e.X, nil, iota)
|
||||
check.rawExpr(x, e.X, nil)
|
||||
|
||||
case *ast.SelectorExpr:
|
||||
check.selector(x, e, iota)
|
||||
check.selector(x, e)
|
||||
|
||||
case *ast.IndexExpr:
|
||||
check.expr(x, e.X, iota)
|
||||
check.expr(x, e.X)
|
||||
if x.mode == invalid {
|
||||
goto Error
|
||||
}
|
||||
|
|
@ -1051,7 +1045,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) {
|
|||
|
||||
case *Map:
|
||||
var key operand
|
||||
check.expr(&key, e.Index, iota)
|
||||
check.expr(&key, e.Index)
|
||||
if !check.assignment(&key, typ.key) {
|
||||
if key.mode != invalid {
|
||||
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
|
||||
}
|
||||
|
||||
check.index(e.Index, length, iota)
|
||||
check.index(e.Index, length)
|
||||
// ok to continue
|
||||
|
||||
case *ast.SliceExpr:
|
||||
check.expr(x, e.X, iota)
|
||||
check.expr(x, e.X)
|
||||
if x.mode == invalid {
|
||||
goto Error
|
||||
}
|
||||
|
|
@ -1134,14 +1128,14 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) {
|
|||
|
||||
lo := int64(0)
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
hi := int64(-1)
|
||||
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
|
||||
}
|
||||
} else if length >= 0 {
|
||||
|
|
@ -1154,7 +1148,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) {
|
|||
}
|
||||
|
||||
case *ast.TypeAssertExpr:
|
||||
check.expr(x, e.X, iota)
|
||||
check.expr(x, e.X)
|
||||
if x.mode == invalid {
|
||||
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")
|
||||
goto Error
|
||||
}
|
||||
typ := check.typ(e.Type, iota, nil, false)
|
||||
typ := check.typ(e.Type, nil, false)
|
||||
if typ == Typ[Invalid] {
|
||||
goto Error
|
||||
}
|
||||
|
|
@ -1192,10 +1186,10 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) {
|
|||
x.typ = typ
|
||||
|
||||
case *ast.CallExpr:
|
||||
check.call(x, e, iota)
|
||||
check.call(x, e)
|
||||
|
||||
case *ast.StarExpr:
|
||||
check.exprOrType(x, e.X, iota)
|
||||
check.exprOrType(x, e.X)
|
||||
switch x.mode {
|
||||
case invalid:
|
||||
goto Error
|
||||
|
|
@ -1212,7 +1206,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) {
|
|||
}
|
||||
|
||||
case *ast.UnaryExpr:
|
||||
check.expr(x, e.X, iota)
|
||||
check.expr(x, e.X)
|
||||
if x.mode == invalid {
|
||||
goto Error
|
||||
}
|
||||
|
|
@ -1222,7 +1216,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) {
|
|||
}
|
||||
|
||||
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 {
|
||||
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,
|
||||
*ast.InterfaceType, *ast.MapType, *ast.ChanType:
|
||||
x.mode = typexpr
|
||||
x.typ = check.typ(e, iota, nil, false)
|
||||
x.typ = check.typ(e, nil, false)
|
||||
// check.typ is already notifying clients
|
||||
// of e's type; don't do it a 2nd time
|
||||
ignore = true
|
||||
|
|
@ -1258,10 +1252,9 @@ Error:
|
|||
|
||||
// expr typechecks expression e and initializes x with the expression value.
|
||||
// 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) {
|
||||
check.rawExpr(x, e, nil, iota)
|
||||
func (check *checker) expr(x *operand, e ast.Expr) {
|
||||
check.rawExpr(x, e, nil)
|
||||
switch x.mode {
|
||||
case novalue:
|
||||
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.
|
||||
// If an error occurred, x.mode is set to invalid.
|
||||
// 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)
|
||||
check.rawExpr(x, e, hint, iota)
|
||||
check.rawExpr(x, e, hint)
|
||||
switch x.mode {
|
||||
case novalue:
|
||||
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.
|
||||
// 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) {
|
||||
check.rawExpr(x, e, nil, iota)
|
||||
func (check *checker) exprOrType(x *operand, e ast.Expr) {
|
||||
check.rawExpr(x, e, nil)
|
||||
if x.mode == novalue {
|
||||
check.errorf(x.pos(), "%s used as value or type", x)
|
||||
x.mode = invalid
|
||||
|
|
|
|||
|
|
@ -335,7 +335,7 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) {
|
|||
// - 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.
|
||||
func (check *checker) declareObject(obj Object, def *Named, cycleOk bool) {
|
||||
d := check.objMap[obj]
|
||||
|
|
@ -344,6 +344,10 @@ func (check *checker) declareObject(obj Object, def *Named, cycleOk bool) {
|
|||
oldScope := check.topScope
|
||||
check.topScope = d.file // for lookup
|
||||
|
||||
// save current iota
|
||||
oldIota := check.iota
|
||||
check.iota = nil
|
||||
|
||||
switch obj := obj.(type) {
|
||||
case *Const:
|
||||
check.declareConst(obj, d.typ, d.init)
|
||||
|
|
@ -357,6 +361,7 @@ func (check *checker) declareObject(obj Object, def *Named, cycleOk bool) {
|
|||
unreachable()
|
||||
}
|
||||
|
||||
check.iota = oldIota
|
||||
check.topScope = oldScope
|
||||
}
|
||||
|
||||
|
|
@ -367,12 +372,14 @@ func (check *checker) declareConst(obj *Const, typ, init ast.Expr) {
|
|||
return
|
||||
}
|
||||
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
|
||||
if typ != nil {
|
||||
obj.typ = check.typ(typ, int(iota), nil, false)
|
||||
obj.typ = check.typ(typ, nil, false)
|
||||
}
|
||||
|
||||
var x operand
|
||||
|
|
@ -381,12 +388,13 @@ func (check *checker) declareConst(obj *Const, typ, init ast.Expr) {
|
|||
goto Error // error reported before
|
||||
}
|
||||
|
||||
check.expr(&x, init, int(iota))
|
||||
check.expr(&x, init)
|
||||
if x.mode == invalid {
|
||||
goto Error
|
||||
}
|
||||
|
||||
check.assign(obj, &x)
|
||||
check.iota = nil
|
||||
return
|
||||
|
||||
Error:
|
||||
|
|
@ -395,6 +403,7 @@ Error:
|
|||
} else {
|
||||
obj.val = exact.MakeUnknown()
|
||||
}
|
||||
check.iota = nil
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
// var declarations cannot use iota
|
||||
assert(check.iota == nil)
|
||||
|
||||
// determine type, if any
|
||||
if typ != nil {
|
||||
obj.typ = check.typ(typ, -1, nil, false)
|
||||
obj.typ = check.typ(typ, nil, false)
|
||||
}
|
||||
|
||||
if init == nil {
|
||||
|
|
@ -424,7 +436,7 @@ func (check *checker) declareVar(obj *Var, typ, init ast.Expr) {
|
|||
}
|
||||
|
||||
var x operand
|
||||
check.expr(&x, init, -1)
|
||||
check.expr(&x, init)
|
||||
if x.mode == invalid {
|
||||
goto Error
|
||||
}
|
||||
|
|
@ -477,6 +489,9 @@ Error:
|
|||
func (check *checker) declareType(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
|
||||
|
||||
|
|
@ -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.
|
||||
u := check.typ(typ, -1, named, cycleOk)
|
||||
u := check.typ(typ, named, cycleOk)
|
||||
|
||||
// Determine the unnamed underlying type.
|
||||
// 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
|
||||
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)
|
||||
|
||||
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 declarations cannot use iota
|
||||
assert(check.iota == nil)
|
||||
|
||||
fdecl := obj.decl
|
||||
// methods are typechecked when their receivers are typechecked
|
||||
// TODO(gri) there is no reason to make this a special case: receivers are simply parameters
|
||||
if fdecl.Recv == nil {
|
||||
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) {
|
||||
check.errorf(fdecl.Pos(), "func init must have no arguments and no return values")
|
||||
// ok to continue
|
||||
|
|
|
|||
|
|
@ -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
|
||||
// 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)
|
||||
|
||||
// Start with rhs so we have an expression type
|
||||
// for declarations with implicit type.
|
||||
if x == nil {
|
||||
x = new(operand)
|
||||
check.expr(x, rhs, iota)
|
||||
check.expr(x, rhs)
|
||||
// don't exit for declarations - we need the lhs first
|
||||
if x.mode == invalid && !decl {
|
||||
return
|
||||
|
|
@ -70,7 +70,7 @@ func (check *checker) assign1to1(lhs, rhs ast.Expr, x *operand, decl bool, iota
|
|||
}
|
||||
|
||||
var z operand
|
||||
check.expr(&z, lhs, -1)
|
||||
check.expr(&z, lhs)
|
||||
if z.mode == invalid || z.typ == Typ[Invalid] {
|
||||
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.
|
||||
// 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(!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.
|
||||
if len(lhs) == len(rhs) {
|
||||
for i, e := range rhs {
|
||||
check.assign1to1(lhs[i], e, nil, decl, iota, isConst)
|
||||
check.assign1to1(lhs[i], e, nil, decl, isConst)
|
||||
}
|
||||
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
|
||||
// for declarations with implicit types.
|
||||
var x operand
|
||||
check.expr(&x, rhs[0], iota)
|
||||
check.expr(&x, rhs[0])
|
||||
if x.mode == invalid {
|
||||
goto Error
|
||||
}
|
||||
|
|
@ -207,7 +207,7 @@ func (check *checker) assignNtoM(lhs, rhs []ast.Expr, decl bool, iota int, isCon
|
|||
obj := t.At(i)
|
||||
x.expr = nil // TODO(gri) should do better here
|
||||
x.typ = obj.typ
|
||||
check.assign1to1(lhs[i], nil, &x, decl, iota, isConst)
|
||||
check.assign1to1(lhs[i], nil, &x, decl, isConst)
|
||||
}
|
||||
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 {
|
||||
// comma-ok expression
|
||||
x.mode = value
|
||||
check.assign1to1(lhs[0], nil, &x, decl, iota, isConst)
|
||||
check.assign1to1(lhs[0], nil, &x, decl, isConst)
|
||||
|
||||
x.typ = Typ[UntypedBool]
|
||||
check.assign1to1(lhs[1], nil, &x, decl, iota, isConst)
|
||||
check.assign1to1(lhs[1], nil, &x, decl, isConst)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
@ -307,6 +307,10 @@ func (check *checker) closeScope() {
|
|||
|
||||
// stmt typechecks statement s.
|
||||
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) {
|
||||
case *ast.BadStmt, *ast.EmptyStmt:
|
||||
// ignore
|
||||
|
|
@ -335,7 +339,7 @@ func (check *checker) stmt(s ast.Stmt) {
|
|||
// (Caution: This evaluates e.Fun twice, once here and once
|
||||
// below as part of s.X. This has consequences for
|
||||
// check.callIdent. Perhaps this can be avoided.)
|
||||
check.expr(&x, e.Fun, -1)
|
||||
check.expr(&x, e.Fun)
|
||||
if x.mode != invalid {
|
||||
if b, ok := x.typ.(*Builtin); ok && !b.isStatement {
|
||||
used = false
|
||||
|
|
@ -351,15 +355,15 @@ func (check *checker) stmt(s ast.Stmt) {
|
|||
check.errorf(s.Pos(), "%s not used", s.X)
|
||||
// ok to continue
|
||||
}
|
||||
check.rawExpr(&x, s.X, nil, -1)
|
||||
check.rawExpr(&x, s.X, nil)
|
||||
if x.mode == typexpr {
|
||||
check.errorf(x.pos(), "%s is not an expression", &x)
|
||||
}
|
||||
|
||||
case *ast.SendStmt:
|
||||
var ch, x operand
|
||||
check.expr(&ch, s.Chan, -1)
|
||||
check.expr(&x, s.Value, -1)
|
||||
check.expr(&ch, s.Chan)
|
||||
check.expr(&x, s.Value)
|
||||
if ch.mode == invalid || x.mode == invalid {
|
||||
return
|
||||
}
|
||||
|
|
@ -382,11 +386,11 @@ func (check *checker) stmt(s ast.Stmt) {
|
|||
}
|
||||
var x operand
|
||||
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 {
|
||||
return
|
||||
}
|
||||
check.assign1to1(s.X, nil, &x, false, -1, false)
|
||||
check.assign1to1(s.X, nil, &x, false, false)
|
||||
|
||||
case *ast.AssignStmt:
|
||||
switch s.Tok {
|
||||
|
|
@ -418,7 +422,7 @@ func (check *checker) stmt(s ast.Stmt) {
|
|||
check.declareShort(check.topScope, lhs) // scope starts after the assignment
|
||||
|
||||
} 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:
|
||||
|
|
@ -457,21 +461,21 @@ func (check *checker) stmt(s ast.Stmt) {
|
|||
return
|
||||
}
|
||||
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 {
|
||||
return
|
||||
}
|
||||
check.assign1to1(s.Lhs[0], nil, &x, false, -1, false)
|
||||
check.assign1to1(s.Lhs[0], nil, &x, false, false)
|
||||
}
|
||||
|
||||
case *ast.GoStmt:
|
||||
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.
|
||||
|
||||
case *ast.DeferStmt:
|
||||
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.
|
||||
|
||||
case *ast.ReturnStmt:
|
||||
|
|
@ -508,7 +512,7 @@ func (check *checker) stmt(s ast.Stmt) {
|
|||
}
|
||||
if len(s.Results) > 0 || !named {
|
||||
// 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 {
|
||||
check.errorf(s.Pos(), "no result values expected")
|
||||
|
|
@ -526,7 +530,7 @@ func (check *checker) stmt(s ast.Stmt) {
|
|||
check.openScope(s)
|
||||
check.optionalStmt(s.Init)
|
||||
var x operand
|
||||
check.expr(&x, s.Cond, -1)
|
||||
check.expr(&x, s.Cond)
|
||||
if x.mode != invalid && !isBoolean(x.typ) {
|
||||
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"))
|
||||
tag = ident
|
||||
}
|
||||
check.expr(&x, tag, -1)
|
||||
check.expr(&x, tag)
|
||||
|
||||
check.multipleDefaults(s.Body.List)
|
||||
// TODO(gri) check also correct use of fallthrough
|
||||
|
|
@ -559,7 +563,7 @@ func (check *checker) stmt(s ast.Stmt) {
|
|||
for _, expr := range clause.List {
|
||||
x := x // copy of x (don't modify original)
|
||||
var y operand
|
||||
check.expr(&y, expr, -1)
|
||||
check.expr(&y, expr)
|
||||
if y.mode == invalid {
|
||||
continue // error reported before
|
||||
}
|
||||
|
|
@ -645,7 +649,7 @@ func (check *checker) stmt(s ast.Stmt) {
|
|||
return
|
||||
}
|
||||
var x operand
|
||||
check.expr(&x, expr.X, -1)
|
||||
check.expr(&x, expr.X)
|
||||
if x.mode == invalid {
|
||||
return
|
||||
}
|
||||
|
|
@ -717,7 +721,7 @@ func (check *checker) stmt(s ast.Stmt) {
|
|||
check.optionalStmt(s.Init)
|
||||
if s.Cond != nil {
|
||||
var x operand
|
||||
check.expr(&x, s.Cond, -1)
|
||||
check.expr(&x, s.Cond)
|
||||
if x.mode != invalid && !isBoolean(x.typ) {
|
||||
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
|
||||
decl := s.Tok == token.DEFINE
|
||||
var x operand
|
||||
check.expr(&x, s.X, -1)
|
||||
check.expr(&x, s.X)
|
||||
if x.mode == invalid {
|
||||
// if we don't have a declaration, we can still check the loop's body
|
||||
if !decl {
|
||||
|
|
@ -792,7 +796,7 @@ func (check *checker) stmt(s ast.Stmt) {
|
|||
if s.Key != nil {
|
||||
x.typ = key
|
||||
x.expr = s.Key
|
||||
check.assign1to1(s.Key, nil, &x, decl, -1, false)
|
||||
check.assign1to1(s.Key, nil, &x, decl, false)
|
||||
} else {
|
||||
check.invalidAST(s.Pos(), "range clause requires index iteration variable")
|
||||
// ok to continue
|
||||
|
|
@ -800,7 +804,7 @@ func (check *checker) stmt(s ast.Stmt) {
|
|||
if s.Value != nil {
|
||||
x.typ = val
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -231,8 +231,43 @@ const (
|
|||
|
||||
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
|
||||
const (
|
||||
_n0 = nil /* ERROR "invalid constant type" */
|
||||
_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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,10 +16,9 @@ import (
|
|||
|
||||
// ident typechecks identifier e and initializes x with the value or type of e.
|
||||
// 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.
|
||||
//
|
||||
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.expr = e
|
||||
|
||||
|
|
@ -56,11 +55,11 @@ func (check *checker) ident(x *operand, e *ast.Ident, iota int, def *Named, cycl
|
|||
return
|
||||
}
|
||||
if obj == universeIota {
|
||||
if iota < 0 {
|
||||
check.invalidAST(e.Pos(), "cannot use iota outside constant declaration")
|
||||
if check.iota == nil {
|
||||
check.errorf(e.Pos(), "cannot use iota outside constant declaration")
|
||||
return
|
||||
}
|
||||
x.val = exact.MakeInt64(int64(iota))
|
||||
x.val = check.iota
|
||||
} else {
|
||||
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.
|
||||
// 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
|
||||
// in a type declaration, and def.underlying will be set to the type of e before
|
||||
// any components of e are typechecked.
|
||||
// If cycleOk is set, e (or elements of e) may refer to a named type that is not
|
||||
// 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 {
|
||||
check.trace(e.Pos(), "%s", e)
|
||||
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) {
|
||||
case *ast.Ident:
|
||||
var x operand
|
||||
check.ident(&x, e, iota, def, cycleOk)
|
||||
check.ident(&x, e, def, cycleOk)
|
||||
|
||||
switch x.mode {
|
||||
case typexpr:
|
||||
|
|
@ -132,7 +130,7 @@ func (check *checker) typ(e ast.Expr, iota int, def *Named, cycleOk bool) (res T
|
|||
|
||||
case *ast.SelectorExpr:
|
||||
var x operand
|
||||
check.selector(&x, e, iota)
|
||||
check.selector(&x, e)
|
||||
|
||||
switch x.mode {
|
||||
case typexpr:
|
||||
|
|
@ -146,12 +144,12 @@ func (check *checker) typ(e ast.Expr, iota int, def *Named, cycleOk bool) (res T
|
|||
}
|
||||
|
||||
case *ast.ParenExpr:
|
||||
return check.typ(e.X, iota, def, cycleOk)
|
||||
return check.typ(e.X, def, cycleOk)
|
||||
|
||||
case *ast.ArrayType:
|
||||
if e.Len != nil {
|
||||
var x operand
|
||||
check.expr(&x, e.Len, iota)
|
||||
check.expr(&x, e.Len)
|
||||
if x.mode != constant {
|
||||
if x.mode != invalid {
|
||||
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.elt = check.typ(e.Elt, iota, nil, cycleOk)
|
||||
typ.elt = check.typ(e.Elt, nil, cycleOk)
|
||||
return typ
|
||||
|
||||
} else {
|
||||
|
|
@ -183,7 +181,7 @@ func (check *checker) typ(e ast.Expr, iota int, def *Named, cycleOk bool) (res T
|
|||
def.underlying = typ
|
||||
}
|
||||
|
||||
typ.elt = check.typ(e.Elt, iota, nil, true)
|
||||
typ.elt = check.typ(e.Elt, nil, true)
|
||||
return typ
|
||||
}
|
||||
|
||||
|
|
@ -202,7 +200,7 @@ func (check *checker) typ(e ast.Expr, iota int, def *Named, cycleOk bool) (res T
|
|||
def.underlying = typ
|
||||
}
|
||||
|
||||
typ.base = check.typ(e.X, iota, nil, true)
|
||||
typ.base = check.typ(e.X, nil, true)
|
||||
return typ
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
typ.key = check.typ(e.Key, iota, nil, true)
|
||||
typ.elt = check.typ(e.Value, iota, nil, true)
|
||||
typ.key = check.typ(e.Key, nil, true)
|
||||
typ.elt = check.typ(e.Value, nil, true)
|
||||
return typ
|
||||
|
||||
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.elt = check.typ(e.Value, iota, nil, true)
|
||||
typ.elt = check.typ(e.Value, nil, true)
|
||||
return typ
|
||||
|
||||
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 {
|
||||
var x operand
|
||||
check.rawExpr(&x, e, nil, -1)
|
||||
check.rawExpr(&x, e, nil)
|
||||
switch x.mode {
|
||||
case invalid:
|
||||
// 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
|
||||
// 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 {
|
||||
// named parameter
|
||||
for _, name := range field.Names {
|
||||
|
|
@ -337,7 +335,7 @@ func (check *checker) collectMethods(list *ast.FieldList, cycleOk bool) (methods
|
|||
}
|
||||
scope := NewScope(nil)
|
||||
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
|
||||
// care if a constructed AST contains a non-nil tag
|
||||
if len(f.Names) > 0 {
|
||||
|
|
@ -413,7 +411,7 @@ func (check *checker) collectFields(list *ast.FieldList, cycleOk bool) (fields [
|
|||
}
|
||||
|
||||
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)
|
||||
if len(f.Names) > 0 {
|
||||
// named fields
|
||||
|
|
|
|||
Loading…
Reference in New Issue