]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: give the closure generated for rangefunc bodies a name.
authorDavid Chase <drchase@google.com>
Wed, 12 Jun 2024 15:13:26 +0000 (11:13 -0400)
committerDavid Chase <drchase@google.com>
Fri, 14 Jun 2024 17:20:58 +0000 (17:20 +0000)
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 <thanm@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Alessandro Arzilli <alessandro.arzilli@gmail.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
src/cmd/compile/internal/rangefunc/rewrite.go

index 2dcdc3f018780cffe16302a2c49295c1902f942f..e5a0b9f8af141780bed94fd39b6c7ec8971c4201 100644 (file)
@@ -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