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