From f27a40ce5fbb2574b81cf05c61c6630e0dfcaf4a Mon Sep 17 00:00:00 2001 From: David Chase Date: Wed, 12 Jun 2024 11:13:26 -0400 Subject: [PATCH] cmd/compile: give the closure generated for rangefunc bodies a name. The generated name has the form "#yield%d" for %d = 1, 2, 3, ... This may help the debugger connect execution within a rangefunc loop's body to the frame containing the rest of the source code. (It may not actually be necessary; we need to confirm with Alessandro Aarzilli or someone else on the Delve team.) Change-Id: Iabbb2ea5604a4bc1558c160819ac80197e1f2242 Reviewed-on: https://go-review.googlesource.com/c/go/+/592175 Reviewed-by: Than McIntosh LUCI-TryBot-Result: Go LUCI Reviewed-by: Alessandro Arzilli Reviewed-by: Cherry Mui --- src/cmd/compile/internal/rangefunc/rewrite.go | 44 ++++++++++++++----- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/src/cmd/compile/internal/rangefunc/rewrite.go b/src/cmd/compile/internal/rangefunc/rewrite.go index 2dcdc3f018..e5a0b9f8af 100644 --- a/src/cmd/compile/internal/rangefunc/rewrite.go +++ b/src/cmd/compile/internal/rangefunc/rewrite.go @@ -566,11 +566,11 @@ type rewriter struct { rewritten map[*syntax.ForStmt]syntax.Stmt // Declared variables in generated code for outermost loop. - declStmt *syntax.DeclStmt - nextVar types2.Object - retVars []types2.Object - defers types2.Object - stateVarCount int // stateVars are referenced from their respective loops + declStmt *syntax.DeclStmt + nextVar types2.Object + defers types2.Object + stateVarCount int // stateVars are referenced from their respective loops + bodyClosureCount int // to help the debugger, the closures generated for loop bodies get names rangefuncBodyClosures map[*syntax.FuncLit]bool } @@ -764,7 +764,7 @@ func (r *rewriter) editDefer(x *syntax.CallStmt) syntax.Stmt { tv := syntax.TypeAndValue{Type: r.any.Type()} tv.SetIsValue() init.SetTypeInfo(tv) - r.defers = r.declVar("#defers", r.any.Type(), init) + r.defers = r.declOuterVar("#defers", r.any.Type(), init) } // Attach the token as an "extra" argument to the defer. @@ -1033,12 +1033,18 @@ func (r *rewriter) endLoop(loop *forLoop) { base.Fatalf("invalid typecheck of range func") } + // Give the closure generated for the body a name, to help the debugger connect it to its frame, if active. + r.bodyClosureCount++ + clo := r.bodyFunc(nfor.Body.List, syntax.UnpackListExpr(rclause.Lhs), rclause.Def, ftyp, start, end) + cloDecl, cloVar := r.declSingleVar(fmt.Sprintf("#yield%d", r.bodyClosureCount), clo.GetTypeInfo().Type, clo) + setPos(cloDecl, start) + // Build X(bodyFunc) call := &syntax.ExprStmt{ X: &syntax.CallExpr{ Fun: rclause.X, ArgList: []syntax.Expr{ - r.bodyFunc(nfor.Body.List, syntax.UnpackListExpr(rclause.Lhs), rclause.Def, ftyp, start, end), + r.useObj(cloVar), }, }, } @@ -1073,7 +1079,7 @@ func (r *rewriter) endLoop(loop *forLoop) { } // iteratorFunc(bodyFunc) - block.List = append(block.List, call) + block.List = append(block.List, cloDecl, call) if r.checkFuncMisuse() { // iteratorFunc has exited, check for swallowed panic, and set body state to abi.RF_EXHAUSTED @@ -1092,7 +1098,6 @@ func (r *rewriter) endLoop(loop *forLoop) { if len(r.forStack) == 1 { // ending an outermost loop r.declStmt = nil r.nextVar = nil - r.retVars = nil r.defers = nil } @@ -1348,7 +1353,7 @@ func (r *rewriter) callPanic(start syntax.Pos, arg syntax.Expr) syntax.Stmt { // next returns a reference to the #next variable. func (r *rewriter) next() *syntax.Name { if r.nextVar == nil { - r.nextVar = r.declVar("#next", r.int.Type(), nil) + r.nextVar = r.declOuterVar("#next", r.int.Type(), nil) } return r.useObj(r.nextVar) } @@ -1425,8 +1430,9 @@ func (r *rewriter) generateParamName(results []*syntax.Field, i int) { r.info.Defs[n] = obj } -// declVar declares a variable with a given name type and initializer value. -func (r *rewriter) declVar(name string, typ types2.Type, init syntax.Expr) *types2.Var { +// declOuterVar 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.Var { if r.declStmt == nil { r.declStmt = &syntax.DeclStmt{} } @@ -1440,6 +1446,20 @@ func (r *rewriter) declVar(name string, typ types2.Type, init syntax.Expr) *type return obj } +// declSingleVar 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) { + stmt := &syntax.DeclStmt{} + obj, n := r.makeVarName(stmt.Pos(), name, typ) + stmt.DeclList = append(stmt.DeclList, &syntax.VarDecl{ + NameList: []*syntax.Name{n}, + // Note: Type is ignored + Values: init, + }) + return stmt, obj +} + // runtimePkg is a fake runtime package that contains what we need to refer to in package runtime. var runtimePkg = func() *types2.Package { var nopos syntax.Pos -- 2.48.1