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