github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/compile/types2/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 types2 8 9 import ( 10 "go/constant" 11 "sort" 12 13 "github.com/go-asm/go/buildcfg" 14 "github.com/go-asm/go/cmd/compile/syntax" 15 . "github.com/go-asm/go/types/errors" 16 ) 17 18 func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body *syntax.BlockStmt, iota constant.Value) { 19 if check.conf.IgnoreFuncBodies { 20 panic("function body not ignored") 21 } 22 23 if check.conf.Trace { 24 check.trace(body.Pos(), "-- %s: %s", name, sig) 25 } 26 27 // save/restore current environment and set up function environment 28 // (and use 0 indentation at function start) 29 defer func(env environment, indent int) { 30 check.environment = env 31 check.indent = indent 32 }(check.environment, check.indent) 33 check.environment = environment{ 34 decl: decl, 35 scope: sig.scope, 36 iota: iota, 37 sig: sig, 38 } 39 check.indent = 0 40 41 check.stmtList(0, body.List) 42 43 if check.hasLabel && !check.conf.IgnoreBranchErrors { 44 check.labels(body) 45 } 46 47 if sig.results.Len() > 0 && !check.isTerminating(body, "") { 48 check.error(body.Rbrace, MissingReturn, "missing return") 49 } 50 51 // spec: "Implementation restriction: A compiler may make it illegal to 52 // declare a variable inside a function body if the variable is never used." 53 check.usage(sig.scope) 54 } 55 56 func (check *Checker) usage(scope *Scope) { 57 var unused []*Var 58 for name, elem := range scope.elems { 59 elem = resolve(name, elem) 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 cmpPos(unused[i].pos, unused[j].pos) < 0 66 }) 67 for _, v := range unused { 68 check.softErrorf(v.pos, UnusedVar, "%s declared and 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 inTypeSwitch 95 ) 96 97 func (check *Checker) simpleStmt(s syntax.Stmt) { 98 if s != nil { 99 check.stmt(0, s) 100 } 101 } 102 103 func trimTrailingEmptyStmts(list []syntax.Stmt) []syntax.Stmt { 104 for i := len(list); i > 0; i-- { 105 if _, ok := list[i-1].(*syntax.EmptyStmt); !ok { 106 return list[:i] 107 } 108 } 109 return nil 110 } 111 112 func (check *Checker) stmtList(ctxt stmtContext, list []syntax.Stmt) { 113 ok := ctxt&fallthroughOk != 0 114 inner := ctxt &^ fallthroughOk 115 list = trimTrailingEmptyStmts(list) // trailing empty statements are "invisible" to fallthrough analysis 116 for i, s := range list { 117 inner := inner 118 if ok && i+1 == len(list) { 119 inner |= fallthroughOk 120 } 121 check.stmt(inner, s) 122 } 123 } 124 125 func (check *Checker) multipleSwitchDefaults(list []*syntax.CaseClause) { 126 var first *syntax.CaseClause 127 for _, c := range list { 128 if c.Cases == nil { 129 if first != nil { 130 check.errorf(c, DuplicateDefault, "multiple defaults (first at %s)", first.Pos()) 131 // TODO(gri) probably ok to bail out after first error (and simplify this code) 132 } else { 133 first = c 134 } 135 } 136 } 137 } 138 139 func (check *Checker) multipleSelectDefaults(list []*syntax.CommClause) { 140 var first *syntax.CommClause 141 for _, c := range list { 142 if c.Comm == nil { 143 if first != nil { 144 check.errorf(c, DuplicateDefault, "multiple defaults (first at %s)", first.Pos()) 145 // TODO(gri) probably ok to bail out after first error (and simplify this code) 146 } else { 147 first = c 148 } 149 } 150 } 151 } 152 153 func (check *Checker) openScope(node syntax.Node, comment string) { 154 check.openScopeUntil(node, syntax.EndPos(node), comment) 155 } 156 157 func (check *Checker) openScopeUntil(node syntax.Node, end syntax.Pos, comment string) { 158 scope := NewScope(check.scope, node.Pos(), end, comment) 159 check.recordScope(node, scope) 160 check.scope = scope 161 } 162 163 func (check *Checker) closeScope() { 164 check.scope = check.scope.Parent() 165 } 166 167 func (check *Checker) suspendedCall(keyword string, call syntax.Expr) { 168 code := InvalidDefer 169 if keyword == "go" { 170 code = InvalidGo 171 } 172 173 if _, ok := call.(*syntax.CallExpr); !ok { 174 check.errorf(call, code, "expression in %s must be function call", keyword) 175 check.use(call) 176 return 177 } 178 179 var x operand 180 var msg string 181 switch check.rawExpr(nil, &x, call, nil, false) { 182 case conversion: 183 msg = "requires function call, not conversion" 184 case expression: 185 msg = "discards result of" 186 code = UnusedResults 187 case statement: 188 return 189 default: 190 unreachable() 191 } 192 check.errorf(&x, code, "%s %s %s", keyword, msg, &x) 193 } 194 195 // goVal returns the Go value for val, or nil. 196 func goVal(val constant.Value) interface{} { 197 // val should exist, but be conservative and check 198 if val == nil { 199 return nil 200 } 201 // Match implementation restriction of other compilers. 202 // gc only checks duplicates for integer, floating-point 203 // and string values, so only create Go values for these 204 // types. 205 switch val.Kind() { 206 case constant.Int: 207 if x, ok := constant.Int64Val(val); ok { 208 return x 209 } 210 if x, ok := constant.Uint64Val(val); ok { 211 return x 212 } 213 case constant.Float: 214 if x, ok := constant.Float64Val(val); ok { 215 return x 216 } 217 case constant.String: 218 return constant.StringVal(val) 219 } 220 return nil 221 } 222 223 // A valueMap maps a case value (of a basic Go type) to a list of positions 224 // where the same case value appeared, together with the corresponding case 225 // types. 226 // Since two case values may have the same "underlying" value but different 227 // types we need to also check the value's types (e.g., byte(1) vs myByte(1)) 228 // when the switch expression is of interface type. 229 type ( 230 valueMap map[interface{}][]valueType // underlying Go value -> valueType 231 valueType struct { 232 pos syntax.Pos 233 typ Type 234 } 235 ) 236 237 func (check *Checker) caseValues(x *operand, values []syntax.Expr, seen valueMap) { 238 L: 239 for _, e := range values { 240 var v operand 241 check.expr(nil, &v, e) 242 if x.mode == invalid || v.mode == invalid { 243 continue L 244 } 245 check.convertUntyped(&v, x.typ) 246 if v.mode == invalid { 247 continue L 248 } 249 // Order matters: By comparing v against x, error positions are at the case values. 250 res := v // keep original v unchanged 251 check.comparison(&res, x, syntax.Eql, true) 252 if res.mode == invalid { 253 continue L 254 } 255 if v.mode != constant_ { 256 continue L // we're done 257 } 258 // look for duplicate values 259 if val := goVal(v.val); val != nil { 260 // look for duplicate types for a given value 261 // (quadratic algorithm, but these lists tend to be very short) 262 for _, vt := range seen[val] { 263 if Identical(v.typ, vt.typ) { 264 var err error_ 265 err.code = DuplicateCase 266 err.errorf(&v, "duplicate case %s in expression switch", &v) 267 err.errorf(vt.pos, "previous case") 268 check.report(&err) 269 continue L 270 } 271 } 272 seen[val] = append(seen[val], valueType{v.Pos(), v.typ}) 273 } 274 } 275 } 276 277 // isNil reports whether the expression e denotes the predeclared value nil. 278 func (check *Checker) isNil(e syntax.Expr) bool { 279 // The only way to express the nil value is by literally writing nil (possibly in parentheses). 280 if name, _ := syntax.Unparen(e).(*syntax.Name); name != nil { 281 _, ok := check.lookup(name.Value).(*Nil) 282 return ok 283 } 284 return false 285 } 286 287 // If the type switch expression is invalid, x is nil. 288 func (check *Checker) caseTypes(x *operand, types []syntax.Expr, seen map[Type]syntax.Expr) (T Type) { 289 var dummy operand 290 L: 291 for _, e := range types { 292 // The spec allows the value nil instead of a type. 293 if check.isNil(e) { 294 T = nil 295 check.expr(nil, &dummy, e) // run e through expr so we get the usual Info recordings 296 } else { 297 T = check.varType(e) 298 if !isValid(T) { 299 continue L 300 } 301 } 302 // look for duplicate types 303 // (quadratic algorithm, but type switches tend to be reasonably small) 304 for t, other := range seen { 305 if T == nil && t == nil || T != nil && t != nil && Identical(T, t) { 306 // talk about "case" rather than "type" because of nil case 307 Ts := "nil" 308 if T != nil { 309 Ts = TypeString(T, check.qualifier) 310 } 311 var err error_ 312 err.code = DuplicateCase 313 err.errorf(e, "duplicate case %s in type switch", Ts) 314 err.errorf(other, "previous case") 315 check.report(&err) 316 continue L 317 } 318 } 319 seen[T] = e 320 if x != nil && T != nil { 321 check.typeAssertion(e, x, T, true) 322 } 323 } 324 return 325 } 326 327 // TODO(gri) Once we are certain that typeHash is correct in all situations, use this version of caseTypes instead. 328 // (Currently it may be possible that different types have identical names and import paths due to ImporterFrom.) 329 // 330 // func (check *Checker) caseTypes(x *operand, xtyp *Interface, types []syntax.Expr, seen map[string]syntax.Expr) (T Type) { 331 // var dummy operand 332 // L: 333 // for _, e := range types { 334 // // The spec allows the value nil instead of a type. 335 // var hash string 336 // if check.isNil(e) { 337 // check.expr(nil, &dummy, e) // run e through expr so we get the usual Info recordings 338 // T = nil 339 // hash = "<nil>" // avoid collision with a type named nil 340 // } else { 341 // T = check.varType(e) 342 // if !isValid(T) { 343 // continue L 344 // } 345 // hash = typeHash(T, nil) 346 // } 347 // // look for duplicate types 348 // if other := seen[hash]; other != nil { 349 // // talk about "case" rather than "type" because of nil case 350 // Ts := "nil" 351 // if T != nil { 352 // Ts = TypeString(T, check.qualifier) 353 // } 354 // var err error_ 355 // err.code = _DuplicateCase 356 // err.errorf(e, "duplicate case %s in type switch", Ts) 357 // err.errorf(other, "previous case") 358 // check.report(&err) 359 // continue L 360 // } 361 // seen[hash] = e 362 // if T != nil { 363 // check.typeAssertion(e, x, xtyp, T, true) 364 // } 365 // } 366 // return 367 // } 368 369 // stmt typechecks statement s. 370 func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) { 371 // statements must end with the same top scope as they started with 372 if debug { 373 defer func(scope *Scope) { 374 // don't check if code is panicking 375 if p := recover(); p != nil { 376 panic(p) 377 } 378 assert(scope == check.scope) 379 }(check.scope) 380 } 381 382 // process collected function literals before scope changes 383 defer check.processDelayed(len(check.delayed)) 384 385 // reset context for statements of inner blocks 386 inner := ctxt &^ (fallthroughOk | finalSwitchCase | inTypeSwitch) 387 388 switch s := s.(type) { 389 case *syntax.EmptyStmt: 390 // ignore 391 392 case *syntax.DeclStmt: 393 check.declStmt(s.DeclList) 394 395 case *syntax.LabeledStmt: 396 check.hasLabel = true 397 check.stmt(ctxt, s.Stmt) 398 399 case *syntax.ExprStmt: 400 // spec: "With the exception of specific built-in functions, 401 // function and method calls and receive operations can appear 402 // in statement context. Such statements may be parenthesized." 403 var x operand 404 kind := check.rawExpr(nil, &x, s.X, nil, false) 405 var msg string 406 var code Code 407 switch x.mode { 408 default: 409 if kind == statement { 410 return 411 } 412 msg = "is not used" 413 code = UnusedExpr 414 case builtin: 415 msg = "must be called" 416 code = UncalledBuiltin 417 case typexpr: 418 msg = "is not an expression" 419 code = NotAnExpr 420 } 421 check.errorf(&x, code, "%s %s", &x, msg) 422 423 case *syntax.SendStmt: 424 var ch, val operand 425 check.expr(nil, &ch, s.Chan) 426 check.expr(nil, &val, s.Value) 427 if ch.mode == invalid || val.mode == invalid { 428 return 429 } 430 u := coreType(ch.typ) 431 if u == nil { 432 check.errorf(s, InvalidSend, invalidOp+"cannot send to %s: no core type", &ch) 433 return 434 } 435 uch, _ := u.(*Chan) 436 if uch == nil { 437 check.errorf(s, InvalidSend, invalidOp+"cannot send to non-channel %s", &ch) 438 return 439 } 440 if uch.dir == RecvOnly { 441 check.errorf(s, InvalidSend, invalidOp+"cannot send to receive-only channel %s", &ch) 442 return 443 } 444 check.assignment(&val, uch.elem, "send") 445 446 case *syntax.AssignStmt: 447 if s.Rhs == nil { 448 // x++ or x-- 449 // (no need to call unpackExpr as s.Lhs must be single-valued) 450 var x operand 451 check.expr(nil, &x, s.Lhs) 452 if x.mode == invalid { 453 return 454 } 455 if !allNumeric(x.typ) { 456 check.errorf(s.Lhs, NonNumericIncDec, invalidOp+"%s%s%s (non-numeric type %s)", s.Lhs, s.Op, s.Op, x.typ) 457 return 458 } 459 check.assignVar(s.Lhs, nil, &x, "assignment") 460 return 461 } 462 463 lhs := syntax.UnpackListExpr(s.Lhs) 464 rhs := syntax.UnpackListExpr(s.Rhs) 465 switch s.Op { 466 case 0: 467 check.assignVars(lhs, rhs) 468 return 469 case syntax.Def: 470 check.shortVarDecl(s.Pos(), lhs, rhs) 471 return 472 } 473 474 // assignment operations 475 if len(lhs) != 1 || len(rhs) != 1 { 476 check.errorf(s, MultiValAssignOp, "assignment operation %s requires single-valued expressions", s.Op) 477 return 478 } 479 480 var x operand 481 check.binary(&x, nil, lhs[0], rhs[0], s.Op) 482 check.assignVar(lhs[0], nil, &x, "assignment") 483 484 case *syntax.CallStmt: 485 kind := "go" 486 if s.Tok == syntax.Defer { 487 kind = "defer" 488 } 489 check.suspendedCall(kind, s.Call) 490 491 case *syntax.ReturnStmt: 492 res := check.sig.results 493 // Return with implicit results allowed for function with named results. 494 // (If one is named, all are named.) 495 results := syntax.UnpackListExpr(s.Results) 496 if len(results) == 0 && res.Len() > 0 && res.vars[0].name != "" { 497 // spec: "Implementation restriction: A compiler may disallow an empty expression 498 // list in a "return" statement if a different entity (constant, type, or variable) 499 // with the same name as a result parameter is in scope at the place of the return." 500 for _, obj := range res.vars { 501 if alt := check.lookup(obj.name); alt != nil && alt != obj { 502 var err error_ 503 err.code = OutOfScopeResult 504 err.errorf(s, "result parameter %s not in scope at return", obj.name) 505 err.errorf(alt, "inner declaration of %s", obj) 506 check.report(&err) 507 // ok to continue 508 } 509 } 510 } else { 511 var lhs []*Var 512 if res.Len() > 0 { 513 lhs = res.vars 514 } 515 check.initVars(lhs, results, s) 516 } 517 518 case *syntax.BranchStmt: 519 if s.Label != nil { 520 check.hasLabel = true 521 break // checked in 2nd pass (check.labels) 522 } 523 if check.conf.IgnoreBranchErrors { 524 break 525 } 526 switch s.Tok { 527 case syntax.Break: 528 if ctxt&breakOk == 0 { 529 check.error(s, MisplacedBreak, "break not in for, switch, or select statement") 530 } 531 case syntax.Continue: 532 if ctxt&continueOk == 0 { 533 check.error(s, MisplacedContinue, "continue not in for statement") 534 } 535 case syntax.Fallthrough: 536 if ctxt&fallthroughOk == 0 { 537 var msg string 538 switch { 539 case ctxt&finalSwitchCase != 0: 540 msg = "cannot fallthrough final case in switch" 541 case ctxt&inTypeSwitch != 0: 542 msg = "cannot fallthrough in type switch" 543 default: 544 msg = "fallthrough statement out of place" 545 } 546 check.error(s, MisplacedFallthrough, msg) 547 } 548 case syntax.Goto: 549 // goto's must have labels, should have been caught above 550 fallthrough 551 default: 552 check.errorf(s, InvalidSyntaxTree, "branch statement: %s", s.Tok) 553 } 554 555 case *syntax.BlockStmt: 556 check.openScope(s, "block") 557 defer check.closeScope() 558 559 check.stmtList(inner, s.List) 560 561 case *syntax.IfStmt: 562 check.openScope(s, "if") 563 defer check.closeScope() 564 565 check.simpleStmt(s.Init) 566 var x operand 567 check.expr(nil, &x, s.Cond) 568 if x.mode != invalid && !allBoolean(x.typ) { 569 check.error(s.Cond, InvalidCond, "non-boolean condition in if statement") 570 } 571 check.stmt(inner, s.Then) 572 // The parser produces a correct AST but if it was modified 573 // elsewhere the else branch may be invalid. Check again. 574 switch s.Else.(type) { 575 case nil: 576 // valid or error already reported 577 case *syntax.IfStmt, *syntax.BlockStmt: 578 check.stmt(inner, s.Else) 579 default: 580 check.error(s.Else, InvalidSyntaxTree, "invalid else branch in if statement") 581 } 582 583 case *syntax.SwitchStmt: 584 inner |= breakOk 585 check.openScope(s, "switch") 586 defer check.closeScope() 587 588 check.simpleStmt(s.Init) 589 590 if g, _ := s.Tag.(*syntax.TypeSwitchGuard); g != nil { 591 check.typeSwitchStmt(inner|inTypeSwitch, s, g) 592 } else { 593 check.switchStmt(inner, s) 594 } 595 596 case *syntax.SelectStmt: 597 inner |= breakOk 598 599 check.multipleSelectDefaults(s.Body) 600 601 for i, clause := range s.Body { 602 if clause == nil { 603 continue // error reported before 604 } 605 606 // clause.Comm must be a SendStmt, RecvStmt, or default case 607 valid := false 608 var rhs syntax.Expr // rhs of RecvStmt, or nil 609 switch s := clause.Comm.(type) { 610 case nil, *syntax.SendStmt: 611 valid = true 612 case *syntax.AssignStmt: 613 if _, ok := s.Rhs.(*syntax.ListExpr); !ok { 614 rhs = s.Rhs 615 } 616 case *syntax.ExprStmt: 617 rhs = s.X 618 } 619 620 // if present, rhs must be a receive operation 621 if rhs != nil { 622 if x, _ := syntax.Unparen(rhs).(*syntax.Operation); x != nil && x.Y == nil && x.Op == syntax.Recv { 623 valid = true 624 } 625 } 626 627 if !valid { 628 check.error(clause.Comm, InvalidSelectCase, "select case must be send or receive (possibly with assignment)") 629 continue 630 } 631 end := s.Rbrace 632 if i+1 < len(s.Body) { 633 end = s.Body[i+1].Pos() 634 } 635 check.openScopeUntil(clause, end, "case") 636 if clause.Comm != nil { 637 check.stmt(inner, clause.Comm) 638 } 639 check.stmtList(inner, clause.Body) 640 check.closeScope() 641 } 642 643 case *syntax.ForStmt: 644 inner |= breakOk | continueOk 645 646 if rclause, _ := s.Init.(*syntax.RangeClause); rclause != nil { 647 check.rangeStmt(inner, s, rclause) 648 break 649 } 650 651 check.openScope(s, "for") 652 defer check.closeScope() 653 654 check.simpleStmt(s.Init) 655 if s.Cond != nil { 656 var x operand 657 check.expr(nil, &x, s.Cond) 658 if x.mode != invalid && !allBoolean(x.typ) { 659 check.error(s.Cond, InvalidCond, "non-boolean condition in for statement") 660 } 661 } 662 check.simpleStmt(s.Post) 663 // spec: "The init statement may be a short variable 664 // declaration, but the post statement must not." 665 if s, _ := s.Post.(*syntax.AssignStmt); s != nil && s.Op == syntax.Def { 666 // The parser already reported an error. 667 check.use(s.Lhs) // avoid follow-up errors 668 } 669 check.stmt(inner, s.Body) 670 671 default: 672 check.error(s, InvalidSyntaxTree, "invalid statement") 673 } 674 } 675 676 func (check *Checker) switchStmt(inner stmtContext, s *syntax.SwitchStmt) { 677 // init statement already handled 678 679 var x operand 680 if s.Tag != nil { 681 check.expr(nil, &x, s.Tag) 682 // By checking assignment of x to an invisible temporary 683 // (as a compiler would), we get all the relevant checks. 684 check.assignment(&x, nil, "switch expression") 685 if x.mode != invalid && !Comparable(x.typ) && !hasNil(x.typ) { 686 check.errorf(&x, InvalidExprSwitch, "cannot switch on %s (%s is not comparable)", &x, x.typ) 687 x.mode = invalid 688 } 689 } else { 690 // spec: "A missing switch expression is 691 // equivalent to the boolean value true." 692 x.mode = constant_ 693 x.typ = Typ[Bool] 694 x.val = constant.MakeBool(true) 695 // TODO(gri) should have a better position here 696 pos := s.Rbrace 697 if len(s.Body) > 0 { 698 pos = s.Body[0].Pos() 699 } 700 x.expr = syntax.NewName(pos, "true") 701 } 702 703 check.multipleSwitchDefaults(s.Body) 704 705 seen := make(valueMap) // map of seen case values to positions and types 706 for i, clause := range s.Body { 707 if clause == nil { 708 check.error(clause, InvalidSyntaxTree, "incorrect expression switch case") 709 continue 710 } 711 end := s.Rbrace 712 inner := inner 713 if i+1 < len(s.Body) { 714 end = s.Body[i+1].Pos() 715 inner |= fallthroughOk 716 } else { 717 inner |= finalSwitchCase 718 } 719 check.caseValues(&x, syntax.UnpackListExpr(clause.Cases), seen) 720 check.openScopeUntil(clause, end, "case") 721 check.stmtList(inner, clause.Body) 722 check.closeScope() 723 } 724 } 725 726 func (check *Checker) typeSwitchStmt(inner stmtContext, s *syntax.SwitchStmt, guard *syntax.TypeSwitchGuard) { 727 // init statement already handled 728 729 // A type switch guard must be of the form: 730 // 731 // TypeSwitchGuard = [ identifier ":=" ] PrimaryExpr "." "(" "type" ")" . 732 // \__lhs__/ \___rhs___/ 733 734 // check lhs, if any 735 lhs := guard.Lhs 736 if lhs != nil { 737 if lhs.Value == "_" { 738 // _ := x.(type) is an invalid short variable declaration 739 check.softErrorf(lhs, NoNewVar, "no new variable on left side of :=") 740 lhs = nil // avoid declared and not used error below 741 } else { 742 check.recordDef(lhs, nil) // lhs variable is implicitly declared in each cause clause 743 } 744 } 745 746 // check rhs 747 var x operand 748 check.expr(nil, &x, guard.X) 749 if x.mode == invalid { 750 return 751 } 752 753 // TODO(gri) we may want to permit type switches on type parameter values at some point 754 var sx *operand // switch expression against which cases are compared against; nil if invalid 755 if isTypeParam(x.typ) { 756 check.errorf(&x, InvalidTypeSwitch, "cannot use type switch on type parameter value %s", &x) 757 } else { 758 if _, ok := under(x.typ).(*Interface); ok { 759 sx = &x 760 } else { 761 check.errorf(&x, InvalidTypeSwitch, "%s is not an interface", &x) 762 } 763 } 764 765 check.multipleSwitchDefaults(s.Body) 766 767 var lhsVars []*Var // list of implicitly declared lhs variables 768 seen := make(map[Type]syntax.Expr) // map of seen types to positions 769 for i, clause := range s.Body { 770 if clause == nil { 771 check.error(s, InvalidSyntaxTree, "incorrect type switch case") 772 continue 773 } 774 end := s.Rbrace 775 if i+1 < len(s.Body) { 776 end = s.Body[i+1].Pos() 777 } 778 // Check each type in this type switch case. 779 cases := syntax.UnpackListExpr(clause.Cases) 780 T := check.caseTypes(sx, cases, seen) 781 check.openScopeUntil(clause, end, "case") 782 // If lhs exists, declare a corresponding variable in the case-local scope. 783 if lhs != nil { 784 // spec: "The TypeSwitchGuard may include a short variable declaration. 785 // When that form is used, the variable is declared at the beginning of 786 // the implicit block in each clause. In clauses with a case listing 787 // exactly one type, the variable has that type; otherwise, the variable 788 // has the type of the expression in the TypeSwitchGuard." 789 if len(cases) != 1 || T == nil { 790 T = x.typ 791 } 792 obj := NewVar(lhs.Pos(), check.pkg, lhs.Value, T) 793 // TODO(mdempsky): Just use clause.Colon? Why did I even suggest 794 // "at the end of the TypeSwitchCase" in go.dev/issue/16794 instead? 795 scopePos := clause.Pos() // for default clause (len(List) == 0) 796 if n := len(cases); n > 0 { 797 scopePos = syntax.EndPos(cases[n-1]) 798 } 799 check.declare(check.scope, nil, obj, scopePos) 800 check.recordImplicit(clause, obj) 801 // For the "declared and not used" error, all lhs variables act as 802 // one; i.e., if any one of them is 'used', all of them are 'used'. 803 // Collect them for later analysis. 804 lhsVars = append(lhsVars, obj) 805 } 806 check.stmtList(inner, clause.Body) 807 check.closeScope() 808 } 809 810 // If lhs exists, we must have at least one lhs variable that was used. 811 // (We can't use check.usage because that only looks at one scope; and 812 // we don't want to use the same variable for all scopes and change the 813 // variable type underfoot.) 814 if lhs != nil { 815 var used bool 816 for _, v := range lhsVars { 817 if v.used { 818 used = true 819 } 820 v.used = true // avoid usage error when checking entire function 821 } 822 if !used { 823 check.softErrorf(lhs, UnusedVar, "%s declared and not used", lhs.Value) 824 } 825 } 826 } 827 828 func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *syntax.RangeClause) { 829 // Convert syntax form to local variables. 830 type Expr = syntax.Expr 831 type identType = syntax.Name 832 identName := func(n *identType) string { return n.Value } 833 sKey := rclause.Lhs // possibly nil 834 var sValue, sExtra syntax.Expr 835 if p, _ := sKey.(*syntax.ListExpr); p != nil { 836 if len(p.ElemList) < 2 { 837 check.error(s, InvalidSyntaxTree, "invalid lhs in range clause") 838 return 839 } 840 // len(p.ElemList) >= 2 841 sKey = p.ElemList[0] 842 sValue = p.ElemList[1] 843 if len(p.ElemList) > 2 { 844 // delay error reporting until we know more 845 sExtra = p.ElemList[2] 846 } 847 } 848 isDef := rclause.Def 849 rangeVar := rclause.X 850 noNewVarPos := s 851 852 // Do not use rclause anymore. 853 rclause = nil 854 855 // Everything from here on is shared between github.com/go-asm/go/cmd/compile/types2 and go/types. 856 857 // check expression to iterate over 858 var x operand 859 check.expr(nil, &x, rangeVar) 860 861 // determine key/value types 862 var key, val Type 863 if x.mode != invalid { 864 // Ranging over a type parameter is permitted if it has a core type. 865 k, v, cause, isFunc, ok := rangeKeyVal(x.typ, func(v goVersion) bool { 866 return check.allowVersion(check.pkg, x.expr, v) 867 }) 868 switch { 869 case !ok && cause != "": 870 check.softErrorf(&x, InvalidRangeExpr, "cannot range over %s: %s", &x, cause) 871 case !ok: 872 check.softErrorf(&x, InvalidRangeExpr, "cannot range over %s", &x) 873 case k == nil && sKey != nil: 874 check.softErrorf(sKey, InvalidIterVar, "range over %s permits no iteration variables", &x) 875 case v == nil && sValue != nil: 876 check.softErrorf(sValue, InvalidIterVar, "range over %s permits only one iteration variable", &x) 877 case sExtra != nil: 878 check.softErrorf(sExtra, InvalidIterVar, "range clause permits at most two iteration variables") 879 case isFunc && ((k == nil) != (sKey == nil) || (v == nil) != (sValue == nil)): 880 var count string 881 switch { 882 case k == nil: 883 count = "no iteration variables" 884 case v == nil: 885 count = "one iteration variable" 886 default: 887 count = "two iteration variables" 888 } 889 check.softErrorf(&x, InvalidIterVar, "range over %s must have %s", &x, count) 890 } 891 key, val = k, v 892 } 893 894 // Open the for-statement block scope now, after the range clause. 895 // Iteration variables declared with := need to go in this scope (was go.dev/issue/51437). 896 check.openScope(s, "range") 897 defer check.closeScope() 898 899 // check assignment to/declaration of iteration variables 900 // (irregular assignment, cannot easily map to existing assignment checks) 901 902 // lhs expressions and initialization value (rhs) types 903 lhs := [2]Expr{sKey, sValue} // sKey, sValue may be nil 904 rhs := [2]Type{key, val} // key, val may be nil 905 906 constIntRange := x.mode == constant_ && isInteger(x.typ) 907 908 if isDef { 909 // short variable declaration 910 var vars []*Var 911 for i, lhs := range lhs { 912 if lhs == nil { 913 continue 914 } 915 916 // determine lhs variable 917 var obj *Var 918 if ident, _ := lhs.(*identType); ident != nil { 919 // declare new variable 920 name := identName(ident) 921 obj = NewVar(ident.Pos(), check.pkg, name, nil) 922 check.recordDef(ident, obj) 923 // _ variables don't count as new variables 924 if name != "_" { 925 vars = append(vars, obj) 926 } 927 } else { 928 check.errorf(lhs, InvalidSyntaxTree, "cannot declare %s", lhs) 929 obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable 930 } 931 932 // initialize lhs variable 933 if constIntRange { 934 check.initVar(obj, &x, "range clause") 935 } else if typ := rhs[i]; typ != nil { 936 x.mode = value 937 x.expr = lhs // we don't have a better rhs expression to use here 938 x.typ = typ 939 check.initVar(obj, &x, "assignment") // error is on variable, use "assignment" not "range clause" 940 } else { 941 obj.typ = Typ[Invalid] 942 obj.used = true // don't complain about unused variable 943 } 944 } 945 946 // declare variables 947 if len(vars) > 0 { 948 scopePos := s.Body.Pos() 949 for _, obj := range vars { 950 check.declare(check.scope, nil /* recordDef already called */, obj, scopePos) 951 } 952 } else { 953 check.error(noNewVarPos, NoNewVar, "no new variables on left side of :=") 954 } 955 } else if sKey != nil /* lhs[0] != nil */ { 956 // ordinary assignment 957 for i, lhs := range lhs { 958 if lhs == nil { 959 continue 960 } 961 962 if constIntRange { 963 check.assignVar(lhs, nil, &x, "range clause") 964 } else if typ := rhs[i]; typ != nil { 965 x.mode = value 966 x.expr = lhs // we don't have a better rhs expression to use here 967 x.typ = typ 968 check.assignVar(lhs, nil, &x, "assignment") // error is on variable, use "assignment" not "range clause" 969 } 970 } 971 } else if constIntRange { 972 // If we don't have any iteration variables, we still need to 973 // check that a (possibly untyped) integer range expression x 974 // is valid. 975 // We do this by checking the assignment _ = x. This ensures 976 // that an untyped x can be converted to a value of type int. 977 check.assignment(&x, nil, "range clause") 978 } 979 980 check.stmt(inner, s.Body) 981 } 982 983 // RangeKeyVal returns the key and value types for a range over typ. 984 // Exported for use by the compiler (does not exist in go/types). 985 func RangeKeyVal(typ Type) (Type, Type) { 986 key, val, _, _, _ := rangeKeyVal(typ, nil) 987 return key, val 988 } 989 990 // rangeKeyVal returns the key and value type produced by a range clause 991 // over an expression of type typ. 992 // If allowVersion != nil, it is used to check the required language version. 993 // If the range clause is not permitted, rangeKeyVal returns ok = false. 994 // When ok = false, rangeKeyVal may also return a reason in cause. 995 func rangeKeyVal(typ Type, allowVersion func(goVersion) bool) (key, val Type, cause string, isFunc, ok bool) { 996 bad := func(cause string) (Type, Type, string, bool, bool) { 997 return Typ[Invalid], Typ[Invalid], cause, false, false 998 } 999 toSig := func(t Type) *Signature { 1000 sig, _ := coreType(t).(*Signature) 1001 return sig 1002 } 1003 1004 orig := typ 1005 switch typ := arrayPtrDeref(coreType(typ)).(type) { 1006 case nil: 1007 return bad("no core type") 1008 case *Basic: 1009 if isString(typ) { 1010 return Typ[Int], universeRune, "", false, true // use 'rune' name 1011 } 1012 if isInteger(typ) { 1013 if allowVersion != nil && !allowVersion(go1_22) { 1014 return bad("requires go1.22 or later") 1015 } 1016 return orig, nil, "", false, true 1017 } 1018 case *Array: 1019 return Typ[Int], typ.elem, "", false, true 1020 case *Slice: 1021 return Typ[Int], typ.elem, "", false, true 1022 case *Map: 1023 return typ.key, typ.elem, "", false, true 1024 case *Chan: 1025 if typ.dir == SendOnly { 1026 return bad("receive from send-only channel") 1027 } 1028 return typ.elem, nil, "", false, true 1029 case *Signature: 1030 // TODO(gri) when this becomes enabled permanently, add version check 1031 if !buildcfg.Experiment.RangeFunc { 1032 break 1033 } 1034 assert(typ.Recv() == nil) 1035 switch { 1036 case typ.Params().Len() != 1: 1037 return bad("func must be func(yield func(...) bool): wrong argument count") 1038 case toSig(typ.Params().At(0).Type()) == nil: 1039 return bad("func must be func(yield func(...) bool): argument is not func") 1040 case typ.Results().Len() != 0: 1041 return bad("func must be func(yield func(...) bool): unexpected results") 1042 } 1043 cb := toSig(typ.Params().At(0).Type()) 1044 assert(cb.Recv() == nil) 1045 switch { 1046 case cb.Params().Len() > 2: 1047 return bad("func must be func(yield func(...) bool): yield func has too many parameters") 1048 case cb.Results().Len() != 1 || !isBoolean(cb.Results().At(0).Type()): 1049 return bad("func must be func(yield func(...) bool): yield func does not return bool") 1050 } 1051 if cb.Params().Len() >= 1 { 1052 key = cb.Params().At(0).Type() 1053 } 1054 if cb.Params().Len() >= 2 { 1055 val = cb.Params().At(1).Type() 1056 } 1057 return key, val, "", true, true 1058 } 1059 return 1060 }