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 if _, existed := r.labelLoop[l]; existed { 998 // The typechecker has already validated that labels are unique within this scope. 999 // If a duplicate label 'X' is encountered, it must reside in a nested scope 1000 // (e.g., inside a function literal). Because nested labels do not affect 1001 // the current control flow analysis, they can be safely ignored. 1002 } else { 1003 r.labelLoop[l] = f 1004 } 1005 } 1006 } else { 1007 n := stack[len(stack)-1] 1008 stack = stack[:len(stack)-1] 1009 if n == forStack[len(forStack)-1] { 1010 forStack = forStack[:len(forStack)-1] 1011 } 1012 } 1013 return true 1014 }) 1015 1016 // Assign numbers to all the labels we observed. 1017 used := -1 // returns use -1 1018 for _, l := range labels { 1019 used -= 3 1020 r.branchNext[branch{syntax.Break, l}] = used 1021 r.branchNext[branch{syntax.Continue, l}] = used + 1 1022 r.branchNext[branch{syntax.Goto, l}] = used + 2 1023 } 1024 } 1025 1026 // endLoop finishes the conversion of a range-over-func loop. 1027 // We have inspected and rewritten the body of the loop and can now 1028 // construct the body function and rewrite the for loop into a call 1029 // bracketed by any declarations and checks it requires. 1030 func (r *rewriter) endLoop(loop *forLoop) { 1031 // Pick apart for range X { ... } 1032 nfor := loop.nfor 1033 start, end := nfor.Pos(), nfor.Body.Rbrace // start, end position of for loop 1034 rclause := nfor.Init.(*syntax.RangeClause) 1035 rfunc := types2.CoreType(rclause.X.GetTypeInfo().Type).(*types2.Signature) // type of X - func(func(...)bool) 1036 if rfunc.Params().Len() != 1 { 1037 base.Fatalf("invalid typecheck of range func") 1038 } 1039 ftyp := types2.CoreType(rfunc.Params().At(0).Type()).(*types2.Signature) // func(...) bool 1040 if ftyp.Results().Len() != 1 { 1041 base.Fatalf("invalid typecheck of range func") 1042 } 1043 1044 // Give the closure generated for the body a name, to help the debugger connect it to its frame, if active. 1045 r.bodyClosureCount++ 1046 clo := r.bodyFunc(nfor.Body.List, syntax.UnpackListExpr(rclause.Lhs), rclause.Def, ftyp, start, end) 1047 cloDecl, cloVar := r.declSingleVar(fmt.Sprintf("#yield%d", r.bodyClosureCount), clo.GetTypeInfo().Type, clo) 1048 setPos(cloDecl, start) 1049 1050 // Build X(bodyFunc) 1051 call := &syntax.ExprStmt{ 1052 X: &syntax.CallExpr{ 1053 Fun: rclause.X, 1054 ArgList: []syntax.Expr{ 1055 r.useObj(cloVar), 1056 }, 1057 }, 1058 } 1059 setPos(call, start) 1060 1061 // Build checks based on #next after X(bodyFunc) 1062 checks := r.checks(loop, end) 1063 1064 // Rewrite for vars := range X { ... } to 1065 // 1066 // { 1067 // r.declStmt 1068 // call 1069 // checks 1070 // } 1071 // 1072 // The r.declStmt can be added to by this loop or any inner loop 1073 // during the creation of r.bodyFunc; it is only emitted in the outermost 1074 // converted range loop. 1075 block := &syntax.BlockStmt{Rbrace: end} 1076 setPos(block, start) 1077 if len(r.forStack) == 1 && r.declStmt != nil { 1078 setPos(r.declStmt, start) 1079 block.List = append(block.List, r.declStmt) 1080 } 1081 1082 // declare the state variable here so it has proper scope and initialization 1083 if r.checkFuncMisuse() { 1084 stateVarDecl := &syntax.DeclStmt{DeclList: []syntax.Decl{loop.stateVarDecl}} 1085 setPos(stateVarDecl, start) 1086 block.List = append(block.List, stateVarDecl) 1087 } 1088 1089 // iteratorFunc(bodyFunc) 1090 block.List = append(block.List, cloDecl, call) 1091 1092 if r.checkFuncMisuse() { 1093 // iteratorFunc has exited, check for swallowed panic, and set body state to abi.RF_EXHAUSTED 1094 nif := &syntax.IfStmt{ 1095 Cond: r.cond(syntax.Eql, r.useObj(loop.stateVar), r.stateConst(abi.RF_PANIC)), 1096 Then: &syntax.BlockStmt{ 1097 List: []syntax.Stmt{r.callPanic(start, r.stateConst(abi.RF_MISSING_PANIC))}, 1098 }, 1099 } 1100 setPos(nif, end) 1101 block.List = append(block.List, nif) 1102 block.List = append(block.List, r.setState(abi.RF_EXHAUSTED, end)) 1103 } 1104 block.List = append(block.List, checks...) 1105 1106 if len(r.forStack) == 1 { // ending an outermost loop 1107 r.declStmt = nil 1108 r.nextVar = nil 1109 r.defers = nil 1110 } 1111 1112 r.rewritten[nfor] = block 1113 } 1114 1115 func (r *rewriter) cond(op syntax.Operator, x, y syntax.Expr) *syntax.Operation { 1116 cond := &syntax.Operation{Op: op, X: x, Y: y} 1117 tv := syntax.TypeAndValue{Type: r.bool.Type()} 1118 tv.SetIsValue() 1119 cond.SetTypeInfo(tv) 1120 return cond 1121 } 1122 1123 func (r *rewriter) setState(val abi.RF_State, pos syntax.Pos) *syntax.AssignStmt { 1124 ss := r.setStateAt(len(r.forStack)-1, val) 1125 setPos(ss, pos) 1126 return ss 1127 } 1128 1129 func (r *rewriter) setStateAt(index int, stateVal abi.RF_State) *syntax.AssignStmt { 1130 loop := r.forStack[index] 1131 return &syntax.AssignStmt{ 1132 Lhs: r.useObj(loop.stateVar), 1133 Rhs: r.stateConst(stateVal), 1134 } 1135 } 1136 1137 // bodyFunc converts the loop body (control flow has already been updated) 1138 // to a func literal that can be passed to the range function. 1139 // 1140 // vars is the range variables from the range statement. 1141 // def indicates whether this is a := range statement. 1142 // ftyp is the type of the function we are creating 1143 // start and end are the syntax positions to use for new nodes 1144 // that should be at the start or end of the loop. 1145 func (r *rewriter) bodyFunc(body []syntax.Stmt, lhs []syntax.Expr, def bool, ftyp *types2.Signature, start, end syntax.Pos) *syntax.FuncLit { 1146 // Starting X(bodyFunc); build up bodyFunc first. 1147 var params, results []*types2.Var 1148 results = append(results, types2.NewVar(start, nil, "#r", r.bool.Type())) 1149 bodyFunc := &syntax.FuncLit{ 1150 // Note: Type is ignored but needs to be non-nil to avoid panic in syntax.Inspect. 1151 Type: &syntax.FuncType{}, 1152 Body: &syntax.BlockStmt{ 1153 List: []syntax.Stmt{}, 1154 Rbrace: end, 1155 }, 1156 } 1157 r.rangefuncBodyClosures[bodyFunc] = true 1158 setPos(bodyFunc, start) 1159 1160 for i := 0; i < ftyp.Params().Len(); i++ { 1161 typ := ftyp.Params().At(i).Type() 1162 var paramVar *types2.Var 1163 if i < len(lhs) && def { 1164 // Reuse range variable as parameter. 1165 x := lhs[i] 1166 paramVar = r.info.Defs[x.(*syntax.Name)].(*types2.Var) 1167 } else { 1168 // Declare new parameter and assign it to range expression. 1169 paramVar = types2.NewVar(start, r.pkg, fmt.Sprintf("#p%d", 1+i), typ) 1170 if i < len(lhs) { 1171 x := lhs[i] 1172 as := &syntax.AssignStmt{Lhs: x, Rhs: r.useObj(paramVar)} 1173 as.SetPos(x.Pos()) 1174 setPos(as.Rhs, x.Pos()) 1175 bodyFunc.Body.List = append(bodyFunc.Body.List, as) 1176 } 1177 } 1178 params = append(params, paramVar) 1179 } 1180 1181 tv := syntax.TypeAndValue{ 1182 Type: types2.NewSignatureType(nil, nil, nil, 1183 types2.NewTuple(params...), 1184 types2.NewTuple(results...), 1185 ftyp.Variadic()), 1186 } 1187 tv.SetIsValue() 1188 bodyFunc.SetTypeInfo(tv) 1189 1190 loop := r.forStack[len(r.forStack)-1] 1191 1192 if r.checkFuncMisuse() { 1193 // #tmpState := #stateVarN 1194 // #stateVarN = abi.RF_PANIC 1195 // if #tmpState != abi.RF_READY { 1196 // runtime.panicrangestate(#tmpState) 1197 // } 1198 // 1199 // That is a slightly code-size-optimized version of 1200 // 1201 // if #stateVarN != abi.RF_READY { 1202 // #stateVarN = abi.RF_PANIC // If we ever need to specially detect "iterator swallowed checking panic" we put a different value here. 1203 // runtime.panicrangestate(#tmpState) 1204 // } 1205 // #stateVarN = abi.RF_PANIC 1206 // 1207 1208 tmpDecl, tmpState := r.declSingleVar("#tmpState", r.int.Type(), r.useObj(loop.stateVar)) 1209 bodyFunc.Body.List = append(bodyFunc.Body.List, tmpDecl) 1210 bodyFunc.Body.List = append(bodyFunc.Body.List, r.setState(abi.RF_PANIC, start)) 1211 bodyFunc.Body.List = append(bodyFunc.Body.List, r.assertReady(start, tmpState)) 1212 } 1213 1214 // Original loop body (already rewritten by editStmt during inspect). 1215 bodyFunc.Body.List = append(bodyFunc.Body.List, body...) 1216 1217 // end of loop body, set state to abi.RF_READY and return true to continue iteration 1218 if r.checkFuncMisuse() { 1219 bodyFunc.Body.List = append(bodyFunc.Body.List, r.setState(abi.RF_READY, end)) 1220 } 1221 ret := &syntax.ReturnStmt{Results: r.useObj(r.true)} 1222 ret.SetPos(end) 1223 bodyFunc.Body.List = append(bodyFunc.Body.List, ret) 1224 1225 return bodyFunc 1226 } 1227 1228 // checks returns the post-call checks that need to be done for the given loop. 1229 func (r *rewriter) checks(loop *forLoop, pos syntax.Pos) []syntax.Stmt { 1230 var list []syntax.Stmt 1231 if len(loop.checkBranch) > 0 { 1232 did := make(map[branch]bool) 1233 for _, br := range loop.checkBranch { 1234 if did[br] { 1235 continue 1236 } 1237 did[br] = true 1238 doBranch := &syntax.BranchStmt{Tok: br.tok, Label: &syntax.Name{Value: br.label}} 1239 list = append(list, r.ifNext(syntax.Eql, r.branchNext[br], true, doBranch)) 1240 } 1241 } 1242 1243 curLoop := loop.depth - 1 1244 curLoopIndex := curLoop - 1 1245 1246 if len(r.forStack) == 1 { 1247 if loop.checkRet { 1248 list = append(list, r.ifNext(syntax.Eql, -1, false, retStmt(nil))) 1249 } 1250 } else { 1251 1252 // Idealized check, implemented more simply for now. 1253 1254 // // N == depth of this loop, one less than the one just exited. 1255 // if #next != 0 { 1256 // if #next >= perLoopStep*N-1 { // this loop 1257 // if #next >= perLoopStep*N+1 { // error checking 1258 // runtime.panicrangestate(abi.RF_DONE) 1259 // } 1260 // rv := #next & 1 == 1 // code generates into #next&1 1261 // #next = 0 1262 // return rv 1263 // } 1264 // return false // or handle returns and gotos 1265 // } 1266 1267 if loop.checkRet { 1268 // Note: next < 0 also handles gotos handled by outer loops. 1269 // We set checkRet in that case to trigger this check. 1270 if r.checkFuncMisuse() { 1271 list = append(list, r.ifNext(syntax.Lss, 0, false, r.setStateAt(curLoopIndex, abi.RF_DONE), retStmt(r.useObj(r.false)))) 1272 } else { 1273 list = append(list, r.ifNext(syntax.Lss, 0, false, retStmt(r.useObj(r.false)))) 1274 } 1275 } 1276 1277 depthStep := perLoopStep * (curLoop) 1278 1279 if r.checkFuncMisuse() { 1280 list = append(list, r.ifNext(syntax.Gtr, depthStep, false, r.callPanic(pos, r.stateConst(abi.RF_DONE)))) 1281 } else { 1282 list = append(list, r.ifNext(syntax.Gtr, depthStep, true)) 1283 } 1284 1285 if r.checkFuncMisuse() { 1286 if loop.checkContinue { 1287 list = append(list, r.ifNext(syntax.Eql, depthStep-1, true, r.setStateAt(curLoopIndex, abi.RF_READY), retStmt(r.useObj(r.true)))) 1288 } 1289 1290 if loop.checkBreak { 1291 list = append(list, r.ifNext(syntax.Eql, depthStep, true, r.setStateAt(curLoopIndex, abi.RF_DONE), retStmt(r.useObj(r.false)))) 1292 } 1293 1294 if loop.checkContinue || loop.checkBreak { 1295 list = append(list, r.ifNext(syntax.Gtr, 0, false, r.setStateAt(curLoopIndex, abi.RF_DONE), retStmt(r.useObj(r.false)))) 1296 } 1297 1298 } else { 1299 if loop.checkContinue { 1300 list = append(list, r.ifNext(syntax.Eql, depthStep-1, true, retStmt(r.useObj(r.true)))) 1301 } 1302 if loop.checkBreak { 1303 list = append(list, r.ifNext(syntax.Eql, depthStep, true, retStmt(r.useObj(r.false)))) 1304 } 1305 if loop.checkContinue || loop.checkBreak { 1306 list = append(list, r.ifNext(syntax.Gtr, 0, false, retStmt(r.useObj(r.false)))) 1307 } 1308 } 1309 } 1310 1311 for _, j := range list { 1312 setPos(j, pos) 1313 } 1314 return list 1315 } 1316 1317 // retStmt returns a return statement returning the given return values. 1318 func retStmt(results syntax.Expr) *syntax.ReturnStmt { 1319 return &syntax.ReturnStmt{Results: results} 1320 } 1321 1322 // ifNext returns the statement: 1323 // 1324 // if #next op c { [#next = 0;] thens... } 1325 func (r *rewriter) ifNext(op syntax.Operator, c int, zeroNext bool, thens ...syntax.Stmt) syntax.Stmt { 1326 var thenList []syntax.Stmt 1327 if zeroNext { 1328 clr := &syntax.AssignStmt{ 1329 Lhs: r.next(), 1330 Rhs: r.intConst(0), 1331 } 1332 thenList = append(thenList, clr) 1333 } 1334 for _, then := range thens { 1335 thenList = append(thenList, then) 1336 } 1337 nif := &syntax.IfStmt{ 1338 Cond: r.cond(op, r.next(), r.intConst(c)), 1339 Then: &syntax.BlockStmt{ 1340 List: thenList, 1341 }, 1342 } 1343 return nif 1344 } 1345 1346 // setValueType marks x as a value with type typ. 1347 func setValueType(x syntax.Expr, typ syntax.Type) { 1348 tv := syntax.TypeAndValue{Type: typ} 1349 tv.SetIsValue() 1350 x.SetTypeInfo(tv) 1351 } 1352 1353 // assertReady returns the statement: 1354 // 1355 // if #tmpState != abi.RF_READY { runtime.panicrangestate(#tmpState) } 1356 func (r *rewriter) assertReady(start syntax.Pos, tmpState *types2.Var) syntax.Stmt { 1357 1358 nif := &syntax.IfStmt{ 1359 Cond: r.cond(syntax.Neq, r.useObj(tmpState), r.stateConst(abi.RF_READY)), 1360 Then: &syntax.BlockStmt{ 1361 List: []syntax.Stmt{ 1362 r.callPanic(start, r.useObj(tmpState))}, 1363 }, 1364 } 1365 setPos(nif, start) 1366 return nif 1367 } 1368 1369 func (r *rewriter) callPanic(start syntax.Pos, arg syntax.Expr) syntax.Stmt { 1370 callPanicExpr := &syntax.CallExpr{ 1371 Fun: runtimeSym(r.info, "panicrangestate"), 1372 ArgList: []syntax.Expr{arg}, 1373 } 1374 setValueType(callPanicExpr, nil) // no result type 1375 return &syntax.ExprStmt{X: callPanicExpr} 1376 } 1377 1378 // next returns a reference to the #next variable. 1379 func (r *rewriter) next() *syntax.Name { 1380 if r.nextVar == nil { 1381 r.nextVar = r.declOuterVar("#next", r.int.Type(), nil) 1382 } 1383 return r.useObj(r.nextVar) 1384 } 1385 1386 // forRangeFunc checks whether n is a range-over-func. 1387 // If so, it returns n.(*syntax.ForStmt), true. 1388 // Otherwise it returns nil, false. 1389 func forRangeFunc(n syntax.Node) (*syntax.ForStmt, bool) { 1390 nfor, ok := n.(*syntax.ForStmt) 1391 if !ok { 1392 return nil, false 1393 } 1394 nrange, ok := nfor.Init.(*syntax.RangeClause) 1395 if !ok { 1396 return nil, false 1397 } 1398 _, ok = types2.CoreType(nrange.X.GetTypeInfo().Type).(*types2.Signature) 1399 if !ok { 1400 return nil, false 1401 } 1402 return nfor, true 1403 } 1404 1405 // intConst returns syntax for an integer literal with the given value. 1406 func (r *rewriter) intConst(c int) *syntax.BasicLit { 1407 lit := &syntax.BasicLit{ 1408 Value: fmt.Sprint(c), 1409 Kind: syntax.IntLit, 1410 } 1411 tv := syntax.TypeAndValue{Type: r.int.Type(), Value: constant.MakeInt64(int64(c))} 1412 tv.SetIsValue() 1413 lit.SetTypeInfo(tv) 1414 return lit 1415 } 1416 1417 func (r *rewriter) stateConst(s abi.RF_State) *syntax.BasicLit { 1418 return r.intConst(int(s)) 1419 } 1420 1421 // useObj returns syntax for a reference to decl, which should be its declaration. 1422 func (r *rewriter) useObj(obj types2.Object) *syntax.Name { 1423 n := syntax.NewName(nopos, obj.Name()) 1424 tv := syntax.TypeAndValue{Type: obj.Type()} 1425 tv.SetIsValue() 1426 n.SetTypeInfo(tv) 1427 r.info.Uses[n] = obj 1428 return n 1429 } 1430 1431 // useList is useVar for a list of decls. 1432 func (r *rewriter) useList(vars []types2.Object) syntax.Expr { 1433 var new []syntax.Expr 1434 for _, obj := range vars { 1435 new = append(new, r.useObj(obj)) 1436 } 1437 if len(new) == 1 { 1438 return new[0] 1439 } 1440 return &syntax.ListExpr{ElemList: new} 1441 } 1442 1443 func (r *rewriter) makeVarName(pos syntax.Pos, name string, typ types2.Type) (*types2.Var, *syntax.Name) { 1444 obj := types2.NewVar(pos, r.pkg, name, typ) 1445 n := syntax.NewName(pos, name) 1446 tv := syntax.TypeAndValue{Type: typ} 1447 tv.SetIsValue() 1448 n.SetTypeInfo(tv) 1449 r.info.Defs[n] = obj 1450 return obj, n 1451 } 1452 1453 func (r *rewriter) generateParamName(results []*syntax.Field, i int) { 1454 obj, n := r.sig.RenameResult(results, i) 1455 r.info.Defs[n] = obj 1456 } 1457 1458 // declOuterVar declares a variable with a given name, type, and initializer value, 1459 // in the same scope as the outermost loop in a loop nest. 1460 func (r *rewriter) declOuterVar(name string, typ types2.Type, init syntax.Expr) *types2.Var { 1461 if r.declStmt == nil { 1462 r.declStmt = &syntax.DeclStmt{} 1463 } 1464 stmt := r.declStmt 1465 obj, n := r.makeVarName(stmt.Pos(), name, typ) 1466 stmt.DeclList = append(stmt.DeclList, &syntax.VarDecl{ 1467 NameList: []*syntax.Name{n}, 1468 // Note: Type is ignored 1469 Values: init, 1470 }) 1471 return obj 1472 } 1473 1474 // declSingleVar declares a variable with a given name, type, and initializer value, 1475 // and returns both the declaration and variable, so that the declaration can be placed 1476 // in a specific scope. 1477 func (r *rewriter) declSingleVar(name string, typ types2.Type, init syntax.Expr) (*syntax.DeclStmt, *types2.Var) { 1478 stmt := &syntax.DeclStmt{} 1479 obj, n := r.makeVarName(stmt.Pos(), name, typ) 1480 stmt.DeclList = append(stmt.DeclList, &syntax.VarDecl{ 1481 NameList: []*syntax.Name{n}, 1482 // Note: Type is ignored 1483 Values: init, 1484 }) 1485 return stmt, obj 1486 } 1487 1488 // runtimePkg is a fake runtime package that contains what we need to refer to in package runtime. 1489 var runtimePkg = func() *types2.Package { 1490 var nopos syntax.Pos 1491 pkg := types2.NewPackage("runtime", "runtime") 1492 anyType := types2.Universe.Lookup("any").Type() 1493 intType := types2.Universe.Lookup("int").Type() 1494 1495 // func deferrangefunc() unsafe.Pointer 1496 obj := types2.NewFunc(nopos, pkg, "deferrangefunc", types2.NewSignatureType(nil, nil, nil, nil, types2.NewTuple(types2.NewParam(nopos, pkg, "extra", anyType)), false)) 1497 pkg.Scope().Insert(obj) 1498 1499 // func panicrangestate() 1500 obj = types2.NewFunc(nopos, pkg, "panicrangestate", types2.NewSignatureType(nil, nil, nil, types2.NewTuple(types2.NewParam(nopos, pkg, "state", intType)), nil, false)) 1501 pkg.Scope().Insert(obj) 1502 1503 return pkg 1504 }() 1505 1506 // runtimeSym returns a reference to a symbol in the fake runtime package. 1507 func runtimeSym(info *types2.Info, name string) *syntax.Name { 1508 obj := runtimePkg.Scope().Lookup(name) 1509 n := syntax.NewName(nopos, "runtime."+name) 1510 tv := syntax.TypeAndValue{Type: obj.Type()} 1511 tv.SetIsValue() 1512 tv.SetIsRuntimeHelper() 1513 n.SetTypeInfo(tv) 1514 info.Uses[n] = obj 1515 return n 1516 } 1517 1518 // setPos walks the top structure of x that has no position assigned 1519 // and assigns it all to have position pos. 1520 // When setPos encounters a syntax node with a position assigned, 1521 // setPos does not look inside that node. 1522 // setPos only needs to handle syntax we create in this package; 1523 // all other syntax should have positions assigned already. 1524 func setPos(x syntax.Node, pos syntax.Pos) { 1525 if x == nil { 1526 return 1527 } 1528 syntax.Inspect(x, func(n syntax.Node) bool { 1529 if n == nil || n.Pos() != nopos { 1530 return false 1531 } 1532 n.SetPos(pos) 1533 switch n := n.(type) { 1534 case *syntax.BlockStmt: 1535 if n.Rbrace == nopos { 1536 n.Rbrace = pos 1537 } 1538 } 1539 return true 1540 }) 1541 } 1542