Imports #
"cmd/compile/internal/base"
"cmd/compile/internal/syntax"
"cmd/compile/internal/types2"
"fmt"
"go/constant"
"internal/abi"
"os"
"cmd/compile/internal/base"
"cmd/compile/internal/syntax"
"cmd/compile/internal/types2"
"fmt"
"go/constant"
"internal/abi"
"os"
nopos is the zero syntax.Pos.
var nopos syntax.PosperLoopStep is part of the encoding of loop-spanning control flow for function range iterators. Each multiple of two encodes a "return false" passing control to an enclosing iterator; a terminal value of 1 encodes "return true" (i.e., local continue) from the body function, and a terminal value of 0 encodes executing the remainder of the body function.
const perLoopStep = 2runtimePkg is a fake runtime package that contains what we need to refer to in package runtime.
var runtimePkg = *ast.CallExprtype State intA branch is a single labeled branch.
type branch struct {
tok syntax.Token
label string
}A forLoop describes a single range-over-func loop being processed.
type forLoop struct {
nfor *syntax.ForStmt
stateVar *types2.Var
stateVarDecl *syntax.VarDecl
depth int
checkRet bool
checkBreak bool
checkContinue bool
checkBranch []branch
}A rewriter implements rewriting the range-over-funcs in a given function.
type rewriter struct {
pkg *types2.Package
info *types2.Info
sig *types2.Signature
outer *syntax.FuncType
body *syntax.BlockStmt
any types2.Object
bool types2.Object
int types2.Object
true types2.Object
false types2.Object
branchNext map[branch]int
labelLoop map[string]*syntax.ForStmt
stack []syntax.Node
forStack []*forLoop
rewritten map[*syntax.ForStmt]syntax.Stmt
declStmt *syntax.DeclStmt
nextVar types2.Object
defers types2.Object
stateVarCount int
bodyClosureCount int
rangefuncBodyClosures map[*syntax.FuncLit]bool
}Rewrite rewrites all the range-over-funcs in the files. It returns the set of function literals generated from rangefunc loop bodies. This allows for rangefunc loop bodies to be distinguished by debuggers.
func Rewrite(pkg *types2.Package, info *types2.Info, files []*syntax.File) map[*syntax.FuncLit]boolassertReady returns the statement: if #tmpState != abi.RF_READY { runtime.panicrangestate(#tmpState) }
func (r *rewriter) assertReady(start syntax.Pos, tmpState *types2.Var) syntax.StmtbodyFunc converts the loop body (control flow has already been updated) to a func literal that can be passed to the range function. vars is the range variables from the range statement. def indicates whether this is a := range statement. ftyp is the type of the function we are creating start and end are the syntax positions to use for new nodes that should be at the start or end of the loop.
func (r *rewriter) bodyFunc(body []syntax.Stmt, lhs []syntax.Expr, def bool, ftyp *types2.Signature, start syntax.Pos, end syntax.Pos) *syntax.FuncLitfunc (r *rewriter) callPanic(start syntax.Pos, arg syntax.Expr) syntax.StmtcheckFuncMisuse reports whether to check for misuse of iterator callbacks functions.
func (r *rewriter) checkFuncMisuse() boolchecks returns the post-call checks that need to be done for the given loop.
func (r *rewriter) checks(loop *forLoop, pos syntax.Pos) []syntax.StmtcomputeBranchNext computes the branchNext numbering and determines which labels end up inside which range-over-func loop bodies.
func (r *rewriter) computeBranchNext()func (r *rewriter) cond(op syntax.Operator, x syntax.Expr, y syntax.Expr) *syntax.OperationdeclOuterVar declares a variable with a given name, type, and initializer value, in the same scope as the outermost loop in a loop nest.
func (r *rewriter) declOuterVar(name string, typ types2.Type, init syntax.Expr) *types2.VardeclSingleVar declares a variable with a given name, type, and initializer value, and returns both the declaration and variable, so that the declaration can be placed in a specific scope.
func (r *rewriter) declSingleVar(name string, typ types2.Type, init syntax.Expr) (*syntax.DeclStmt, *types2.Var)editBranch returns the replacement for the branch statement x, or x itself if it should be left alone. See the package doc comment above for more context.
func (r *rewriter) editBranch(x *syntax.BranchStmt) syntax.StmteditDefer returns the replacement for the defer statement x. See the "Defers" section in the package doc comment above for more context.
func (r *rewriter) editDefer(x *syntax.CallStmt) syntax.StmteditReturn returns the replacement for the return statement x. See the "Return" section in the package doc comment above for more context.
func (r *rewriter) editReturn(x *syntax.ReturnStmt) syntax.StmteditStmt returns the replacement for the statement x, or x itself if it should be left alone. This includes the for loops we are converting, as left in x.rewritten by r.endLoop.
func (r *rewriter) editStmt(x syntax.Stmt) syntax.StmtendLoop finishes the conversion of a range-over-func loop. We have inspected and rewritten the body of the loop and can now construct the body function and rewrite the for loop into a call bracketed by any declarations and checks it requires.
func (r *rewriter) endLoop(loop *forLoop)forRangeFunc checks whether n is a range-over-func. If so, it returns n.(*syntax.ForStmt), true. Otherwise it returns nil, false.
func forRangeFunc(n syntax.Node) (*syntax.ForStmt, bool)func (r *rewriter) generateParamName(results []*syntax.Field, i int)ifNext returns the statement: if #next op c { [#next = 0;] thens... }
func (r *rewriter) ifNext(op syntax.Operator, c int, zeroNext bool, thens ...syntax.Stmt) syntax.Stmtinspect is a callback for syntax.Inspect that drives the actual rewriting. If it sees a func literal, it kicks off a separate rewrite for that literal. Otherwise, it maintains a stack of range-over-func loops and converts each in turn.
func (r *rewriter) inspect(n syntax.Node) boolintConst returns syntax for an integer literal with the given value.
func (r *rewriter) intConst(c int) *syntax.BasicLitfunc (r *rewriter) makeVarName(pos syntax.Pos, name string, typ types2.Type) (*types2.Var, *syntax.Name)next returns a reference to the #next variable.
func (r *rewriter) next() *syntax.NameretStmt returns a return statement returning the given return values.
func retStmt(results syntax.Expr) *syntax.ReturnStmtrewriteFunc rewrites all the range-over-funcs in a single function (a top-level func or a func literal). The typ and body are the function's type and body.
func rewriteFunc(pkg *types2.Package, info *types2.Info, typ *syntax.FuncType, body *syntax.BlockStmt, sig *types2.Signature, ri map[*syntax.FuncLit]bool)runtimeSym returns a reference to a symbol in the fake runtime package.
func runtimeSym(info *types2.Info, name string) *syntax.NamesetPos walks the top structure of x that has no position assigned and assigns it all to have position pos. When setPos encounters a syntax node with a position assigned, setPos does not look inside that node. setPos only needs to handle syntax we create in this package; all other syntax should have positions assigned already.
func setPos(x syntax.Node, pos syntax.Pos)func (r *rewriter) setState(val abi.RF_State, pos syntax.Pos) *syntax.AssignStmtfunc (r *rewriter) setStateAt(index int, stateVal abi.RF_State) *syntax.AssignStmtsetValueType marks x as a value with type typ.
func setValueType(x syntax.Expr, typ syntax.Type)startLoop sets up for converting a range-over-func loop.
func (r *rewriter) startLoop(loop *forLoop)func (r *rewriter) stateConst(s abi.RF_State) *syntax.BasicLitfunc (r *rewriter) stateVar(pos syntax.Pos) (*types2.Var, *syntax.VarDecl)useList is useVar for a list of decls.
func (r *rewriter) useList(vars []types2.Object) syntax.ExpruseObj returns syntax for a reference to decl, which should be its declaration.
func (r *rewriter) useObj(obj types2.Object) *syntax.NameGenerated with Arrow