github.com/kdevb0x/go@v0.0.0-20180115030120-39687051e9e7/src/go/types/stmt.go (about) 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 check.use(s.Lhs...) // avoid follow-up errors 735 } 736 check.stmt(inner, s.Body) 737 738 case *ast.RangeStmt: 739 inner |= breakOk | continueOk 740 check.openScope(s, "for") 741 defer check.closeScope() 742 743 // check expression to iterate over 744 var x operand 745 check.expr(&x, s.X) 746 747 // determine key/value types 748 var key, val Type 749 if x.mode != invalid { 750 switch typ := x.typ.Underlying().(type) { 751 case *Basic: 752 if isString(typ) { 753 key = Typ[Int] 754 val = universeRune // use 'rune' name 755 } 756 case *Array: 757 key = Typ[Int] 758 val = typ.elem 759 case *Slice: 760 key = Typ[Int] 761 val = typ.elem 762 case *Pointer: 763 if typ, _ := typ.base.Underlying().(*Array); typ != nil { 764 key = Typ[Int] 765 val = typ.elem 766 } 767 case *Map: 768 key = typ.key 769 val = typ.elem 770 case *Chan: 771 key = typ.elem 772 val = Typ[Invalid] 773 if typ.dir == SendOnly { 774 check.errorf(x.pos(), "cannot range over send-only channel %s", &x) 775 // ok to continue 776 } 777 if s.Value != nil { 778 check.errorf(s.Value.Pos(), "iteration over %s permits only one iteration variable", &x) 779 // ok to continue 780 } 781 } 782 } 783 784 if key == nil { 785 check.errorf(x.pos(), "cannot range over %s", &x) 786 // ok to continue 787 } 788 789 // check assignment to/declaration of iteration variables 790 // (irregular assignment, cannot easily map to existing assignment checks) 791 792 // lhs expressions and initialization value (rhs) types 793 lhs := [2]ast.Expr{s.Key, s.Value} 794 rhs := [2]Type{key, val} // key, val may be nil 795 796 if s.Tok == token.DEFINE { 797 // short variable declaration; variable scope starts after the range clause 798 // (the for loop opens a new scope, so variables on the lhs never redeclare 799 // previously declared variables) 800 var vars []*Var 801 for i, lhs := range lhs { 802 if lhs == nil { 803 continue 804 } 805 806 // determine lhs variable 807 var obj *Var 808 if ident, _ := lhs.(*ast.Ident); ident != nil { 809 // declare new variable 810 name := ident.Name 811 obj = NewVar(ident.Pos(), check.pkg, name, nil) 812 check.recordDef(ident, obj) 813 // _ variables don't count as new variables 814 if name != "_" { 815 vars = append(vars, obj) 816 } 817 } else { 818 check.errorf(lhs.Pos(), "cannot declare %s", lhs) 819 obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable 820 } 821 822 // initialize lhs variable 823 if typ := rhs[i]; typ != nil { 824 x.mode = value 825 x.expr = lhs // we don't have a better rhs expression to use here 826 x.typ = typ 827 check.initVar(obj, &x, "range clause") 828 } else { 829 obj.typ = Typ[Invalid] 830 obj.used = true // don't complain about unused variable 831 } 832 } 833 834 // declare variables 835 if len(vars) > 0 { 836 scopePos := s.X.End() 837 for _, obj := range vars { 838 // spec: "The scope of a constant or variable identifier declared inside 839 // a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl 840 // for short variable declarations) and ends at the end of the innermost 841 // containing block." 842 check.declare(check.scope, nil /* recordDef already called */, obj, scopePos) 843 } 844 } else { 845 check.error(s.TokPos, "no new variables on left side of :=") 846 } 847 } else { 848 // ordinary assignment 849 for i, lhs := range lhs { 850 if lhs == nil { 851 continue 852 } 853 if typ := rhs[i]; typ != nil { 854 x.mode = value 855 x.expr = lhs // we don't have a better rhs expression to use here 856 x.typ = typ 857 check.assignVar(lhs, &x) 858 } 859 } 860 } 861 862 check.stmt(inner, s.Body) 863 864 default: 865 check.error(s.Pos(), "invalid statement") 866 } 867 }