From afaeb12586d562ac8e3b2d55af61e3a4eeef4109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Efe=20G=C3=B6kdemir?= Date: Sat, 7 Nov 2026 05:57:02 +0300 Subject: [PATCH] Fix removal of closed upvalues --- stack.go | 4 +++- stack_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 stack_test.go diff --git a/stack.go b/stack.go index 2616638..9bb5178 100644 --- a/stack.go +++ b/stack.go @@ -106,7 +106,7 @@ func (l *State) newUpValueAt(level int) *upValue { func (l *State) close(level int) { // TODO this seems really inefficient - how can we terminate early? var p *openUpValue - for e := l.upValues; e != nil; e, p = e.next, e { + for e := l.upValues; e != nil; e = e.next { if e.upValue.isInStackAbove(level) { e.upValue.close() if p != nil { @@ -114,6 +114,8 @@ func (l *State) close(level int) { } else { l.upValues = e.next } + } else { + p = e } } } diff --git a/stack_test.go b/stack_test.go new file mode 100644 index 0000000..dc991a1 --- /dev/null +++ b/stack_test.go @@ -0,0 +1,29 @@ +package lua + +import "testing" + +func TestCloseUnlinksAdjacentClosedUpValues(t *testing.T) { + l := NewState() + l.stack[1] = "kept open" + l.stack[2] = "closed first" + l.stack[3] = "closed second" + + kept := l.newUpValueAt(1) + closedFirst := l.newUpValueAt(2) + closedSecond := l.newUpValueAt(3) + + l.close(2) + + if got := closedFirst.value(); got != "closed first" { + t.Errorf("first closed upvalue = %v, want %q", got, "closed first") + } + if got := closedSecond.value(); got != "closed second" { + t.Errorf("second closed upvalue = %v, want %q", got, "closed second") + } + if !kept.isInStackAt(1) { + t.Fatal("upvalue below the closing level was closed") + } + if l.upValues == nil || l.upValues.upValue != kept || l.upValues.next != nil { + t.Error("closed upvalues remain in the open upvalue list") + } +}