Fix block capture sync for bytecode locals

This commit is contained in:
Sergey Chernov 2026-01-30 15:39:03 +03:00
parent 89cf2c1612
commit ecf64dcbc3
3 changed files with 17 additions and 15 deletions

View File

@ -2116,6 +2116,7 @@ class BytecodeCompiler(
compileRefWithFallback(ref, null, target.pos)
}
}
is VarDeclStatement -> emitVarDecl(target)
is IfStatement -> compileIfStatement(target)
is net.sergeych.lyng.ForInStatement -> {
val resultSlot = emitForIn(target, false) ?: return null

View File

@ -1522,6 +1522,19 @@ class CmdFrame(
}
}
private fun shouldSyncLocalCaptures(captures: List<String>): Boolean {
if (captures.isEmpty()) return false
val localNames = fn.localSlotNames
if (localNames.isEmpty()) return false
for (capture in captures) {
for (local in localNames) {
if (local == null) continue
if (local == capture) return true
}
}
return false
}
private fun resolveModuleScope(scope: Scope): Scope {
var current: Scope? = scope
var last: Scope = scope
@ -1545,7 +1558,7 @@ class CmdFrame(
} else {
emptyList()
}
if (captures.isNotEmpty() && fn.localSlotNames.isNotEmpty()) {
if (shouldSyncLocalCaptures(captures)) {
syncFrameToScope()
}
if (scope.skipScopeCreation) {
@ -1584,8 +1597,8 @@ class CmdFrame(
?: error("Scope stack underflow in POP_SCOPE")
val captures = captureStack.removeLastOrNull() ?: emptyList()
scopeDepth -= 1
if (captures.isNotEmpty() && fn.localSlotNames.isNotEmpty()) {
syncScopeToFrame()
if (shouldSyncLocalCaptures(captures)) {
syncFrameToScope()
}
}

View File

@ -131,7 +131,6 @@ class ScriptTest {
}
// --- Helpers to test iterator cancellation semantics ---
@Ignore
class ObjTestIterable : Obj() {
var cancelCount: Int = 0
@ -148,7 +147,6 @@ class ScriptTest {
}
}
@Ignore
class ObjTestIterator(private val owner: ObjTestIterable) : Obj() {
override val objClass: ObjClass = type
private var i = 0
@ -171,7 +169,6 @@ class ScriptTest {
}
}
@Ignore("Scope.eval should seed compile-time symbols from current scope")
@Test
fun testForLoopDoesNotCancelOnNaturalCompletion() = runTest {
val scope = Script.newScope()
@ -189,7 +186,6 @@ class ScriptTest {
assertEquals(0, ti.cancelCount)
}
@Ignore("incremental enable")
@Test
fun testForLoopCancelsOnBreak() = runTest {
val scope = Script.newScope()
@ -205,7 +201,6 @@ class ScriptTest {
assertEquals(1, ti.cancelCount)
}
@Ignore("incremental enable")
@Test
fun testForLoopCancelsOnException() = runTest {
val scope = Script.newScope()
@ -384,7 +379,6 @@ class ScriptTest {
assertTrue(eval("sin(π)").toDouble() - 1 < 0.000001)
}
@Ignore("Scope.eval should seed compile-time symbols from current scope")
@Test
fun varsAndConstsTest() = runTest {
val scope = Scope(pos = Pos.builtIn)
@ -406,7 +400,6 @@ class ScriptTest {
assertEquals(5, scope.eval("b").toInt())
}
@Ignore("incremental enable")
@Test
fun functionTest() = runTest {
val scope = Scope(pos = Pos.builtIn)
@ -433,7 +426,6 @@ class ScriptTest {
assertEquals(14, scope.eval("bar(3)").toInt())
}
@Ignore("incremental enable")
@Test
fun simpleClosureTest() = runTest {
val scope = Scope(pos = Pos.builtIn)
@ -559,7 +551,6 @@ class ScriptTest {
assertFalse { eval("4 <= 3").toBool() }
}
@Ignore("incremental enable")
@Test
fun ifTest() = runTest {
// if - single line
@ -759,7 +750,6 @@ class ScriptTest {
assertEquals(ObjInt(5), c["c"]?.value)
}
@Ignore("Scope.eval should seed compile-time symbols from current scope")
@Test
fun testAssignArgumentsEndEllipsis() = runTest {
// equal args,
@ -787,7 +777,6 @@ class ScriptTest {
c.eval("assert( b == [] )")
}
@Ignore("incremental enable")
@Test
fun testAssignArgumentsStartEllipsis() = runTest {
val ttEnd = Token.Type.RBRACE
@ -822,7 +811,6 @@ class ScriptTest {
}
}
@Ignore("incremental enable")
@Test
fun testAssignArgumentsMiddleEllipsis() = runTest {
val ttEnd = Token.Type.RBRACE