1
0
mirror of https://github.com/golang/go synced 2024-10-01 10:28:31 -06:00

go.tools/go/types: missing checks for select statements

Also: Use defer to make sure scopes are always closed
even in case of early exits via bailout (and don't cause
an imbalanced scope error in debug mode).

R=adonovan, gri
CC=golang-dev
https://golang.org/cl/29300043
This commit is contained in:
Robert Griesemer 2013-11-19 13:58:01 -08:00
parent 849643aaaf
commit b4286c4c1b
2 changed files with 54 additions and 12 deletions

View File

@ -311,11 +311,14 @@ func (check *checker) stmt(ctxt stmtContext, s ast.Stmt) {
case *ast.BlockStmt:
check.openScope(s)
defer check.closeScope()
check.stmtList(inner, s.List)
check.closeScope()
case *ast.IfStmt:
check.openScope(s)
defer check.closeScope()
check.initStmt(s.Init)
var x operand
check.expr(&x, s.Cond)
@ -326,11 +329,12 @@ func (check *checker) stmt(ctxt stmtContext, s ast.Stmt) {
if s.Else != nil {
check.stmt(inner, s.Else)
}
check.closeScope()
case *ast.SwitchStmt:
inner |= inBreakable
check.openScope(s)
defer check.closeScope()
check.initStmt(s.Init)
var x operand
tag := s.Tag
@ -361,12 +365,12 @@ func (check *checker) stmt(ctxt stmtContext, s ast.Stmt) {
check.stmtList(inner, clause.Body)
check.closeScope()
}
check.closeScope()
case *ast.TypeSwitchStmt:
inner |= inBreakable
check.openScope(s)
defer check.closeScope()
check.initStmt(s.Init)
// A type switch guard must be of the form:
@ -473,17 +477,46 @@ func (check *checker) stmt(ctxt stmtContext, s ast.Stmt) {
if clause == nil {
continue // error reported before
}
check.openScope(clause)
if s := clause.Comm; s != nil {
check.stmt(inner, s) // TODO(gri) check correctness of c.Comm (must be Send/RecvStmt)
// clause.Comm must be a SendStmt, RecvStmt, or default case
valid := false
var rhs ast.Expr // rhs of RecvStmt, or nil
switch s := clause.Comm.(type) {
case nil, *ast.SendStmt:
valid = true
case *ast.AssignStmt:
if len(s.Rhs) == 1 {
rhs = s.Rhs[0]
}
case *ast.ExprStmt:
rhs = s.X
}
// if present, rhs must be a receive operation
if rhs != nil {
if x, _ := unparen(rhs).(*ast.UnaryExpr); x != nil && x.Op == token.ARROW {
valid = true
}
}
if !valid {
check.errorf(clause.Comm.Pos(), "select case must be send or receive (possibly with assignment)")
continue
}
check.openScope(s)
defer check.closeScope()
if clause.Comm != nil {
check.stmt(inner, clause.Comm)
}
check.stmtList(inner, clause.Body)
check.closeScope()
}
case *ast.ForStmt:
inner |= inBreakable | inContinuable
check.openScope(s)
defer check.closeScope()
check.initStmt(s.Init)
if s.Cond != nil {
var x operand
@ -494,7 +527,6 @@ func (check *checker) stmt(ctxt stmtContext, s ast.Stmt) {
}
check.initStmt(s.Post)
check.stmt(inner, s.Body)
check.closeScope()
case *ast.RangeStmt:
inner |= inBreakable | inContinuable

View File

@ -186,20 +186,30 @@ func selects() {
var (
ch chan int
sc chan <- bool
x int
)
select {
case <-ch:
ch <- x
case (<-ch):
case t := <-ch:
_ = t
case t := (<-ch):
_ = t
case t, ok := <-ch:
x = t
_ = ok
_, _ = t, ok
case t, ok := (<-ch):
_, _ = t, ok
case <-sc /* ERROR "cannot receive from send-only channel" */ :
}
select {
default:
default /* ERROR "multiple defaults" */ :
}
select {
case a, b := <-ch:
_, b = a, b
case x /* ERROR send or receive */ :
case a /* ERROR send or receive */ := ch:
}
}
func gos() {