Home | History | Annotate | Download | only in types
      1 // Copyright 2012 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 // This file implements typechecking of statements.
      6 
      7 package types
      8 
      9 import (
     10 	"fmt"
     11 	"go/ast"
     12 	"go/constant"
     13 	"go/token"
     14 )
     15 
     16 func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body *ast.BlockStmt) {
     17 	if trace {
     18 		if name == "" {
     19 			name = "<function literal>"
     20 		}
     21 		fmt.Printf("--- %s: %s {\n", name, sig)
     22 		defer fmt.Println("--- <end>")
     23 	}
     24 
     25 	// set function scope extent
     26 	sig.scope.pos = body.Pos()
     27 	sig.scope.end = body.End()
     28 
     29 	// save/restore current context and setup function context
     30 	// (and use 0 indentation at function start)
     31 	defer func(ctxt context, indent int) {
     32 		check.context = ctxt
     33 		check.indent = indent
     34 	}(check.context, check.indent)
     35 	check.context = context{
     36 		decl:  decl,
     37 		scope: sig.scope,
     38 		sig:   sig,
     39 	}
     40 	check.indent = 0
     41 
     42 	check.stmtList(0, body.List)
     43 
     44 	if check.hasLabel {
     45 		check.labels(body)
     46 	}
     47 
     48 	if sig.results.Len() > 0 && !check.isTerminating(body, "") {
     49 		check.error(body.Rbrace, "missing return")
     50 	}
     51 
     52 	// spec: "Implementation restriction: A compiler may make it illegal to
     53 	// declare a variable inside a function body if the variable is never used."
     54 	// (One could check each scope after use, but that distributes this check
     55 	// over several places because CloseScope is not always called explicitly.)
     56 	check.usage(sig.scope)
     57 }
     58 
     59 func (check *Checker) usage(scope *Scope) {
     60 	for _, obj := range scope.elems {
     61 		if v, _ := obj.(*Var); v != nil && !v.used {
     62 			check.softErrorf(v.pos, "%s declared but not used", v.name)
     63 		}
     64 	}
     65 	for _, scope := range scope.children {
     66 		check.usage(scope)
     67 	}
     68 }
     69 
     70 // stmtContext is a bitset describing which
     71 // control-flow statements are permissible,
     72 // and provides additional context information
     73 // for better error messages.
     74 type stmtContext uint
     75 
     76 const (
     77 	// permissible control-flow statements
     78 	breakOk stmtContext = 1 << iota
     79 	continueOk
     80 	fallthroughOk
     81 
     82 	// additional context information
     83 	finalSwitchCase
     84 )
     85 
     86 func (check *Checker) simpleStmt(s ast.Stmt) {
     87 	if s != nil {
     88 		check.stmt(0, s)
     89 	}
     90 }
     91 
     92 func trimTrailingEmptyStmts(list []ast.Stmt) []ast.Stmt {
     93 	for i := len(list); i > 0; i-- {
     94 		if _, ok := list[i-1].(*ast.EmptyStmt); !ok {
     95 			return list[:i]
     96 		}
     97 	}
     98 	return nil
     99 }
    100 
    101 func (check *Checker) stmtList(ctxt stmtContext, list []ast.Stmt) {
    102 	ok := ctxt&fallthroughOk != 0
    103 	inner := ctxt &^ fallthroughOk
    104 	list = trimTrailingEmptyStmts(list) // trailing empty statements are "invisible" to fallthrough analysis
    105 	for i, s := range list {
    106 		inner := inner
    107 		if ok && i+1 == len(list) {
    108 			inner |= fallthroughOk
    109 		}
    110 		check.stmt(inner, s)
    111 	}
    112 }
    113 
    114 func (check *Checker) multipleDefaults(list []ast.Stmt) {
    115 	var first ast.Stmt
    116 	for _, s := range list {
    117 		var d ast.Stmt
    118 		switch c := s.(type) {
    119 		case *ast.CaseClause:
    120 			if len(c.List) == 0 {
    121 				d = s
    122 			}
    123 		case *ast.CommClause:
    124 			if c.Comm == nil {
    125 				d = s
    126 			}
    127 		default:
    128 			check.invalidAST(s.Pos(), "case/communication clause expected")
    129 		}
    130 		if d != nil {
    131 			if first != nil {
    132 				check.errorf(d.Pos(), "multiple defaults (first at %s)", check.fset.Position(first.Pos()))
    133 			} else {
    134 				first = d
    135 			}
    136 		}
    137 	}
    138 }
    139 
    140 func (check *Checker) openScope(s ast.Stmt, comment string) {
    141 	scope := NewScope(check.scope, s.Pos(), s.End(), comment)
    142 	check.recordScope(s, scope)
    143 	check.scope = scope
    144 }
    145 
    146 func (check *Checker) closeScope() {
    147 	check.scope = check.scope.Parent()
    148 }
    149 
    150 func assignOp(op token.Token) token.Token {
    151 	// token_test.go verifies the token ordering this function relies on
    152 	if token.ADD_ASSIGN <= op && op <= token.AND_NOT_ASSIGN {
    153 		return op + (token.ADD - token.ADD_ASSIGN)
    154 	}
    155 	return token.ILLEGAL
    156 }
    157 
    158 func (check *Checker) suspendedCall(keyword string, call *ast.CallExpr) {
    159 	var x operand
    160 	var msg string
    161 	switch check.rawExpr(&x, call, nil) {
    162 	case conversion:
    163 		msg = "requires function call, not conversion"
    164 	case expression:
    165 		msg = "discards result of"
    166 	case statement:
    167 		return
    168 	default:
    169 		unreachable()
    170 	}
    171 	check.errorf(x.pos(), "%s %s %s", keyword, msg, &x)
    172 }
    173 
    174 // goVal returns the Go value for val, or nil.
    175 func goVal(val constant.Value) interface{} {
    176 	// val should exist, but be conservative and check
    177 	if val == nil {
    178 		return nil
    179 	}
    180 	// Match implementation restriction of other compilers.
    181 	// gc only checks duplicates for integer, floating-point
    182 	// and string values, so only create Go values for these
    183 	// types.
    184 	switch val.Kind() {
    185 	case constant.Int:
    186 		if x, ok := constant.Int64Val(val); ok {
    187 			return x
    188 		}
    189 		if x, ok := constant.Uint64Val(val); ok {
    190 			return x
    191 		}
    192 	case constant.Float:
    193 		if x, ok := constant.Float64Val(val); ok {
    194 			return x
    195 		}
    196 	case constant.String:
    197 		return constant.StringVal(val)
    198 	}
    199 	return nil
    200 }
    201 
    202 // A valueMap maps a case value (of a basic Go type) to a list of positions
    203 // where the same case value appeared, together with the corresponding case
    204 // types.
    205 // Since two case values may have the same "underlying" value but different
    206 // types we need to also check the value's types (e.g., byte(1) vs myByte(1))
    207 // when the switch expression is of interface type.
    208 type (
    209 	valueMap  map[interface{}][]valueType // underlying Go value -> valueType
    210 	valueType struct {
    211 		pos token.Pos
    212 		typ Type
    213 	}
    214 )
    215 
    216 func (check *Checker) caseValues(x *operand, values []ast.Expr, seen valueMap) {
    217 L:
    218 	for _, e := range values {
    219 		var v operand
    220 		check.expr(&v, e)
    221 		if x.mode == invalid || v.mode == invalid {
    222 			continue L
    223 		}
    224 		check.convertUntyped(&v, x.typ)
    225 		if v.mode == invalid {
    226 			continue L
    227 		}
    228 		// Order matters: By comparing v against x, error positions are at the case values.
    229 		res := v // keep original v unchanged
    230 		check.comparison(&res, x, token.EQL)
    231 		if res.mode == invalid {
    232 			continue L
    233 		}
    234 		if v.mode != constant_ {
    235 			continue L // we're done
    236 		}
    237 		// look for duplicate values
    238 		if val := goVal(v.val); val != nil {
    239 			if list := seen[val]; list != nil {
    240 				// look for duplicate types for a given value
    241 				// (quadratic algorithm, but these lists tend to be very short)
    242 				for _, vt := range list {
    243 					if Identical(v.typ, vt.typ) {
    244 						check.errorf(v.pos(), "duplicate case %s in expression switch", &v)
    245 						check.error(vt.pos, "\tprevious case") // secondary error, \t indented
    246 						continue L
    247 					}
    248 				}
    249 			}
    250 			seen[val] = append(seen[val], valueType{v.pos(), v.typ})
    251 		}
    252 	}
    253 }
    254 
    255 func (check *Checker) caseTypes(x *operand, xtyp *Interface, types []ast.Expr, seen map[Type]token.Pos) (T Type) {
    256 L:
    257 	for _, e := range types {
    258 		T = check.typOrNil(e)
    259 		if T == Typ[Invalid] {
    260 			continue L
    261 		}
    262 		// look for duplicate types
    263 		// (quadratic algorithm, but type switches tend to be reasonably small)
    264 		for t, pos := range seen {
    265 			if T == nil && t == nil || T != nil && t != nil && Identical(T, t) {
    266 				// talk about "case" rather than "type" because of nil case
    267 				Ts := "nil"
    268 				if T != nil {
    269 					Ts = T.String()
    270 				}
    271 				check.errorf(e.Pos(), "duplicate case %s in type switch", Ts)
    272 				check.error(pos, "\tprevious case") // secondary error, \t indented
    273 				continue L
    274 			}
    275 		}
    276 		seen[T] = e.Pos()
    277 		if T != nil {
    278 			check.typeAssertion(e.Pos(), x, xtyp, T)
    279 		}
    280 	}
    281 	return
    282 }
    283 
    284 // stmt typechecks statement s.
    285 func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
    286 	// statements cannot use iota in general
    287 	// (constant declarations set it explicitly)
    288 	assert(check.iota == nil)
    289 
    290 	// statements must end with the same top scope as they started with
    291 	if debug {
    292 		defer func(scope *Scope) {
    293 			// don't check if code is panicking
    294 			if p := recover(); p != nil {
    295 				panic(p)
    296 			}
    297 			assert(scope == check.scope)
    298 		}(check.scope)
    299 	}
    300 
    301 	inner := ctxt &^ (fallthroughOk | finalSwitchCase)
    302 	switch s := s.(type) {
    303 	case *ast.BadStmt, *ast.EmptyStmt:
    304 		// ignore
    305 
    306 	case *ast.DeclStmt:
    307 		check.declStmt(s.Decl)
    308 
    309 	case *ast.LabeledStmt:
    310 		check.hasLabel = true
    311 		check.stmt(ctxt, s.Stmt)
    312 
    313 	case *ast.ExprStmt:
    314 		// spec: "With the exception of specific built-in functions,
    315 		// function and method calls and receive operations can appear
    316 		// in statement context. Such statements may be parenthesized."
    317 		var x operand
    318 		kind := check.rawExpr(&x, s.X, nil)
    319 		var msg string
    320 		switch x.mode {
    321 		default:
    322 			if kind == statement {
    323 				return
    324 			}
    325 			msg = "is not used"
    326 		case builtin:
    327 			msg = "must be called"
    328 		case typexpr:
    329 			msg = "is not an expression"
    330 		}
    331 		check.errorf(x.pos(), "%s %s", &x, msg)
    332 
    333 	case *ast.SendStmt:
    334 		var ch, x operand
    335 		check.expr(&ch, s.Chan)
    336 		check.expr(&x, s.Value)
    337 		if ch.mode == invalid || x.mode == invalid {
    338 			return
    339 		}
    340 
    341 		tch, ok := ch.typ.Underlying().(*Chan)
    342 		if !ok {
    343 			check.invalidOp(s.Arrow, "cannot send to non-chan type %s", ch.typ)
    344 			return
    345 		}
    346 
    347 		if tch.dir == RecvOnly {
    348 			check.invalidOp(s.Arrow, "cannot send to receive-only type %s", tch)
    349 			return
    350 		}
    351 
    352 		check.assignment(&x, tch.elem, "send")
    353 
    354 	case *ast.IncDecStmt:
    355 		var op token.Token
    356 		switch s.Tok {
    357 		case token.INC:
    358 			op = token.ADD
    359 		case token.DEC:
    360 			op = token.SUB
    361 		default:
    362 			check.invalidAST(s.TokPos, "unknown inc/dec operation %s", s.Tok)
    363 			return
    364 		}
    365 
    366 		var x operand
    367 		check.expr(&x, s.X)
    368 		if x.mode == invalid {
    369 			return
    370 		}
    371 		if !isNumeric(x.typ) {
    372 			check.invalidOp(s.X.Pos(), "%s%s (non-numeric type %s)", s.X, s.Tok, x.typ)
    373 			return
    374 		}
    375 
    376 		Y := &ast.BasicLit{ValuePos: s.X.Pos(), Kind: token.INT, Value: "1"} // use x's position
    377 		check.binary(&x, nil, s.X, Y, op)
    378 		if x.mode == invalid {
    379 			return
    380 		}
    381 		check.assignVar(s.X, &x)
    382 
    383 	case *ast.AssignStmt:
    384 		switch s.Tok {
    385 		case token.ASSIGN, token.DEFINE:
    386 			if len(s.Lhs) == 0 {
    387 				check.invalidAST(s.Pos(), "missing lhs in assignment")
    388 				return
    389 			}
    390 			if s.Tok == token.DEFINE {
    391 				check.shortVarDecl(s.TokPos, s.Lhs, s.Rhs)
    392 			} else {
    393 				// regular assignment
    394 				check.assignVars(s.Lhs, s.Rhs)
    395 			}
    396 
    397 		default:
    398 			// assignment operations
    399 			if len(s.Lhs) != 1 || len(s.Rhs) != 1 {
    400 				check.errorf(s.TokPos, "assignment operation %s requires single-valued expressions", s.Tok)
    401 				return
    402 			}
    403 			op := assignOp(s.Tok)
    404 			if op == token.ILLEGAL {
    405 				check.invalidAST(s.TokPos, "unknown assignment operation %s", s.Tok)
    406 				return
    407 			}
    408 			var x operand
    409 			check.binary(&x, nil, s.Lhs[0], s.Rhs[0], op)
    410 			if x.mode == invalid {
    411 				return
    412 			}
    413 			check.assignVar(s.Lhs[0], &x)
    414 		}
    415 
    416 	case *ast.GoStmt:
    417 		check.suspendedCall("go", s.Call)
    418 
    419 	case *ast.DeferStmt:
    420 		check.suspendedCall("defer", s.Call)
    421 
    422 	case *ast.ReturnStmt:
    423 		res := check.sig.results
    424 		if res.Len() > 0 {
    425 			// function returns results
    426 			// (if one, say the first, result parameter is named, all of them are named)
    427 			if len(s.Results) == 0 && res.vars[0].name != "" {
    428 				// spec: "Implementation restriction: A compiler may disallow an empty expression
    429 				// list in a "return" statement if a different entity (constant, type, or variable)
    430 				// with the same name as a result parameter is in scope at the place of the return."
    431 				for _, obj := range res.vars {
    432 					if _, alt := check.scope.LookupParent(obj.name, check.pos); alt != nil && alt != obj {
    433 						check.errorf(s.Pos(), "result parameter %s not in scope at return", obj.name)
    434 						check.errorf(alt.Pos(), "\tinner declaration of %s", obj)
    435 						// ok to continue
    436 					}
    437 				}
    438 			} else {
    439 				// return has results or result parameters are unnamed
    440 				check.initVars(res.vars, s.Results, s.Return)
    441 			}
    442 		} else if len(s.Results) > 0 {
    443 			check.error(s.Results[0].Pos(), "no result values expected")
    444 			check.use(s.Results...)
    445 		}
    446 
    447 	case *ast.BranchStmt:
    448 		if s.Label != nil {
    449 			check.hasLabel = true
    450 			return // checked in 2nd pass (check.labels)
    451 		}
    452 		switch s.Tok {
    453 		case token.BREAK:
    454 			if ctxt&breakOk == 0 {
    455 				check.error(s.Pos(), "break not in for, switch, or select statement")
    456 			}
    457 		case token.CONTINUE:
    458 			if ctxt&continueOk == 0 {
    459 				check.error(s.Pos(), "continue not in for statement")
    460 			}
    461 		case token.FALLTHROUGH:
    462 			if ctxt&fallthroughOk == 0 {
    463 				msg := "fallthrough statement out of place"
    464 				if ctxt&finalSwitchCase != 0 {
    465 					msg = "cannot fallthrough final case in switch"
    466 				}
    467 				check.error(s.Pos(), msg)
    468 			}
    469 		default:
    470 			check.invalidAST(s.Pos(), "branch statement: %s", s.Tok)
    471 		}
    472 
    473 	case *ast.BlockStmt:
    474 		check.openScope(s, "block")
    475 		defer check.closeScope()
    476 
    477 		check.stmtList(inner, s.List)
    478 
    479 	case *ast.IfStmt:
    480 		check.openScope(s, "if")
    481 		defer check.closeScope()
    482 
    483 		check.simpleStmt(s.Init)
    484 		var x operand
    485 		check.expr(&x, s.Cond)
    486 		if x.mode != invalid && !isBoolean(x.typ) {
    487 			check.error(s.Cond.Pos(), "non-boolean condition in if statement")
    488 		}
    489 		check.stmt(inner, s.Body)
    490 		// The parser produces a correct AST but if it was modified
    491 		// elsewhere the else branch may be invalid. Check again.
    492 		switch s.Else.(type) {
    493 		case nil, *ast.BadStmt:
    494 			// valid or error already reported
    495 		case *ast.IfStmt, *ast.BlockStmt:
    496 			check.stmt(inner, s.Else)
    497 		default:
    498 			check.error(s.Else.Pos(), "invalid else branch in if statement")
    499 		}
    500 
    501 	case *ast.SwitchStmt:
    502 		inner |= breakOk
    503 		check.openScope(s, "switch")
    504 		defer check.closeScope()
    505 
    506 		check.simpleStmt(s.Init)
    507 		var x operand
    508 		if s.Tag != nil {
    509 			check.expr(&x, s.Tag)
    510 			// By checking assignment of x to an invisible temporary
    511 			// (as a compiler would), we get all the relevant checks.
    512 			check.assignment(&x, nil, "switch expression")
    513 		} else {
    514 			// spec: "A missing switch expression is
    515 			// equivalent to the boolean value true."
    516 			x.mode = constant_
    517 			x.typ = Typ[Bool]
    518 			x.val = constant.MakeBool(true)
    519 			x.expr = &ast.Ident{NamePos: s.Body.Lbrace, Name: "true"}
    520 		}
    521 
    522 		check.multipleDefaults(s.Body.List)
    523 
    524 		seen := make(valueMap) // map of seen case values to positions and types
    525 		for i, c := range s.Body.List {
    526 			clause, _ := c.(*ast.CaseClause)
    527 			if clause == nil {
    528 				check.invalidAST(c.Pos(), "incorrect expression switch case")
    529 				continue
    530 			}
    531 			check.caseValues(&x, clause.List, seen)
    532 			check.openScope(clause, "case")
    533 			inner := inner
    534 			if i+1 < len(s.Body.List) {
    535 				inner |= fallthroughOk
    536 			} else {
    537 				inner |= finalSwitchCase
    538 			}
    539 			check.stmtList(inner, clause.Body)
    540 			check.closeScope()
    541 		}
    542 
    543 	case *ast.TypeSwitchStmt:
    544 		inner |= breakOk
    545 		check.openScope(s, "type switch")
    546 		defer check.closeScope()
    547 
    548 		check.simpleStmt(s.Init)
    549 
    550 		// A type switch guard must be of the form:
    551 		//
    552 		//     TypeSwitchGuard = [ identifier ":=" ] PrimaryExpr "." "(" "type" ")" .
    553 		//
    554 		// The parser is checking syntactic correctness;
    555 		// remaining syntactic errors are considered AST errors here.
    556 		// TODO(gri) better factoring of error handling (invalid ASTs)
    557 		//
    558 		var lhs *ast.Ident // lhs identifier or nil
    559 		var rhs ast.Expr
    560 		switch guard := s.Assign.(type) {
    561 		case *ast.ExprStmt:
    562 			rhs = guard.X
    563 		case *ast.AssignStmt:
    564 			if len(guard.Lhs) != 1 || guard.Tok != token.DEFINE || len(guard.Rhs) != 1 {
    565 				check.invalidAST(s.Pos(), "incorrect form of type switch guard")
    566 				return
    567 			}
    568 
    569 			lhs, _ = guard.Lhs[0].(*ast.Ident)
    570 			if lhs == nil {
    571 				check.invalidAST(s.Pos(), "incorrect form of type switch guard")
    572 				return
    573 			}
    574 
    575 			if lhs.Name == "_" {
    576 				// _ := x.(type) is an invalid short variable declaration
    577 				check.softErrorf(lhs.Pos(), "no new variable on left side of :=")
    578 				lhs = nil // avoid declared but not used error below
    579 			} else {
    580 				check.recordDef(lhs, nil) // lhs variable is implicitly declared in each cause clause
    581 			}
    582 
    583 			rhs = guard.Rhs[0]
    584 
    585 		default:
    586 			check.invalidAST(s.Pos(), "incorrect form of type switch guard")
    587 			return
    588 		}
    589 
    590 		// rhs must be of the form: expr.(type) and expr must be an interface
    591 		expr, _ := rhs.(*ast.TypeAssertExpr)
    592 		if expr == nil || expr.Type != nil {
    593 			check.invalidAST(s.Pos(), "incorrect form of type switch guard")
    594 			return
    595 		}
    596 		var x operand
    597 		check.expr(&x, expr.X)
    598 		if x.mode == invalid {
    599 			return
    600 		}
    601 		xtyp, _ := x.typ.Underlying().(*Interface)
    602 		if xtyp == nil {
    603 			check.errorf(x.pos(), "%s is not an interface", &x)
    604 			return
    605 		}
    606 
    607 		check.multipleDefaults(s.Body.List)
    608 
    609 		var lhsVars []*Var               // list of implicitly declared lhs variables
    610 		seen := make(map[Type]token.Pos) // map of seen types to positions
    611 		for _, s := range s.Body.List {
    612 			clause, _ := s.(*ast.CaseClause)
    613 			if clause == nil {
    614 				check.invalidAST(s.Pos(), "incorrect type switch case")
    615 				continue
    616 			}
    617 			// Check each type in this type switch case.
    618 			T := check.caseTypes(&x, xtyp, clause.List, seen)
    619 			check.openScope(clause, "case")
    620 			// If lhs exists, declare a corresponding variable in the case-local scope.
    621 			if lhs != nil {
    622 				// spec: "The TypeSwitchGuard may include a short variable declaration.
    623 				// When that form is used, the variable is declared at the beginning of
    624 				// the implicit block in each clause. In clauses with a case listing
    625 				// exactly one type, the variable has that type; otherwise, the variable
    626 				// has the type of the expression in the TypeSwitchGuard."
    627 				if len(clause.List) != 1 || T == nil {
    628 					T = x.typ
    629 				}
    630 				obj := NewVar(lhs.Pos(), check.pkg, lhs.Name, T)
    631 				scopePos := clause.Pos() + token.Pos(len("default")) // for default clause (len(List) == 0)
    632 				if n := len(clause.List); n > 0 {
    633 					scopePos = clause.List[n-1].End()
    634 				}
    635 				check.declare(check.scope, nil, obj, scopePos)
    636 				check.recordImplicit(clause, obj)
    637 				// For the "declared but not used" error, all lhs variables act as
    638 				// one; i.e., if any one of them is 'used', all of them are 'used'.
    639 				// Collect them for later analysis.
    640 				lhsVars = append(lhsVars, obj)
    641 			}
    642 			check.stmtList(inner, clause.Body)
    643 			check.closeScope()
    644 		}
    645 
    646 		// If lhs exists, we must have at least one lhs variable that was used.
    647 		if lhs != nil {
    648 			var used bool
    649 			for _, v := range lhsVars {
    650 				if v.used {
    651 					used = true
    652 				}
    653 				v.used = true // avoid usage error when checking entire function
    654 			}
    655 			if !used {
    656 				check.softErrorf(lhs.Pos(), "%s declared but not used", lhs.Name)
    657 			}
    658 		}
    659 
    660 	case *ast.SelectStmt:
    661 		inner |= breakOk
    662 
    663 		check.multipleDefaults(s.Body.List)
    664 
    665 		for _, s := range s.Body.List {
    666 			clause, _ := s.(*ast.CommClause)
    667 			if clause == nil {
    668 				continue // error reported before
    669 			}
    670 
    671 			// clause.Comm must be a SendStmt, RecvStmt, or default case
    672 			valid := false
    673 			var rhs ast.Expr // rhs of RecvStmt, or nil
    674 			switch s := clause.Comm.(type) {
    675 			case nil, *ast.SendStmt:
    676 				valid = true
    677 			case *ast.AssignStmt:
    678 				if len(s.Rhs) == 1 {
    679 					rhs = s.Rhs[0]
    680 				}
    681 			case *ast.ExprStmt:
    682 				rhs = s.X
    683 			}
    684 
    685 			// if present, rhs must be a receive operation
    686 			if rhs != nil {
    687 				if x, _ := unparen(rhs).(*ast.UnaryExpr); x != nil && x.Op == token.ARROW {
    688 					valid = true
    689 				}
    690 			}
    691 
    692 			if !valid {
    693 				check.error(clause.Comm.Pos(), "select case must be send or receive (possibly with assignment)")
    694 				continue
    695 			}
    696 
    697 			check.openScope(s, "case")
    698 			if clause.Comm != nil {
    699 				check.stmt(inner, clause.Comm)
    700 			}
    701 			check.stmtList(inner, clause.Body)
    702 			check.closeScope()
    703 		}
    704 
    705 	case *ast.ForStmt:
    706 		inner |= breakOk | continueOk
    707 		check.openScope(s, "for")
    708 		defer check.closeScope()
    709 
    710 		check.simpleStmt(s.Init)
    711 		if s.Cond != nil {
    712 			var x operand
    713 			check.expr(&x, s.Cond)
    714 			if x.mode != invalid && !isBoolean(x.typ) {
    715 				check.error(s.Cond.Pos(), "non-boolean condition in for statement")
    716 			}
    717 		}
    718 		check.simpleStmt(s.Post)
    719 		// spec: "The init statement may be a short variable
    720 		// declaration, but the post statement must not."
    721 		if s, _ := s.Post.(*ast.AssignStmt); s != nil && s.Tok == token.DEFINE {
    722 			check.softErrorf(s.Pos(), "cannot declare in post statement")
    723 			check.use(s.Lhs...) // avoid follow-up errors
    724 		}
    725 		check.stmt(inner, s.Body)
    726 
    727 	case *ast.RangeStmt:
    728 		inner |= breakOk | continueOk
    729 		check.openScope(s, "for")
    730 		defer check.closeScope()
    731 
    732 		// check expression to iterate over
    733 		var x operand
    734 		check.expr(&x, s.X)
    735 
    736 		// determine key/value types
    737 		var key, val Type
    738 		if x.mode != invalid {
    739 			switch typ := x.typ.Underlying().(type) {
    740 			case *Basic:
    741 				if isString(typ) {
    742 					key = Typ[Int]
    743 					val = universeRune // use 'rune' name
    744 				}
    745 			case *Array:
    746 				key = Typ[Int]
    747 				val = typ.elem
    748 			case *Slice:
    749 				key = Typ[Int]
    750 				val = typ.elem
    751 			case *Pointer:
    752 				if typ, _ := typ.base.Underlying().(*Array); typ != nil {
    753 					key = Typ[Int]
    754 					val = typ.elem
    755 				}
    756 			case *Map:
    757 				key = typ.key
    758 				val = typ.elem
    759 			case *Chan:
    760 				key = typ.elem
    761 				val = Typ[Invalid]
    762 				if typ.dir == SendOnly {
    763 					check.errorf(x.pos(), "cannot range over send-only channel %s", &x)
    764 					// ok to continue
    765 				}
    766 				if s.Value != nil {
    767 					check.errorf(s.Value.Pos(), "iteration over %s permits only one iteration variable", &x)
    768 					// ok to continue
    769 				}
    770 			}
    771 		}
    772 
    773 		if key == nil {
    774 			check.errorf(x.pos(), "cannot range over %s", &x)
    775 			// ok to continue
    776 		}
    777 
    778 		// check assignment to/declaration of iteration variables
    779 		// (irregular assignment, cannot easily map to existing assignment checks)
    780 
    781 		// lhs expressions and initialization value (rhs) types
    782 		lhs := [2]ast.Expr{s.Key, s.Value}
    783 		rhs := [2]Type{key, val} // key, val may be nil
    784 
    785 		if s.Tok == token.DEFINE {
    786 			// short variable declaration; variable scope starts after the range clause
    787 			// (the for loop opens a new scope, so variables on the lhs never redeclare
    788 			// previously declared variables)
    789 			var vars []*Var
    790 			for i, lhs := range lhs {
    791 				if lhs == nil {
    792 					continue
    793 				}
    794 
    795 				// determine lhs variable
    796 				var obj *Var
    797 				if ident, _ := lhs.(*ast.Ident); ident != nil {
    798 					// declare new variable
    799 					name := ident.Name
    800 					obj = NewVar(ident.Pos(), check.pkg, name, nil)
    801 					check.recordDef(ident, obj)
    802 					// _ variables don't count as new variables
    803 					if name != "_" {
    804 						vars = append(vars, obj)
    805 					}
    806 				} else {
    807 					check.errorf(lhs.Pos(), "cannot declare %s", lhs)
    808 					obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable
    809 				}
    810 
    811 				// initialize lhs variable
    812 				if typ := rhs[i]; typ != nil {
    813 					x.mode = value
    814 					x.expr = lhs // we don't have a better rhs expression to use here
    815 					x.typ = typ
    816 					check.initVar(obj, &x, "range clause")
    817 				} else {
    818 					obj.typ = Typ[Invalid]
    819 					obj.used = true // don't complain about unused variable
    820 				}
    821 			}
    822 
    823 			// declare variables
    824 			if len(vars) > 0 {
    825 				scopePos := s.X.End()
    826 				for _, obj := range vars {
    827 					// spec: "The scope of a constant or variable identifier declared inside
    828 					// a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
    829 					// for short variable declarations) and ends at the end of the innermost
    830 					// containing block."
    831 					check.declare(check.scope, nil /* recordDef already called */, obj, scopePos)
    832 				}
    833 			} else {
    834 				check.error(s.TokPos, "no new variables on left side of :=")
    835 			}
    836 		} else {
    837 			// ordinary assignment
    838 			for i, lhs := range lhs {
    839 				if lhs == nil {
    840 					continue
    841 				}
    842 				if typ := rhs[i]; typ != nil {
    843 					x.mode = value
    844 					x.expr = lhs // we don't have a better rhs expression to use here
    845 					x.typ = typ
    846 					check.assignVar(lhs, &x)
    847 				}
    848 			}
    849 		}
    850 
    851 		check.stmt(inner, s.Body)
    852 
    853 	default:
    854 		check.error(s.Pos(), "invalid statement")
    855 	}
    856 }
    857