1
0
mirror of https://github.com/golang/go synced 2024-11-19 01:04:40 -07: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: case *ast.BlockStmt:
check.openScope(s) check.openScope(s)
defer check.closeScope()
check.stmtList(inner, s.List) check.stmtList(inner, s.List)
check.closeScope()
case *ast.IfStmt: case *ast.IfStmt:
check.openScope(s) check.openScope(s)
defer check.closeScope()
check.initStmt(s.Init) check.initStmt(s.Init)
var x operand var x operand
check.expr(&x, s.Cond) check.expr(&x, s.Cond)
@ -326,11 +329,12 @@ func (check *checker) stmt(ctxt stmtContext, s ast.Stmt) {
if s.Else != nil { if s.Else != nil {
check.stmt(inner, s.Else) check.stmt(inner, s.Else)
} }
check.closeScope()
case *ast.SwitchStmt: case *ast.SwitchStmt:
inner |= inBreakable inner |= inBreakable
check.openScope(s) check.openScope(s)
defer check.closeScope()
check.initStmt(s.Init) check.initStmt(s.Init)
var x operand var x operand
tag := s.Tag tag := s.Tag
@ -361,12 +365,12 @@ func (check *checker) stmt(ctxt stmtContext, s ast.Stmt) {
check.stmtList(inner, clause.Body) check.stmtList(inner, clause.Body)
check.closeScope() check.closeScope()
} }
check.closeScope()
case *ast.TypeSwitchStmt: case *ast.TypeSwitchStmt:
inner |= inBreakable inner |= inBreakable
check.openScope(s) check.openScope(s)
defer check.closeScope() defer check.closeScope()
check.initStmt(s.Init) check.initStmt(s.Init)
// A type switch guard must be of the form: // 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 { if clause == nil {
continue // error reported before continue // error reported before
} }
check.openScope(clause)
if s := clause.Comm; s != nil { // clause.Comm must be a SendStmt, RecvStmt, or default case
check.stmt(inner, s) // TODO(gri) check correctness of c.Comm (must be Send/RecvStmt) 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.stmtList(inner, clause.Body)
check.closeScope()
} }
case *ast.ForStmt: case *ast.ForStmt:
inner |= inBreakable | inContinuable inner |= inBreakable | inContinuable
check.openScope(s) check.openScope(s)
defer check.closeScope()
check.initStmt(s.Init) check.initStmt(s.Init)
if s.Cond != nil { if s.Cond != nil {
var x operand var x operand
@ -494,7 +527,6 @@ func (check *checker) stmt(ctxt stmtContext, s ast.Stmt) {
} }
check.initStmt(s.Post) check.initStmt(s.Post)
check.stmt(inner, s.Body) check.stmt(inner, s.Body)
check.closeScope()
case *ast.RangeStmt: case *ast.RangeStmt:
inner |= inBreakable | inContinuable inner |= inBreakable | inContinuable

View File

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