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) {
|
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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue