Source file src/cmd/compile/internal/rangefunc/rewrite.go
1 // Copyright 2023 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 /* 6 Package rangefunc rewrites range-over-func to code that doesn't use range-over-funcs. 7 Rewriting the construct in the front end, before noder, means the functions generated during 8 the rewrite are available in a noder-generated representation for inlining by the back end. 9 10 # Theory of Operation 11 12 The basic idea is to rewrite 13 14 for x := range f { 15 ... 16 } 17 18 into 19 20 f(func(x T) bool { 21 ... 22 }) 23 24 But it's not usually that easy. 25 26 # Range variables 27 28 For a range not using :=, the assigned variables cannot be function parameters 29 in the generated body function. Instead, we allocate fake parameters and 30 start the body with an assignment. For example: 31 32 for expr1, expr2 = range f { 33 ... 34 } 35 36 becomes 37 38 f(func(#p1 T1, #p2 T2) bool { 39 expr1, expr2 = #p1, #p2 40 ... 41 }) 42 43 (All the generated variables have a # at the start to signal that they 44 are internal variables when looking at the generated code in a 45 debugger. Because variables have all been resolved to the specific 46 objects they represent, there is no danger of using plain "p1" and 47 colliding with a Go variable named "p1"; the # is just nice to have, 48 not for correctness.) 49 50 It can also happen that there are fewer range variables than function 51 arguments, in which case we end up with something like 52 53 f(func(x T1, _ T2) bool { 54 ... 55 }) 56 57 or 58 59 f(func(#p1 T1, #p2 T2, _ T3) bool { 60 expr1, expr2 = #p1, #p2 61 ... 62 }) 63 64 # Return 65 66 If the body contains a "break", that break turns into "return false", 67 to tell f to stop. And if the body contains a "continue", that turns 68 into "return true", to tell f to proceed with the next value. 69 Those are the easy cases. 70 71 If the body contains a return or a break/continue/goto L, then we need 72 to rewrite that into code that breaks out of the loop and then 73 triggers that control flow. In general we rewrite 74 75 for x := range f { 76 ... 77 } 78 79 into 80 81 { 82 var #next int 83 f(func(x T1) bool { 84 ... 85 return true 86 }) 87 ... check #next ... 88 } 89 90 The variable #next is an integer code that says what to do when f 91 returns. Each difficult statement sets #next and then returns false to 92 stop f. 93 94 A plain "return" rewrites to {#next = -1; return false}. 95 The return false breaks the loop. Then when f returns, the "check 96 #next" section includes 97 98 if #next == -1 { return } 99 100 which causes the return we want. 101 102 Return with arguments is more involved, and has to deal with 103 corner cases involving panic, defer, and recover. The results 104 of the enclosing function or closure are rewritten to give them 105 names if they don't have them already, and the names are assigned 106 at the return site. 107 108 func foo() (#rv1 A, #rv2 B) { 109 110 { 111 var ( 112 #next int 113 ) 114 f(func(x T1) bool { 115 ... 116 { 117 // return a, b 118 #rv1, #rv2 = a, b 119 #next = -1 120 return false 121 } 122 ... 123 return true 124 }) 125 if #next == -1 { return } 126 } 127 128 # Checking 129 130 To permit checking that an iterator is well-behaved -- that is, that 131 it does not call the loop body again after it has returned false or 132 after the entire loop has exited (it might retain a copy of the body 133 function, or pass it to another goroutine) -- each generated loop has 134 its own #stateK variable that is used to check for permitted call 135 patterns to the yield function for a loop body. 136 137 The state values are: 138 139 abi.RF_DONE = 0 // body of loop has exited in a non-panic way 140 abi.RF_READY = 1 // body of loop has not exited yet, is not running 141 abi.RF_PANIC = 2 // body of loop is either currently running, or has panicked 142 abi.RF_EXHAUSTED = 3 // iterator function call, e.g. f(func(x t){...}), returned so the sequence is "exhausted". 143 144 abi.RF_MISSING_PANIC = 4 // used to report errors. 145 146 The value of #stateK transitions 147 (1) before calling the iterator function, 148 149 var #stateN = abi.RF_READY 150 151 (2) after the iterator function call returns, 152 153 if #stateN == abi.RF_PANIC { 154 panic(runtime.panicrangestate(abi.RF_MISSING_PANIC)) 155 } 156 #stateN = abi.RF_EXHAUSTED 157 158 (3) at the beginning of the iteration of the loop body, 159 160 if #stateN != abi.RF_READY { #stateN = abi.RF_PANIC ; runtime.panicrangestate(#stateN) } 161 #stateN = abi.RF_PANIC 162 // This is slightly rearranged below for better code generation. 163 164 (4) when loop iteration continues, 165 166 #stateN = abi.RF_READY 167 [return true] 168 169 (5) when control flow exits the loop body. 170 171 #stateN = abi.RF_DONE 172 [return false] 173 174 For example: 175 176 for x := range f { 177 ... 178 if ... { break } 179 ... 180 } 181 182 becomes 183 184 { 185 var #state1 = abi.RF_READY 186 f(func(x T1) bool { 187 if #state1 != abi.RF_READY { #state1 = abi.RF_PANIC; runtime.panicrangestate(#state1) } 188 #state1 = abi.RF_PANIC 189 ... 190 if ... { #state1 = abi.RF_DONE ; return false } 191 ... 192 #state1 = abi.RF_READY 193 return true 194 }) 195 if #state1 == abi.RF_PANIC { 196 // the code for the loop body did not return normally 197 panic(runtime.panicrangestate(abi.RF_MISSING_PANIC)) 198 } 199 #state1 = abi.RF_EXHAUSTED 200 } 201 202 # Nested Loops 203 204 So far we've only considered a single loop. If a function contains a 205 sequence of loops, each can be translated individually. But loops can 206 be nested. It would work to translate the innermost loop and then 207 translate the loop around it, and so on, except that there'd be a lot 208 of rewriting of rewritten code and the overall traversals could end up 209 taking time quadratic in the depth of the nesting. To avoid all that, 210 we use a single rewriting pass that handles a top-most range-over-func 211 loop and all the range-over-func loops it contains at the same time. 212 213 If we need to return from inside a doubly-nested loop, the rewrites 214 above stay the same, but the check after the inner loop only says 215 216 if #next < 0 { return false } 217 218 to stop the outer loop so it can do the actual return. That is, 219 220 for range f { 221 for range g { 222 ... 223 return a, b 224 ... 225 } 226 } 227 228 becomes 229 230 { 231 var ( 232 #next int 233 ) 234 var #state1 = abi.RF_READY 235 f(func() bool { 236 if #state1 != abi.RF_READY { #state1 = abi.RF_PANIC; runtime.panicrangestate(#state1) } 237 #state1 = abi.RF_PANIC 238 var #state2 = abi.RF_READY 239 g(func() bool { 240 if #state2 != abi.RF_READY { #state2 = abi.RF_PANIC; runtime.panicrangestate(#state2) } 241 ... 242 { 243 // return a, b 244 #rv1, #rv2 = a, b 245 #next = -1 246 #state2 = abi.RF_DONE 247 return false 248 } 249 ... 250 #state2 = abi.RF_READY 251 return true 252 }) 253 if #state2 == abi.RF_PANIC { 254 panic(runtime.panicrangestate(abi.RF_MISSING_PANIC)) 255 } 256 #state2 = abi.RF_EXHAUSTED 257 if #next < 0 { 258 #state1 = abi.RF_DONE 259 return false 260 } 261 #state1 = abi.RF_READY 262 return true 263 }) 264 if #state1 == abi.RF_PANIC { 265 panic(runtime.panicrangestate(abi.RF_MISSING_PANIC)) 266 } 267 #state1 = abi.RF_EXHAUSTED 268 if #next == -1 { 269 return 270 } 271 } 272 273 # Labeled break/continue of range-over-func loops 274 275 For a labeled break or continue of an outer range-over-func, we 276 use positive #next values. 277 278 Any such labeled break or continue 279 really means "do N breaks" or "do N breaks and 1 continue". 280 281 The positive #next value tells which level of loop N to target 282 with a break or continue, where perLoopStep*N means break out of 283 level N and perLoopStep*N-1 means continue into level N. The 284 outermost loop has level 1, therefore #next == perLoopStep means 285 to break from the outermost loop, and #next == perLoopStep-1 means 286 to continue the outermost loop. 287 288 Loops that might need to propagate a labeled break or continue 289 add one or both of these to the #next checks: 290 291 // N == depth of this loop, one less than the one just exited. 292 if #next != 0 { 293 if #next >= perLoopStep*N-1 { // break or continue this loop 294 if #next >= perLoopStep*N+1 { // error checking 295 // TODO reason about what exactly can appear 296 // here given full or partial checking. 297 runtime.panicrangestate(abi.RF_DONE) 298 } 299 rv := #next & 1 == 1 // code generates into #next&1 300 #next = 0 301 return rv 302 } 303 return false // or handle returns and gotos 304 } 305 306 For example (with perLoopStep == 2) 307 308 F: for range f { // 1, 2 309 for range g { // 3, 4 310 for range h { 311 ... 312 break F 313 ... 314 ... 315 continue F 316 ... 317 } 318 } 319 ... 320 } 321 322 becomes 323 324 { 325 var #next int 326 var #state1 = abi.RF_READY 327 f(func() { // 1,2 328 if #state1 != abi.RF_READY { #state1 = abi.RF_PANIC; runtime.panicrangestate(#state1) } 329 #state1 = abi.RF_PANIC 330 var #state2 = abi.RF_READY 331 g(func() { // 3,4 332 if #state2 != abi.RF_READY { #state2 = abi.RF_PANIC; runtime.panicrangestate(#state2) } 333 #state2 = abi.RF_PANIC 334 var #state3 = abi.RF_READY 335 h(func() { // 5,6 336 if #state3 != abi.RF_READY { #state3 = abi.RF_PANIC; runtime.panicrangestate(#state3) } 337 #state3 = abi.RF_PANIC 338 ... 339 { 340 // break F 341 #next = 2 342 #state3 = abi.RF_DONE 343 return false 344 } 345 ... 346 { 347 // continue F 348 #next = 1 349 #state3 = abi.RF_DONE 350 return false 351 } 352 ... 353 #state3 = abi.RF_READY 354 return true 355 }) 356 if #state3 == abi.RF_PANIC { 357 panic(runtime.panicrangestate(abi.RF_MISSING_PANIC)) 358 } 359 #state3 = abi.RF_EXHAUSTED 360 if #next != 0 { 361 // no breaks or continues targeting this loop 362 #state2 = abi.RF_DONE 363 return false 364 } 365 return true 366 }) 367 if #state2 == abi.RF_PANIC { 368 panic(runtime.panicrangestate(abi.RF_MISSING_PANIC)) 369 } 370 #state2 = abi.RF_EXHAUSTED 371 if #next != 0 { // just exited g, test for break/continue applied to f/F 372 if #next >= 1 { 373 if #next >= 3 { runtime.panicrangestate(abi.RF_DONE) } // error 374 rv := #next&1 == 1 375 #next = 0 376 return rv 377 } 378 #state1 = abi.RF_DONE 379 return false 380 } 381 ... 382 return true 383 }) 384 if #state1 == abi.RF_PANIC { 385 panic(runtime.panicrangestate(abi.RF_MISSING_PANIC)) 386 } 387 #state1 = abi.RF_EXHAUSTED 388 } 389 390 Note that the post-h checks only consider a break, 391 since no generated code tries to continue g. 392 393 # Gotos and other labeled break/continue 394 395 The final control flow translations are goto and break/continue of a 396 non-range-over-func statement. In both cases, we may need to break 397 out of one or more range-over-func loops before we can do the actual 398 control flow statement. Each such break/continue/goto L statement is 399 assigned a unique negative #next value (since -1 is return). Then 400 the post-checks for a given loop test for the specific codes that 401 refer to labels directly targetable from that block. Otherwise, the 402 generic 403 404 if #next < 0 { return false } 405 406 check handles stopping the next loop to get one step closer to the label. 407 408 For example 409 410 Top: print("start\n") 411 for range f { 412 for range g { 413 ... 414 for range h { 415 ... 416 goto Top 417 ... 418 } 419 } 420 } 421 422 becomes 423 424 Top: print("start\n") 425 { 426 var #next int 427 var #state1 = abi.RF_READY 428 f(func() { 429 if #state1 != abi.RF_READY{ #state1 = abi.RF_PANIC; runtime.panicrangestate(#state1) } 430 #state1 = abi.RF_PANIC 431 var #state2 = abi.RF_READY 432 g(func() { 433 if #state2 != abi.RF_READY { #state2 = abi.RF_PANIC; runtime.panicrangestate(#state2) } 434 #state2 = abi.RF_PANIC 435 ... 436 var #state3 bool = abi.RF_READY 437 h(func() { 438 if #state3 != abi.RF_READY { #state3 = abi.RF_PANIC; runtime.panicrangestate(#state3) } 439 #state3 = abi.RF_PANIC 440 ... 441 { 442 // goto Top 443 #next = -3 444 #state3 = abi.RF_DONE 445 return false 446 } 447 ... 448 #state3 = abi.RF_READY 449 return true 450 }) 451 if #state3 == abi.RF_PANIC {runtime.panicrangestate(abi.RF_MISSING_PANIC)} 452 #state3 = abi.RF_EXHAUSTED 453 if #next < 0 { 454 #state2 = abi.RF_DONE 455 return false 456 } 457 #state2 = abi.RF_READY 458 return true 459 }) 460 if #state2 == abi.RF_PANIC {runtime.panicrangestate(abi.RF_MISSING_PANIC)} 461 #state2 = abi.RF_EXHAUSTED 462 if #next < 0 { 463 #state1 = abi.RF_DONE 464 return false 465 } 466 #state1 = abi.RF_READY 467 return true 468 }) 469 if #state1 == abi.RF_PANIC {runtime.panicrangestate(abi.RF_MISSING_PANIC)} 470 #state1 = abi.RF_EXHAUSTED 471 if #next == -3 { 472 #next = 0 473 goto Top 474 } 475 } 476 477 Labeled break/continue to non-range-over-funcs are handled the same 478 way as goto. 479 480 # Defers 481 482 The last wrinkle is handling defer statements. If we have 483 484 for range f { 485 defer print("A") 486 } 487 488 we cannot rewrite that into 489 490 f(func() { 491 defer print("A") 492 }) 493 494 because the deferred code will run at the end of the iteration, not 495 the end of the containing function. To fix that, the runtime provides 496 a special hook that lets us obtain a defer "token" representing the 497 outer function and then use it in a later defer to attach the deferred 498 code to that outer function. 499 500 Normally, 501 502 defer print("A") 503 504 compiles to 505 506 runtime.deferproc(func() { print("A") }) 507 508 This changes in a range-over-func. For example: 509 510 for range f { 511 defer print("A") 512 } 513 514 compiles to 515 516 var #defers = runtime.deferrangefunc() 517 f(func() { 518 runtime.deferprocat(func() { print("A") }, #defers) 519 }) 520 521 For this rewriting phase, we insert the explicit initialization of 522 #defers and then attach the #defers variable to the CallStmt 523 representing the defer. That variable will be propagated to the 524 backend and will cause the backend to compile the defer using 525 deferprocat instead of an ordinary deferproc. 526 527 TODO: Could call runtime.deferrangefuncend after f. 528 */ 529 package rangefunc 530 531 import ( 532 "cmd/compile/internal/base" 533 "cmd/compile/internal/syntax" 534 "cmd/compile/internal/types2" 535 "fmt" 536 "go/constant" 537 "internal/abi" 538 "os" 539 ) 540 541 // nopos is the zero syntax.Pos. 542 var nopos syntax.Pos 543 544 // A rewriter implements rewriting the range-over-funcs in a given function. 545 type rewriter struct { 546 pkg *types2.Package 547 info *types2.Info 548 sig *types2.Signature 549 outer *syntax.FuncType 550 body *syntax.BlockStmt 551 552 // References to important types and values. 553 any types2.Object 554 bool types2.Object 555 int types2.Object 556 true types2.Object 557 false types2.Object 558 559 // Branch numbering, computed as needed. 560 branchNext map[branch]int // branch -> #next value 561 labelLoop map[string]*syntax.ForStmt // label -> innermost rangefunc loop it is declared inside (nil for no loop) 562 563 // Stack of nodes being visited. 564 stack []syntax.Node // all nodes 565 forStack []*forLoop // range-over-func loops 566 567 rewritten map[*syntax.ForStmt]syntax.Stmt 568 569 // Declared variables in generated code for outermost loop. 570 declStmt *syntax.DeclStmt 571 nextVar types2.Object 572 defers types2.Object 573 stateVarCount int // stateVars are referenced from their respective loops 574 bodyClosureCount int // to help the debugger, the closures generated for loop bodies get names 575 576 rangefuncBodyClosures map[*syntax.FuncLit]bool 577 } 578 579 // A branch is a single labeled branch. 580 type branch struct { 581 tok syntax.Token 582 label string 583 } 584 585 // A forLoop describes a single range-over-func loop being processed. 586 type forLoop struct { 587 nfor *syntax.ForStmt // actual syntax 588 stateVar *types2.Var // #state variable for this loop 589 stateVarDecl *syntax.VarDecl 590 depth int // outermost loop has depth 1, otherwise depth = depth(parent)+1 591 592 checkRet bool // add check for "return" after loop 593 checkBreak bool // add check for "break" after loop 594 checkContinue bool // add check for "continue" after loop 595 checkBranch []branch // add check for labeled branch after loop 596 } 597 598 type State int 599 600 // Rewrite rewrites all the range-over-funcs in the files. 601 // It returns the set of function literals generated from rangefunc loop bodies. 602 // This allows for rangefunc loop bodies to be distinguished by debuggers. 603 func Rewrite(pkg *types2.Package, info *types2.Info, files []*syntax.File) map[*syntax.FuncLit]bool { 604 ri := make(map[*syntax.FuncLit]bool) 605 for _, file := range files { 606 syntax.Inspect(file, func(n syntax.Node) bool { 607 switch n := n.(type) { 608 case *syntax.FuncDecl: 609 sig, _ := info.Defs[n.Name].Type().(*types2.Signature) 610 rewriteFunc(pkg, info, n.Type, n.Body, sig, ri) 611 return false 612 case *syntax.FuncLit: 613 sig, _ := info.Types[n].Type.(*types2.Signature) 614 if sig == nil { 615 tv := n.GetTypeInfo() 616 sig = tv.Type.(*types2.Signature) 617 } 618 rewriteFunc(pkg, info, n.Type, n.Body, sig, ri) 619 return false 620 } 621 return true 622 }) 623 } 624 return ri 625 } 626 627 // rewriteFunc rewrites all the range-over-funcs in a single function (a top-level func or a func literal). 628 // The typ and body are the function's type and body. 629 func rewriteFunc(pkg *types2.Package, info *types2.Info, typ *syntax.FuncType, body *syntax.BlockStmt, sig *types2.Signature, ri map[*syntax.FuncLit]bool) { 630 if body == nil { 631 return 632 } 633 r := &rewriter{ 634 pkg: pkg, 635 info: info, 636 outer: typ, 637 body: body, 638 sig: sig, 639 rangefuncBodyClosures: ri, 640 } 641 syntax.Inspect(body, r.inspect) 642 if (base.Flag.W != 0) && r.forStack != nil { 643 syntax.Fdump(os.Stderr, body) 644 } 645 } 646 647 // checkFuncMisuse reports whether to check for misuse of iterator callbacks functions. 648 func (r *rewriter) checkFuncMisuse() bool { 649 return base.Debug.RangeFuncCheck != 0 650 } 651 652 // inspect is a callback for syntax.Inspect that drives the actual rewriting. 653 // If it sees a func literal, it kicks off a separate rewrite for that literal. 654 // Otherwise, it maintains a stack of range-over-func loops and 655 // converts each in turn. 656 func (r *rewriter) inspect(n syntax.Node) bool { 657 switch n := n.(type) { 658 case *syntax.FuncLit: 659 sig, _ := r.info.Types[n].Type.(*types2.Signature) 660 if sig == nil { 661 tv := n.GetTypeInfo() 662 sig = tv.Type.(*types2.Signature) 663 } 664 rewriteFunc(r.pkg, r.info, n.Type, n.Body, sig, r.rangefuncBodyClosures) 665 return false 666 667 default: 668 // Push n onto stack. 669 r.stack = append(r.stack, n) 670 if nfor, ok := forRangeFunc(n); ok { 671 loop := &forLoop{nfor: nfor, depth: 1 + len(r.forStack)} 672 r.forStack = append(r.forStack, loop) 673 r.startLoop(loop) 674 } 675 676 case nil: 677 // n == nil signals that we are done visiting 678 // the top-of-stack node's children. Find it. 679 n = r.stack[len(r.stack)-1] 680 681 // If we are inside a range-over-func, 682 // take this moment to replace any break/continue/goto/return 683 // statements directly contained in this node. 684 // Also replace any converted for statements 685 // with the rewritten block. 686 switch n := n.(type) { 687 case *syntax.BlockStmt: 688 for i, s := range n.List { 689 n.List[i] = r.editStmt(s) 690 } 691 case *syntax.CaseClause: 692 for i, s := range n.Body { 693 n.Body[i] = r.editStmt(s) 694 } 695 case *syntax.CommClause: 696 for i, s := range n.Body { 697 n.Body[i] = r.editStmt(s) 698 } 699 case *syntax.LabeledStmt: 700 n.Stmt = r.editStmt(n.Stmt) 701 } 702 703 // Pop n. 704 if len(r.forStack) > 0 && r.stack[len(r.stack)-1] == r.forStack[len(r.forStack)-1].nfor { 705 r.endLoop(r.forStack[len(r.forStack)-1]) 706 r.forStack = r.forStack[:len(r.forStack)-1] 707 } 708 r.stack = r.stack[:len(r.stack)-1] 709 } 710 return true 711 } 712 713 // startLoop sets up for converting a range-over-func loop. 714 func (r *rewriter) startLoop(loop *forLoop) { 715 // For first loop in function, allocate syntax for any, bool, int, true, and false. 716 if r.any == nil { 717 r.any = types2.Universe.Lookup("any") 718 r.bool = types2.Universe.Lookup("bool") 719 r.int = types2.Universe.Lookup("int") 720 r.true = types2.Universe.Lookup("true") 721 r.false = types2.Universe.Lookup("false") 722 r.rewritten = make(map[*syntax.ForStmt]syntax.Stmt) 723 } 724 if r.checkFuncMisuse() { 725 // declare the state flag for this loop's body 726 loop.stateVar, loop.stateVarDecl = r.stateVar(loop.nfor.Pos()) 727 } 728 } 729 730 // editStmt returns the replacement for the statement x, 731 // or x itself if it should be left alone. 732 // This includes the for loops we are converting, 733 // as left in x.rewritten by r.endLoop. 734 func (r *rewriter) editStmt(x syntax.Stmt) syntax.Stmt { 735 if x, ok := x.(*syntax.ForStmt); ok { 736 if s := r.rewritten[x]; s != nil { 737 return s 738 } 739 } 740 741 if len(r.forStack) > 0 { 742 switch x := x.(type) { 743 case *syntax.BranchStmt: 744 return r.editBranch(x) 745 case *syntax.CallStmt: 746 if x.Tok == syntax.Defer { 747 return r.editDefer(x) 748 } 749 case *syntax.ReturnStmt: 750 return r.editReturn(x) 751 } 752 } 753 754 return x 755 } 756 757 // editDefer returns the replacement for the defer statement x. 758 // See the "Defers" section in the package doc comment above for more context. 759 func (r *rewriter) editDefer(x *syntax.CallStmt) syntax.Stmt { 760 if r.defers == nil { 761 // Declare and initialize the #defers token. 762 init := &syntax.CallExpr{ 763 Fun: runtimeSym(r.info, "deferrangefunc"), 764 } 765 tv := syntax.TypeAndValue{Type: r.any.Type()} 766 tv.SetIsValue() 767 init.SetTypeInfo(tv) 768 r.defers = r.declOuterVar("#defers", r.any.Type(), init) 769 } 770 771 // Attach the token as an "extra" argument to the defer. 772 x.DeferAt = r.useObj(r.defers) 773 setPos(x.DeferAt, x.Pos()) 774 return x 775 } 776 777 func (r *rewriter) stateVar(pos syntax.Pos) (*types2.Var, *syntax.VarDecl) { 778 r.stateVarCount++ 779 780 name := fmt.Sprintf("#state%d", r.stateVarCount) 781 typ := r.int.Type() 782 obj := types2.NewVar(pos, r.pkg, name, typ) 783 n := syntax.NewName(pos, name) 784 setValueType(n, typ) 785 r.info.Defs[n] = obj 786 787 return obj, &syntax.VarDecl{NameList: []*syntax.Name{n}, Values: r.stateConst(abi.RF_READY)} 788 } 789 790 // editReturn returns the replacement for the return statement x. 791 // See the "Return" section in the package doc comment above for more context. 792 func (r *rewriter) editReturn(x *syntax.ReturnStmt) syntax.Stmt { 793 bl := &syntax.BlockStmt{} 794 795 if x.Results != nil { 796 // rewrite "return val" into "assign to named result; return" 797 if len(r.outer.ResultList) > 0 { 798 // Make sure that result parameters all have names 799 for i, a := range r.outer.ResultList { 800 if a.Name == nil || a.Name.Value == "_" { 801 r.generateParamName(r.outer.ResultList, i) // updates a.Name 802 } 803 } 804 } 805 // Assign to named results 806 results := []types2.Object{} 807 for _, a := range r.outer.ResultList { 808 results = append(results, r.info.Defs[a.Name]) 809 } 810 bl.List = append(bl.List, &syntax.AssignStmt{Lhs: r.useList(results), Rhs: x.Results}) 811 x.Results = nil 812 } 813 814 next := -1 // return 815 816 // Tell the loops along the way to check for a return. 817 for _, loop := range r.forStack { 818 loop.checkRet = true 819 } 820 821 // Set #next, and return false. 822 823 bl.List = append(bl.List, &syntax.AssignStmt{Lhs: r.next(), Rhs: r.intConst(next)}) 824 if r.checkFuncMisuse() { 825 // mark this loop as exited, the others (which will be exited if iterators do not interfere) have not, yet. 826 bl.List = append(bl.List, r.setState(abi.RF_DONE, x.Pos())) 827 } 828 bl.List = append(bl.List, &syntax.ReturnStmt{Results: r.useObj(r.false)}) 829 setPos(bl, x.Pos()) 830 return bl 831 } 832 833 // perLoopStep is part of the encoding of loop-spanning control flow 834 // for function range iterators. Each multiple of two encodes a "return false" 835 // passing control to an enclosing iterator; a terminal value of 1 encodes 836 // "return true" (i.e., local continue) from the body function, and a terminal 837 // value of 0 encodes executing the remainder of the body function. 838 const perLoopStep = 2 839 840 // editBranch returns the replacement for the branch statement x, 841 // or x itself if it should be left alone. 842 // See the package doc comment above for more context. 843 func (r *rewriter) editBranch(x *syntax.BranchStmt) syntax.Stmt { 844 if x.Tok == syntax.Fallthrough { 845 // Fallthrough is unaffected by the rewrite. 846 return x 847 } 848 849 // Find target of break/continue/goto in r.forStack. 850 // (The target may not be in r.forStack at all.) 851 targ := x.Target 852 i := len(r.forStack) - 1 853 if x.Label == nil && r.forStack[i].nfor != targ { 854 // Unlabeled break or continue that's not nfor must be inside nfor. Leave alone. 855 return x 856 } 857 for i >= 0 && r.forStack[i].nfor != targ { 858 i-- 859 } 860 // exitFrom is the index of the loop interior to the target of the control flow, 861 // if such a loop exists (it does not if i == len(r.forStack) - 1) 862 exitFrom := i + 1 863 864 // Compute the value to assign to #next and the specific return to use. 865 var next int 866 var ret *syntax.ReturnStmt 867 if x.Tok == syntax.Goto || i < 0 { 868 // goto Label 869 // or break/continue of labeled non-range-over-func loop (x.Label != nil). 870 // We may be able to leave it alone, or we may have to break 871 // out of one or more nested loops and then use #next to signal 872 // to complete the break/continue/goto. 873 // Figure out which range-over-func loop contains the label. 874 r.computeBranchNext() 875 nfor := r.forStack[len(r.forStack)-1].nfor 876 label := x.Label.Value 877 targ := r.labelLoop[label] 878 if nfor == targ { 879 // Label is in the innermost range-over-func loop; use it directly. 880 return x 881 } 882 883 // Set #next to the code meaning break/continue/goto label. 884 next = r.branchNext[branch{x.Tok, label}] 885 886 // Break out of nested loops up to targ. 887 i := len(r.forStack) - 1 888 for i >= 0 && r.forStack[i].nfor != targ { 889 i-- 890 } 891 exitFrom = i + 1 892 893 // Mark loop we exit to get to targ to check for that branch. 894 // When i==-1 / exitFrom == 0 that's the outermost func body. 895 top := r.forStack[exitFrom] 896 top.checkBranch = append(top.checkBranch, branch{x.Tok, label}) 897 898 // Mark loops along the way to check for a plain return, so they break. 899 for j := exitFrom + 1; j < len(r.forStack); j++ { 900 r.forStack[j].checkRet = true 901 } 902 903 // In the innermost loop, use a plain "return false". 904 ret = &syntax.ReturnStmt{Results: r.useObj(r.false)} 905 } else { 906 // break/continue of labeled range-over-func loop. 907 if exitFrom == len(r.forStack) { 908 // Simple break or continue. 909 // Continue returns true, break returns false, optionally both adjust state, 910 // neither modifies #next. 911 var state abi.RF_State 912 if x.Tok == syntax.Continue { 913 ret = &syntax.ReturnStmt{Results: r.useObj(r.true)} 914 state = abi.RF_READY 915 } else { 916 ret = &syntax.ReturnStmt{Results: r.useObj(r.false)} 917 state = abi.RF_DONE 918 } 919 var stmts []syntax.Stmt 920 if r.checkFuncMisuse() { 921 stmts = []syntax.Stmt{r.setState(state, x.Pos()), ret} 922 } else { 923 stmts = []syntax.Stmt{ret} 924 } 925 bl := &syntax.BlockStmt{ 926 List: stmts, 927 } 928 setPos(bl, x.Pos()) 929 return bl 930 } 931 932 ret = &syntax.ReturnStmt{Results: r.useObj(r.false)} 933 934 // The loop inside the one we are break/continue-ing 935 // needs to make that happen when we break out of it. 936 if x.Tok == syntax.Continue { 937 r.forStack[exitFrom].checkContinue = true 938 } else { 939 exitFrom = i // exitFrom-- 940 r.forStack[exitFrom].checkBreak = true 941 } 942 943 // The loops along the way just need to break. 944 for j := exitFrom + 1; j < len(r.forStack); j++ { 945 r.forStack[j].checkBreak = true 946 } 947 948 // Set next to break the appropriate number of times; 949 // the final time may be a continue, not a break. 950 next = perLoopStep * (i + 1) 951 if x.Tok == syntax.Continue { 952 next-- 953 } 954 } 955 956 // Assign #next = next and do the return. 957 as := &syntax.AssignStmt{Lhs: r.next(), Rhs: r.intConst(next)} 958 bl := &syntax.BlockStmt{ 959 List: []syntax.Stmt{as}, 960 } 961 962 if r.checkFuncMisuse() { 963 // Set #stateK for this loop. 964 // The exterior loops have not exited yet, and the iterator might interfere. 965 bl.List = append(bl.List, r.setState(abi.RF_DONE, x.Pos())) 966 } 967 968 bl.List = append(bl.List, ret) 969 setPos(bl, x.Pos()) 970 return bl 971 } 972 973 // computeBranchNext computes the branchNext numbering 974 // and determines which labels end up inside which range-over-func loop bodies. 975 func (r *rewriter) computeBranchNext() { 976 if r.labelLoop != nil { 977 return 978 } 979 980 r.labelLoop = make(map[string]*syntax.ForStmt) 981 r.branchNext = make(map[branch]int) 982 983 var labels []string 984 var stack []syntax.Node 985 var forStack []*syntax.ForStmt 986 forStack = append(forStack, nil) 987 syntax.Inspect(r.body, func(n syntax.Node) bool { 988 if n != nil { 989 stack = append(stack, n) 990 if nfor, ok := forRangeFunc(n); ok { 991 forStack = append(forStack, nfor) 992 } 993 if n, ok := n.(*syntax.LabeledStmt); ok { 994 l := n.Label.Value 995 labels = append(labels, l) 996 f := forStack[len(forStack)-1] 997 r.labelLoop[l] = f 998 } 999 } else { 1000 n := stack[len(stack)-1] 1001 stack = stack[:len(stack)-1] 1002 if n == forStack[len(forStack)-1] { 1003 forStack = forStack[:len(forStack)-1] 1004 } 1005 } 1006 return true 1007 }) 1008 1009 // Assign numbers to all the labels we observed. 1010 used := -1 // returns use -1 1011 for _, l := range labels { 1012 used -= 3 1013 r.branchNext[branch{syntax.Break, l}] = used 1014 r.branchNext[branch{syntax.Continue, l}] = used + 1 1015 r.branchNext[branch{syntax.Goto, l}] = used + 2 1016 } 1017 } 1018 1019 // endLoop finishes the conversion of a range-over-func loop. 1020 // We have inspected and rewritten the body of the loop and can now 1021 // construct the body function and rewrite the for loop into a call 1022 // bracketed by any declarations and checks it requires. 1023 func (r *rewriter) endLoop(loop *forLoop) { 1024 // Pick apart for range X { ... } 1025 nfor := loop.nfor 1026 start, end := nfor.Pos(), nfor.Body.Rbrace // start, end position of for loop 1027 rclause := nfor.Init.(*syntax.RangeClause) 1028 rfunc := types2.CoreType(rclause.X.GetTypeInfo().Type).(*types2.Signature) // type of X - func(func(...)bool) 1029 if rfunc.Params().Len() != 1 { 1030 base.Fatalf("invalid typecheck of range func") 1031 } 1032 ftyp := types2.CoreType(rfunc.Params().At(0).Type()).(*types2.Signature) // func(...) bool 1033 if ftyp.Results().Len() != 1 { 1034 base.Fatalf("invalid typecheck of range func") 1035 } 1036 1037 // Give the closure generated for the body a name, to help the debugger connect it to its frame, if active. 1038 r.bodyClosureCount++ 1039 clo := r.bodyFunc(nfor.Body.List, syntax.UnpackListExpr(rclause.Lhs), rclause.Def, ftyp, start, end) 1040 cloDecl, cloVar := r.declSingleVar(fmt.Sprintf("#yield%d", r.bodyClosureCount), clo.GetTypeInfo().Type, clo) 1041 setPos(cloDecl, start) 1042 1043 // Build X(bodyFunc) 1044 call := &syntax.ExprStmt{ 1045 X: &syntax.CallExpr{ 1046 Fun: rclause.X, 1047 ArgList: []syntax.Expr{ 1048 r.useObj(cloVar), 1049 }, 1050 }, 1051 } 1052 setPos(call, start) 1053 1054 // Build checks based on #next after X(bodyFunc) 1055 checks := r.checks(loop, end) 1056 1057 // Rewrite for vars := range X { ... } to 1058 // 1059 // { 1060 // r.declStmt 1061 // call 1062 // checks 1063 // } 1064 // 1065 // The r.declStmt can be added to by this loop or any inner loop 1066 // during the creation of r.bodyFunc; it is only emitted in the outermost 1067 // converted range loop. 1068 block := &syntax.BlockStmt{Rbrace: end} 1069 setPos(block, start) 1070 if len(r.forStack) == 1 && r.declStmt != nil { 1071 setPos(r.declStmt, start) 1072 block.List = append(block.List, r.declStmt) 1073 } 1074 1075 // declare the state variable here so it has proper scope and initialization 1076 if r.checkFuncMisuse() { 1077 stateVarDecl := &syntax.DeclStmt{DeclList: []syntax.Decl{loop.stateVarDecl}} 1078 setPos(stateVarDecl, start) 1079 block.List = append(block.List, stateVarDecl) 1080 } 1081 1082 // iteratorFunc(bodyFunc) 1083 block.List = append(block.List, cloDecl, call) 1084 1085 if r.checkFuncMisuse() { 1086 // iteratorFunc has exited, check for swallowed panic, and set body state to abi.RF_EXHAUSTED 1087 nif := &syntax.IfStmt{ 1088 Cond: r.cond(syntax.Eql, r.useObj(loop.stateVar), r.stateConst(abi.RF_PANIC)), 1089 Then: &syntax.BlockStmt{ 1090 List: []syntax.Stmt{r.callPanic(start, r.stateConst(abi.RF_MISSING_PANIC))}, 1091 }, 1092 } 1093 setPos(nif, end) 1094 block.List = append(block.List, nif) 1095 block.List = append(block.List, r.setState(abi.RF_EXHAUSTED, end)) 1096 } 1097 block.List = append(block.List, checks...) 1098 1099 if len(r.forStack) == 1 { // ending an outermost loop 1100 r.declStmt = nil 1101 r.nextVar = nil 1102 r.defers = nil 1103 } 1104 1105 r.rewritten[nfor] = block 1106 } 1107 1108 func (r *rewriter) cond(op syntax.Operator, x, y syntax.Expr) *syntax.Operation { 1109 cond := &syntax.Operation{Op: op, X: x, Y: y} 1110 tv := syntax.TypeAndValue{Type: r.bool.Type()} 1111 tv.SetIsValue() 1112 cond.SetTypeInfo(tv) 1113 return cond 1114 } 1115 1116 func (r *rewriter) setState(val abi.RF_State, pos syntax.Pos) *syntax.AssignStmt { 1117 ss := r.setStateAt(len(r.forStack)-1, val) 1118 setPos(ss, pos) 1119 return ss 1120 } 1121 1122 func (r *rewriter) setStateAt(index int, stateVal abi.RF_State) *syntax.AssignStmt { 1123 loop := r.forStack[index] 1124 return &syntax.AssignStmt{ 1125 Lhs: r.useObj(loop.stateVar), 1126 Rhs: r.stateConst(stateVal), 1127 } 1128 } 1129 1130 // bodyFunc converts the loop body (control flow has already been updated) 1131 // to a func literal that can be passed to the range function. 1132 // 1133 // vars is the range variables from the range statement. 1134 // def indicates whether this is a := range statement. 1135 // ftyp is the type of the function we are creating 1136 // start and end are the syntax positions to use for new nodes 1137 // that should be at the start or end of the loop. 1138 func (r *rewriter) bodyFunc(body []syntax.Stmt, lhs []syntax.Expr, def bool, ftyp *types2.Signature, start, end syntax.Pos) *syntax.FuncLit { 1139 // Starting X(bodyFunc); build up bodyFunc first. 1140 var params, results []*types2.Var 1141 results = append(results, types2.NewVar(start, nil, "#r", r.bool.Type())) 1142 bodyFunc := &syntax.FuncLit{ 1143 // Note: Type is ignored but needs to be non-nil to avoid panic in syntax.Inspect. 1144 Type: &syntax.FuncType{}, 1145 Body: &syntax.BlockStmt{ 1146 List: []syntax.Stmt{}, 1147 Rbrace: end, 1148 }, 1149 } 1150 r.rangefuncBodyClosures[bodyFunc] = true 1151 setPos(bodyFunc, start) 1152 1153 for i := 0; i < ftyp.Params().Len(); i++ { 1154 typ := ftyp.Params().At(i).Type() 1155 var paramVar *types2.Var 1156 if i < len(lhs) && def { 1157 // Reuse range variable as parameter. 1158 x := lhs[i] 1159 paramVar = r.info.Defs[x.(*syntax.Name)].(*types2.Var) 1160 } else { 1161 // Declare new parameter and assign it to range expression. 1162 paramVar = types2.NewVar(start, r.pkg, fmt.Sprintf("#p%d", 1+i), typ) 1163 if i < len(lhs) { 1164 x := lhs[i] 1165 as := &syntax.AssignStmt{Lhs: x, Rhs: r.useObj(paramVar)} 1166 as.SetPos(x.Pos()) 1167 setPos(as.Rhs, x.Pos()) 1168 bodyFunc.Body.List = append(bodyFunc.Body.List, as) 1169 } 1170 } 1171 params = append(params, paramVar) 1172 } 1173 1174 tv := syntax.TypeAndValue{ 1175 Type: types2.NewSignatureType(nil, nil, nil, 1176 types2.NewTuple(params...), 1177 types2.NewTuple(results...), 1178 false), 1179 } 1180 tv.SetIsValue() 1181 bodyFunc.SetTypeInfo(tv) 1182 1183 loop := r.forStack[len(r.forStack)-1] 1184 1185 if r.checkFuncMisuse() { 1186 // #tmpState := #stateVarN 1187 // #stateVarN = abi.RF_PANIC 1188 // if #tmpState != abi.RF_READY { 1189 // runtime.panicrangestate(#tmpState) 1190 // } 1191 // 1192 // That is a slightly code-size-optimized version of 1193 // 1194 // if #stateVarN != abi.RF_READY { 1195 // #stateVarN = abi.RF_PANIC // If we ever need to specially detect "iterator swallowed checking panic" we put a different value here. 1196 // runtime.panicrangestate(#tmpState) 1197 // } 1198 // #stateVarN = abi.RF_PANIC 1199 // 1200 1201 tmpDecl, tmpState := r.declSingleVar("#tmpState", r.int.Type(), r.useObj(loop.stateVar)) 1202 bodyFunc.Body.List = append(bodyFunc.Body.List, tmpDecl) 1203 bodyFunc.Body.List = append(bodyFunc.Body.List, r.setState(abi.RF_PANIC, start)) 1204 bodyFunc.Body.List = append(bodyFunc.Body.List, r.assertReady(start, tmpState)) 1205 } 1206 1207 // Original loop body (already rewritten by editStmt during inspect). 1208 bodyFunc.Body.List = append(bodyFunc.Body.List, body...) 1209 1210 // end of loop body, set state to abi.RF_READY and return true to continue iteration 1211 if r.checkFuncMisuse() { 1212 bodyFunc.Body.List = append(bodyFunc.Body.List, r.setState(abi.RF_READY, end)) 1213 } 1214 ret := &syntax.ReturnStmt{Results: r.useObj(r.true)} 1215 ret.SetPos(end) 1216 bodyFunc.Body.List = append(bodyFunc.Body.List, ret) 1217 1218 return bodyFunc 1219 } 1220 1221 // checks returns the post-call checks that need to be done for the given loop. 1222 func (r *rewriter) checks(loop *forLoop, pos syntax.Pos) []syntax.Stmt { 1223 var list []syntax.Stmt 1224 if len(loop.checkBranch) > 0 { 1225 did := make(map[branch]bool) 1226 for _, br := range loop.checkBranch { 1227 if did[br] { 1228 continue 1229 } 1230 did[br] = true 1231 doBranch := &syntax.BranchStmt{Tok: br.tok, Label: &syntax.Name{Value: br.label}} 1232 list = append(list, r.ifNext(syntax.Eql, r.branchNext[br], true, doBranch)) 1233 } 1234 } 1235 1236 curLoop := loop.depth - 1 1237 curLoopIndex := curLoop - 1 1238 1239 if len(r.forStack) == 1 { 1240 if loop.checkRet { 1241 list = append(list, r.ifNext(syntax.Eql, -1, false, retStmt(nil))) 1242 } 1243 } else { 1244 1245 // Idealized check, implemented more simply for now. 1246 1247 // // N == depth of this loop, one less than the one just exited. 1248 // if #next != 0 { 1249 // if #next >= perLoopStep*N-1 { // this loop 1250 // if #next >= perLoopStep*N+1 { // error checking 1251 // runtime.panicrangestate(abi.RF_DONE) 1252 // } 1253 // rv := #next & 1 == 1 // code generates into #next&1 1254 // #next = 0 1255 // return rv 1256 // } 1257 // return false // or handle returns and gotos 1258 // } 1259 1260 if loop.checkRet { 1261 // Note: next < 0 also handles gotos handled by outer loops. 1262 // We set checkRet in that case to trigger this check. 1263 if r.checkFuncMisuse() { 1264 list = append(list, r.ifNext(syntax.Lss, 0, false, r.setStateAt(curLoopIndex, abi.RF_DONE), retStmt(r.useObj(r.false)))) 1265 } else { 1266 list = append(list, r.ifNext(syntax.Lss, 0, false, retStmt(r.useObj(r.false)))) 1267 } 1268 } 1269 1270 depthStep := perLoopStep * (curLoop) 1271 1272 if r.checkFuncMisuse() { 1273 list = append(list, r.ifNext(syntax.Gtr, depthStep, false, r.callPanic(pos, r.stateConst(abi.RF_DONE)))) 1274 } else { 1275 list = append(list, r.ifNext(syntax.Gtr, depthStep, true)) 1276 } 1277 1278 if r.checkFuncMisuse() { 1279 if loop.checkContinue { 1280 list = append(list, r.ifNext(syntax.Eql, depthStep-1, true, r.setStateAt(curLoopIndex, abi.RF_READY), retStmt(r.useObj(r.true)))) 1281 } 1282 1283 if loop.checkBreak { 1284 list = append(list, r.ifNext(syntax.Eql, depthStep, true, r.setStateAt(curLoopIndex, abi.RF_DONE), retStmt(r.useObj(r.false)))) 1285 } 1286 1287 if loop.checkContinue || loop.checkBreak { 1288 list = append(list, r.ifNext(syntax.Gtr, 0, false, r.setStateAt(curLoopIndex, abi.RF_DONE), retStmt(r.useObj(r.false)))) 1289 } 1290 1291 } else { 1292 if loop.checkContinue { 1293 list = append(list, r.ifNext(syntax.Eql, depthStep-1, true, retStmt(r.useObj(r.true)))) 1294 } 1295 if loop.checkBreak { 1296 list = append(list, r.ifNext(syntax.Eql, depthStep, true, retStmt(r.useObj(r.false)))) 1297 } 1298 if loop.checkContinue || loop.checkBreak { 1299 list = append(list, r.ifNext(syntax.Gtr, 0, false, retStmt(r.useObj(r.false)))) 1300 } 1301 } 1302 } 1303 1304 for _, j := range list { 1305 setPos(j, pos) 1306 } 1307 return list 1308 } 1309 1310 // retStmt returns a return statement returning the given return values. 1311 func retStmt(results syntax.Expr) *syntax.ReturnStmt { 1312 return &syntax.ReturnStmt{Results: results} 1313 } 1314 1315 // ifNext returns the statement: 1316 // 1317 // if #next op c { [#next = 0;] thens... } 1318 func (r *rewriter) ifNext(op syntax.Operator, c int, zeroNext bool, thens ...syntax.Stmt) syntax.Stmt { 1319 var thenList []syntax.Stmt 1320 if zeroNext { 1321 clr := &syntax.AssignStmt{ 1322 Lhs: r.next(), 1323 Rhs: r.intConst(0), 1324 } 1325 thenList = append(thenList, clr) 1326 } 1327 for _, then := range thens { 1328 thenList = append(thenList, then) 1329 } 1330 nif := &syntax.IfStmt{ 1331 Cond: r.cond(op, r.next(), r.intConst(c)), 1332 Then: &syntax.BlockStmt{ 1333 List: thenList, 1334 }, 1335 } 1336 return nif 1337 } 1338 1339 // setValueType marks x as a value with type typ. 1340 func setValueType(x syntax.Expr, typ syntax.Type) { 1341 tv := syntax.TypeAndValue{Type: typ} 1342 tv.SetIsValue() 1343 x.SetTypeInfo(tv) 1344 } 1345 1346 // assertReady returns the statement: 1347 // 1348 // if #tmpState != abi.RF_READY { runtime.panicrangestate(#tmpState) } 1349 func (r *rewriter) assertReady(start syntax.Pos, tmpState *types2.Var) syntax.Stmt { 1350 1351 nif := &syntax.IfStmt{ 1352 Cond: r.cond(syntax.Neq, r.useObj(tmpState), r.stateConst(abi.RF_READY)), 1353 Then: &syntax.BlockStmt{ 1354 List: []syntax.Stmt{ 1355 r.callPanic(start, r.useObj(tmpState))}, 1356 }, 1357 } 1358 setPos(nif, start) 1359 return nif 1360 } 1361 1362 func (r *rewriter) callPanic(start syntax.Pos, arg syntax.Expr) syntax.Stmt { 1363 callPanicExpr := &syntax.CallExpr{ 1364 Fun: runtimeSym(r.info, "panicrangestate"), 1365 ArgList: []syntax.Expr{arg}, 1366 } 1367 setValueType(callPanicExpr, nil) // no result type 1368 return &syntax.ExprStmt{X: callPanicExpr} 1369 } 1370 1371 // next returns a reference to the #next variable. 1372 func (r *rewriter) next() *syntax.Name { 1373 if r.nextVar == nil { 1374 r.nextVar = r.declOuterVar("#next", r.int.Type(), nil) 1375 } 1376 return r.useObj(r.nextVar) 1377 } 1378 1379 // forRangeFunc checks whether n is a range-over-func. 1380 // If so, it returns n.(*syntax.ForStmt), true. 1381 // Otherwise it returns nil, false. 1382 func forRangeFunc(n syntax.Node) (*syntax.ForStmt, bool) { 1383 nfor, ok := n.(*syntax.ForStmt) 1384 if !ok { 1385 return nil, false 1386 } 1387 nrange, ok := nfor.Init.(*syntax.RangeClause) 1388 if !ok { 1389 return nil, false 1390 } 1391 _, ok = types2.CoreType(nrange.X.GetTypeInfo().Type).(*types2.Signature) 1392 if !ok { 1393 return nil, false 1394 } 1395 return nfor, true 1396 } 1397 1398 // intConst returns syntax for an integer literal with the given value. 1399 func (r *rewriter) intConst(c int) *syntax.BasicLit { 1400 lit := &syntax.BasicLit{ 1401 Value: fmt.Sprint(c), 1402 Kind: syntax.IntLit, 1403 } 1404 tv := syntax.TypeAndValue{Type: r.int.Type(), Value: constant.MakeInt64(int64(c))} 1405 tv.SetIsValue() 1406 lit.SetTypeInfo(tv) 1407 return lit 1408 } 1409 1410 func (r *rewriter) stateConst(s abi.RF_State) *syntax.BasicLit { 1411 return r.intConst(int(s)) 1412 } 1413 1414 // useObj returns syntax for a reference to decl, which should be its declaration. 1415 func (r *rewriter) useObj(obj types2.Object) *syntax.Name { 1416 n := syntax.NewName(nopos, obj.Name()) 1417 tv := syntax.TypeAndValue{Type: obj.Type()} 1418 tv.SetIsValue() 1419 n.SetTypeInfo(tv) 1420 r.info.Uses[n] = obj 1421 return n 1422 } 1423 1424 // useList is useVar for a list of decls. 1425 func (r *rewriter) useList(vars []types2.Object) syntax.Expr { 1426 var new []syntax.Expr 1427 for _, obj := range vars { 1428 new = append(new, r.useObj(obj)) 1429 } 1430 if len(new) == 1 { 1431 return new[0] 1432 } 1433 return &syntax.ListExpr{ElemList: new} 1434 } 1435 1436 func (r *rewriter) makeVarName(pos syntax.Pos, name string, typ types2.Type) (*types2.Var, *syntax.Name) { 1437 obj := types2.NewVar(pos, r.pkg, name, typ) 1438 n := syntax.NewName(pos, name) 1439 tv := syntax.TypeAndValue{Type: typ} 1440 tv.SetIsValue() 1441 n.SetTypeInfo(tv) 1442 r.info.Defs[n] = obj 1443 return obj, n 1444 } 1445 1446 func (r *rewriter) generateParamName(results []*syntax.Field, i int) { 1447 obj, n := r.sig.RenameResult(results, i) 1448 r.info.Defs[n] = obj 1449 } 1450 1451 // declOuterVar declares a variable with a given name, type, and initializer value, 1452 // in the same scope as the outermost loop in a loop nest. 1453 func (r *rewriter) declOuterVar(name string, typ types2.Type, init syntax.Expr) *types2.Var { 1454 if r.declStmt == nil { 1455 r.declStmt = &syntax.DeclStmt{} 1456 } 1457 stmt := r.declStmt 1458 obj, n := r.makeVarName(stmt.Pos(), name, typ) 1459 stmt.DeclList = append(stmt.DeclList, &syntax.VarDecl{ 1460 NameList: []*syntax.Name{n}, 1461 // Note: Type is ignored 1462 Values: init, 1463 }) 1464 return obj 1465 } 1466 1467 // declSingleVar declares a variable with a given name, type, and initializer value, 1468 // and returns both the declaration and variable, so that the declaration can be placed 1469 // in a specific scope. 1470 func (r *rewriter) declSingleVar(name string, typ types2.Type, init syntax.Expr) (*syntax.DeclStmt, *types2.Var) { 1471 stmt := &syntax.DeclStmt{} 1472 obj, n := r.makeVarName(stmt.Pos(), name, typ) 1473 stmt.DeclList = append(stmt.DeclList, &syntax.VarDecl{ 1474 NameList: []*syntax.Name{n}, 1475 // Note: Type is ignored 1476 Values: init, 1477 }) 1478 return stmt, obj 1479 } 1480 1481 // runtimePkg is a fake runtime package that contains what we need to refer to in package runtime. 1482 var runtimePkg = func() *types2.Package { 1483 var nopos syntax.Pos 1484 pkg := types2.NewPackage("runtime", "runtime") 1485 anyType := types2.Universe.Lookup("any").Type() 1486 intType := types2.Universe.Lookup("int").Type() 1487 1488 // func deferrangefunc() unsafe.Pointer 1489 obj := types2.NewFunc(nopos, pkg, "deferrangefunc", types2.NewSignatureType(nil, nil, nil, nil, types2.NewTuple(types2.NewParam(nopos, pkg, "extra", anyType)), false)) 1490 pkg.Scope().Insert(obj) 1491 1492 // func panicrangestate() 1493 obj = types2.NewFunc(nopos, pkg, "panicrangestate", types2.NewSignatureType(nil, nil, nil, types2.NewTuple(types2.NewParam(nopos, pkg, "state", intType)), nil, false)) 1494 pkg.Scope().Insert(obj) 1495 1496 return pkg 1497 }() 1498 1499 // runtimeSym returns a reference to a symbol in the fake runtime package. 1500 func runtimeSym(info *types2.Info, name string) *syntax.Name { 1501 obj := runtimePkg.Scope().Lookup(name) 1502 n := syntax.NewName(nopos, "runtime."+name) 1503 tv := syntax.TypeAndValue{Type: obj.Type()} 1504 tv.SetIsValue() 1505 tv.SetIsRuntimeHelper() 1506 n.SetTypeInfo(tv) 1507 info.Uses[n] = obj 1508 return n 1509 } 1510 1511 // setPos walks the top structure of x that has no position assigned 1512 // and assigns it all to have position pos. 1513 // When setPos encounters a syntax node with a position assigned, 1514 // setPos does not look inside that node. 1515 // setPos only needs to handle syntax we create in this package; 1516 // all other syntax should have positions assigned already. 1517 func setPos(x syntax.Node, pos syntax.Pos) { 1518 if x == nil { 1519 return 1520 } 1521 syntax.Inspect(x, func(n syntax.Node) bool { 1522 if n == nil || n.Pos() != nopos { 1523 return false 1524 } 1525 n.SetPos(pos) 1526 switch n := n.(type) { 1527 case *syntax.BlockStmt: 1528 if n.Rbrace == nopos { 1529 n.Rbrace = pos 1530 } 1531 } 1532 return true 1533 }) 1534 } 1535