Commit 973393c2 authored by Robert Griesemer's avatar Robert Griesemer

go/types: accept iotas inside closures of const init expressions

R=go1.11

Fixes #22345.

Change-Id: I7cf22d17bdd0143efb6ee48981e649ffe797aed9
Reviewed-on: https://go-review.googlesource.com/83579Reviewed-by: 's avatarAlan Donovan <adonovan@google.com>
parent ff6d7c2b
...@@ -112,7 +112,6 @@ func (check *Checker) constDecl(obj *Const, typ, init ast.Expr) { ...@@ -112,7 +112,6 @@ func (check *Checker) constDecl(obj *Const, typ, init ast.Expr) {
obj.visited = true obj.visited = true
// use the correct value of iota // use the correct value of iota
assert(check.iota == nil)
check.iota = obj.val check.iota = obj.val
defer func() { check.iota = nil }() defer func() { check.iota = nil }()
...@@ -151,9 +150,6 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) { ...@@ -151,9 +150,6 @@ func (check *Checker) varDecl(obj *Var, lhs []*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) obj.typ = check.typ(typ)
...@@ -234,9 +230,6 @@ func (n *Named) setUnderlying(typ Type) { ...@@ -234,9 +230,6 @@ func (n *Named) setUnderlying(typ Type) {
func (check *Checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, path []*TypeName, alias bool) { func (check *Checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, path []*TypeName, alias bool) {
assert(obj.typ == nil) assert(obj.typ == nil)
// type declarations cannot use iota
assert(check.iota == nil)
if alias { if alias {
obj.typ = Typ[Invalid] obj.typ = Typ[Invalid]
...@@ -356,7 +349,7 @@ func (check *Checker) funcDecl(obj *Func, decl *declInfo) { ...@@ -356,7 +349,7 @@ func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
// (functions implemented elsewhere have no body) // (functions implemented elsewhere have no body)
if !check.conf.IgnoreFuncBodies && fdecl.Body != nil { if !check.conf.IgnoreFuncBodies && fdecl.Body != nil {
check.later(func() { check.later(func() {
check.funcBody(decl, obj.name, sig, fdecl.Body) check.funcBody(decl, obj.name, sig, fdecl.Body, nil)
}) })
} }
} }
......
...@@ -1031,12 +1031,13 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind { ...@@ -1031,12 +1031,13 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
// init expression/func declaration which contains // init expression/func declaration which contains
// them: use existing package-level declaration info. // them: use existing package-level declaration info.
decl := check.decl // capture for use in closure below decl := check.decl // capture for use in closure below
iota := check.iota // capture for use in closure below (#22345)
// Don't type-check right away because the function may // Don't type-check right away because the function may
// be part of a type definition to which the function // be part of a type definition to which the function
// body refers. Instead, type-check as soon as possible, // body refers. Instead, type-check as soon as possible,
// but before the enclosing scope contents changes (#22992). // but before the enclosing scope contents changes (#22992).
check.later(func() { check.later(func() {
check.funcBody(decl, "<function literal>", sig, e.Body) check.funcBody(decl, "<function literal>", sig, e.Body, iota)
}) })
x.mode = value x.mode = value
x.typ = sig x.typ = sig
......
...@@ -13,7 +13,7 @@ import ( ...@@ -13,7 +13,7 @@ import (
"sort" "sort"
) )
func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body *ast.BlockStmt) { func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body *ast.BlockStmt, iota constant.Value) {
if trace { if trace {
check.trace(body.Pos(), "--- %s: %s", name, sig) check.trace(body.Pos(), "--- %s: %s", name, sig)
defer func() { defer func() {
...@@ -34,6 +34,7 @@ func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body ...@@ -34,6 +34,7 @@ func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body
check.context = context{ check.context = context{
decl: decl, decl: decl,
scope: sig.scope, scope: sig.scope,
iota: iota,
sig: sig, sig: sig,
} }
check.indent = 0 check.indent = 0
...@@ -290,10 +291,6 @@ L: ...@@ -290,10 +291,6 @@ L:
// stmt typechecks statement s. // stmt typechecks statement s.
func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) { func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
// statements cannot use iota in general
// (constant declarations set it explicitly)
assert(check.iota == nil)
// statements must end with the same top scope as they started with // statements must end with the same top scope as they started with
if debug { if debug {
defer func(scope *Scope) { defer func(scope *Scope) {
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
package const0 package const0
import "unsafe"
// constants declarations must be initialized by constants // constants declarations must be initialized by constants
var x = 0 var x = 0
const c0 = x /* ERROR "not constant" */ const c0 = x /* ERROR "not constant" */
...@@ -281,6 +283,45 @@ func _() { ...@@ -281,6 +283,45 @@ func _() {
_ = y _ = y
} }
// iotas are usable inside closures in constant declarations (#22345)
const (
_ = iota
_ = len([iota]byte{})
_ = unsafe.Sizeof(iota)
_ = unsafe.Sizeof(func() { _ = iota })
_ = unsafe.Sizeof(func() { var _ = iota })
_ = unsafe.Sizeof(func() { const _ = iota })
_ = unsafe.Sizeof(func() { type _ [iota]byte })
_ = unsafe.Sizeof(func() { func() int { return iota }() })
)
// verify inner and outer const declarations have distinct iotas
const (
zero = iota
one = iota
_ = unsafe.Sizeof(func() {
var x [iota]int // [2]int
const (
Zero = iota
One
Two
_ = unsafe.Sizeof([iota-1]int{} == x) // assert types are equal
_ = unsafe.Sizeof([Two]int{} == x) // assert types are equal
)
})
three = iota // the sequence continues
)
var _ [three]int = [3]int{} // assert 'three' has correct value
var (
_ = iota /* ERROR "iota outside constant decl" */
_ = unsafe.Sizeof(iota /* ERROR "iota outside constant decl" */ )
_ = unsafe.Sizeof(func() { _ = iota /* ERROR "iota outside constant decl" */ })
_ = unsafe.Sizeof(func() { var _ = iota /* ERROR "iota outside constant decl" */ })
_ = unsafe.Sizeof(func() { type _ [iota /* ERROR "iota outside constant decl" */ ]byte })
_ = unsafe.Sizeof(func() { func() int { return iota /* ERROR "iota outside constant decl" */ }() })
)
// constant arithmetic precision and rounding must lead to expected (integer) results // constant arithmetic precision and rounding must lead to expected (integer) results
var _ = []int64{ var _ = []int64{
0.0005 * 1e9, 0.0005 * 1e9,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment