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