From ef5440f0dc1f0fdbf2f9c65a41a28f9aef5cdd8d Mon Sep 17 00:00:00 2001 From: Natasha Kerensikova Date: Sat, 22 Mar 2025 14:33:29 +0100 Subject: [PATCH] Issue #514 : Fix compileRegAssignment cardinality Use `nvars` as the assignment numbers rather than `lennames`. This makes no difference in `compileLocalAssignStmt` as the numbers are equal, but in `compileGenericForStmt` the names are the iteration variables while `nvars` refers to the local generator, state, and control. The iteration variables feel a bit out of place here. The whole body of `compileRegAssignment` seem inconsistent, using `names` only for its length, and mixing `lennames` and `nvars` in surprising ways. Moreover the function name `compileRegAssignment` suggests assigning to registers rather than names, so I dropped `lennames` entirely to use only `nvars`. --- _glua-tests/issues.lua | 19 +++++++++++++++++++ compile.go | 17 ++++++++--------- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/_glua-tests/issues.lua b/_glua-tests/issues.lua index 6d6343ab..1debb7e5 100644 --- a/_glua-tests/issues.lua +++ b/_glua-tests/issues.lua @@ -490,3 +490,22 @@ function test() assert(b == nil) end test() + +-- issue #514 +function test() + local tbl = {foo = 42, bar = "baz"} + local iter = function(s,k) + k,_ = next(tbl, k) + return k + end + local seen1, seen2 = {}, {} + for item in iter do + seen1[item] = true + end + for item in iter do + seen2[item] = true + end + assert(seen1.foo and seen1.bar) + assert(seen2.foo and seen2.bar) +end +test() diff --git a/compile.go b/compile.go index e46e0d75..e9208599 100644 --- a/compile.go +++ b/compile.go @@ -812,20 +812,19 @@ func compileAssignStmt(context *funcContext, stmt *ast.AssignStmt) { // {{{ } } // }}} -func compileRegAssignment(context *funcContext, names []string, exprs []ast.Expr, reg int, nvars int, line int) { // {{{ - lennames := len(names) +func compileRegAssignment(context *funcContext, exprs []ast.Expr, reg int, nvars int, line int) { // {{{ lenexprs := len(exprs) namesassigned := 0 ec := &expcontext{} - for namesassigned < lennames && namesassigned < lenexprs { + for namesassigned < nvars && namesassigned < lenexprs { if isVarArgReturnExpr(exprs[namesassigned]) && (lenexprs-namesassigned-1) <= 0 { varargopt := nvars - namesassigned ecupdate(ec, ecVararg, reg, varargopt-1) compileExpr(context, reg, exprs[namesassigned], ec) reg += varargopt - namesassigned = lennames + namesassigned = nvars } else { ecupdate(ec, ecLocal, reg, 0) compileExpr(context, reg, exprs[namesassigned], ec) @@ -835,8 +834,8 @@ func compileRegAssignment(context *funcContext, names []string, exprs []ast.Expr } // extra left names - if lennames > namesassigned { - restleft := lennames - namesassigned - 1 + if nvars > namesassigned { + restleft := nvars - namesassigned - 1 context.Code.AddLoadNil(reg, reg+restleft, line) reg += restleft } @@ -857,12 +856,12 @@ func compileLocalAssignStmt(context *funcContext, stmt *ast.LocalAssignStmt) { / if len(stmt.Names) == 1 && len(stmt.Exprs) == 1 { if _, ok := stmt.Exprs[0].(*ast.FunctionExpr); ok { context.RegisterLocalVar(stmt.Names[0]) - compileRegAssignment(context, stmt.Names, stmt.Exprs, reg, len(stmt.Names), sline(stmt)) + compileRegAssignment(context, stmt.Exprs, reg, len(stmt.Names), sline(stmt)) return } } - compileRegAssignment(context, stmt.Names, stmt.Exprs, reg, len(stmt.Names), sline(stmt)) + compileRegAssignment(context, stmt.Exprs, reg, len(stmt.Names), sline(stmt)) for _, name := range stmt.Names { context.RegisterLocalVar(name) } @@ -1100,7 +1099,7 @@ func compileGenericForStmt(context *funcContext, stmt *ast.GenericForStmt) { // context.RegisterLocalVar("(for state)") context.RegisterLocalVar("(for control)") - compileRegAssignment(context, stmt.Names, stmt.Exprs, context.RegTop()-3, 3, sline(stmt)) + compileRegAssignment(context, stmt.Exprs, context.RegTop()-3, 3, sline(stmt)) code.AddASbx(OP_JMP, 0, fllabel, sline(stmt))