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

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

View as plain text