go/types: don't permit declarations in post statements
Plus better names for some internal objects. Fixes golang/go#8804. LGTM=adonovan R=adonovan CC=golang-codereviews https://golang.org/cl/149080043
This commit is contained in:
parent
29d9ef959c
commit
6f764e19fa
|
|
@ -64,17 +64,17 @@ func (check *Checker) usage(scope *Scope) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// stmtContext is a bitset describing the environment
|
// stmtContext is a bitset describing which
|
||||||
// (outer statements) containing a statement.
|
// control-flow statements are permissible.
|
||||||
type stmtContext uint
|
type stmtContext uint
|
||||||
|
|
||||||
const (
|
const (
|
||||||
fallthroughOk stmtContext = 1 << iota
|
breakOk stmtContext = 1 << iota
|
||||||
inBreakable
|
continueOk
|
||||||
inContinuable
|
fallthroughOk
|
||||||
)
|
)
|
||||||
|
|
||||||
func (check *Checker) initStmt(s ast.Stmt) {
|
func (check *Checker) simpleStmt(s ast.Stmt) {
|
||||||
if s != nil {
|
if s != nil {
|
||||||
check.stmt(0, s)
|
check.stmt(0, s)
|
||||||
}
|
}
|
||||||
|
|
@ -351,11 +351,11 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
|
||||||
}
|
}
|
||||||
switch s.Tok {
|
switch s.Tok {
|
||||||
case token.BREAK:
|
case token.BREAK:
|
||||||
if ctxt&inBreakable == 0 {
|
if ctxt&breakOk == 0 {
|
||||||
check.error(s.Pos(), "break not in for, switch, or select statement")
|
check.error(s.Pos(), "break not in for, switch, or select statement")
|
||||||
}
|
}
|
||||||
case token.CONTINUE:
|
case token.CONTINUE:
|
||||||
if ctxt&inContinuable == 0 {
|
if ctxt&continueOk == 0 {
|
||||||
check.error(s.Pos(), "continue not in for statement")
|
check.error(s.Pos(), "continue not in for statement")
|
||||||
}
|
}
|
||||||
case token.FALLTHROUGH:
|
case token.FALLTHROUGH:
|
||||||
|
|
@ -376,7 +376,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
|
||||||
check.openScope(s, "if")
|
check.openScope(s, "if")
|
||||||
defer check.closeScope()
|
defer check.closeScope()
|
||||||
|
|
||||||
check.initStmt(s.Init)
|
check.simpleStmt(s.Init)
|
||||||
var x operand
|
var x operand
|
||||||
check.expr(&x, s.Cond)
|
check.expr(&x, s.Cond)
|
||||||
if x.mode != invalid && !isBoolean(x.typ) {
|
if x.mode != invalid && !isBoolean(x.typ) {
|
||||||
|
|
@ -388,11 +388,11 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case *ast.SwitchStmt:
|
case *ast.SwitchStmt:
|
||||||
inner |= inBreakable
|
inner |= breakOk
|
||||||
check.openScope(s, "switch")
|
check.openScope(s, "switch")
|
||||||
defer check.closeScope()
|
defer check.closeScope()
|
||||||
|
|
||||||
check.initStmt(s.Init)
|
check.simpleStmt(s.Init)
|
||||||
var x operand
|
var x operand
|
||||||
if s.Tag != nil {
|
if s.Tag != nil {
|
||||||
check.expr(&x, s.Tag)
|
check.expr(&x, s.Tag)
|
||||||
|
|
@ -426,11 +426,11 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case *ast.TypeSwitchStmt:
|
case *ast.TypeSwitchStmt:
|
||||||
inner |= inBreakable
|
inner |= breakOk
|
||||||
check.openScope(s, "type switch")
|
check.openScope(s, "type switch")
|
||||||
defer check.closeScope()
|
defer check.closeScope()
|
||||||
|
|
||||||
check.initStmt(s.Init)
|
check.simpleStmt(s.Init)
|
||||||
|
|
||||||
// A type switch guard must be of the form:
|
// A type switch guard must be of the form:
|
||||||
//
|
//
|
||||||
|
|
@ -532,7 +532,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case *ast.SelectStmt:
|
case *ast.SelectStmt:
|
||||||
inner |= inBreakable
|
inner |= breakOk
|
||||||
|
|
||||||
check.multipleDefaults(s.Body.List)
|
check.multipleDefaults(s.Body.List)
|
||||||
|
|
||||||
|
|
@ -577,11 +577,11 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case *ast.ForStmt:
|
case *ast.ForStmt:
|
||||||
inner |= inBreakable | inContinuable
|
inner |= breakOk | continueOk
|
||||||
check.openScope(s, "for")
|
check.openScope(s, "for")
|
||||||
defer check.closeScope()
|
defer check.closeScope()
|
||||||
|
|
||||||
check.initStmt(s.Init)
|
check.simpleStmt(s.Init)
|
||||||
if s.Cond != nil {
|
if s.Cond != nil {
|
||||||
var x operand
|
var x operand
|
||||||
check.expr(&x, s.Cond)
|
check.expr(&x, s.Cond)
|
||||||
|
|
@ -589,11 +589,17 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
|
||||||
check.error(s.Cond.Pos(), "non-boolean condition in for statement")
|
check.error(s.Cond.Pos(), "non-boolean condition in for statement")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
check.initStmt(s.Post)
|
check.simpleStmt(s.Post)
|
||||||
|
// spec: "The init statement may be a short variable
|
||||||
|
// declaration, but the post statement must not."
|
||||||
|
if s, _ := s.Post.(*ast.AssignStmt); s != nil && s.Tok == token.DEFINE {
|
||||||
|
check.softErrorf(s.Pos(), "cannot declare in post statement")
|
||||||
|
check.use(s.Lhs...) // avoid follow-up errors
|
||||||
|
}
|
||||||
check.stmt(inner, s.Body)
|
check.stmt(inner, s.Body)
|
||||||
|
|
||||||
case *ast.RangeStmt:
|
case *ast.RangeStmt:
|
||||||
inner |= inBreakable | inContinuable
|
inner |= breakOk | continueOk
|
||||||
check.openScope(s, "for")
|
check.openScope(s, "for")
|
||||||
defer check.closeScope()
|
defer check.closeScope()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -622,6 +622,14 @@ func typeswitch3(x interface{}) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fors1() {
|
||||||
|
for {}
|
||||||
|
var i string
|
||||||
|
_ = i
|
||||||
|
for i := 0; i < 10; i++ {}
|
||||||
|
for i := 0; i < 10; j /* ERROR cannot declare */ := 0 {}
|
||||||
|
}
|
||||||
|
|
||||||
func rangeloops1() {
|
func rangeloops1() {
|
||||||
var (
|
var (
|
||||||
x int
|
x int
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue