Source file src/cmd/compile/internal/rangefunc/rewrite.go

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

View as plain text