Fix loop scoping in bytecode and unignore ScriptTests

This commit is contained in:
Sergey Chernov 2026-01-30 23:46:25 +03:00
parent d363501081
commit 8f60a84e3b
3 changed files with 42 additions and 8 deletions

View File

@ -101,11 +101,16 @@ class Compiler(
private fun moduleSlotPlan(): SlotPlan? = slotPlanStack.firstOrNull()
private fun seedSlotPlanFromScope(scope: Scope) {
private fun seedSlotPlanFromScope(scope: Scope, includeParents: Boolean = false) {
val plan = moduleSlotPlan() ?: return
for ((name, record) in scope.objects) {
if (!record.visibility.isPublic) continue
declareSlotNameIn(plan, name, record.isMutable, record.type == ObjRecord.Type.Delegated)
var current: Scope? = scope
while (current != null) {
for ((name, record) in current.objects) {
if (!record.visibility.isPublic) continue
declareSlotNameIn(plan, name, record.isMutable, record.type == ObjRecord.Type.Delegated)
}
if (!includeParents) return
current = current.parent
}
}
@ -399,6 +404,9 @@ class Compiler(
return LocalVarRef(name, pos)
}
resolutionSink?.reference(name, pos)
seedScope?.chainLookupIgnoreClosure(name)?.let {
return LocalVarRef(name, pos)
}
if (allowUnresolvedRefs || (name.isNotEmpty() && name[0].isUpperCase())) {
return LocalVarRef(name, pos)
}

View File

@ -2575,6 +2575,12 @@ class BytecodeCompiler(
rangeRef = extractRangeFromLocal(stmt.source)
}
val typedRangeLocal = if (range == null && rangeRef == null) extractTypedRangeLocal(stmt.source) else null
val useLoopScope = stmt.loopSlotPlan.isNotEmpty()
val planId = if (useLoopScope) {
builder.addConst(BytecodeConst.SlotPlan(stmt.loopSlotPlan, emptyList()))
} else {
-1
}
val loopLocalIndex = localSlotIndexByName[stmt.loopVarName]
var usedOverride = false
val loopSlotId = when {
@ -2631,6 +2637,10 @@ class BytecodeCompiler(
val loopLabel = builder.label()
val continueLabel = builder.label()
val endLabel = builder.label()
if (useLoopScope) {
builder.emit(Opcode.PUSH_SCOPE, planId)
resetAddrCache()
}
builder.mark(loopLabel)
val hasNextSlot = allocSlot()
@ -2694,6 +2704,10 @@ class BytecodeCompiler(
}
builder.mark(afterElse)
}
if (useLoopScope) {
builder.emit(Opcode.POP_SCOPE)
resetAddrCache()
}
return resultSlot
}
@ -2739,6 +2753,10 @@ class BytecodeCompiler(
val continueLabel = builder.label()
val endLabel = builder.label()
val doneLabel = builder.label()
if (useLoopScope) {
builder.emit(Opcode.PUSH_SCOPE, planId)
resetAddrCache()
}
builder.mark(loopLabel)
val cmpSlot = allocSlot()
builder.emit(Opcode.CMP_GTE_INT, iSlot, endSlot, cmpSlot)
@ -2786,6 +2804,10 @@ class BytecodeCompiler(
}
builder.mark(afterElse)
}
if (useLoopScope) {
builder.emit(Opcode.POP_SCOPE)
resetAddrCache()
}
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(doneLabel)))
builder.mark(badRangeLabel)
val msgId = builder.addConst(BytecodeConst.StringVal("expected Int range"))
@ -2808,6 +2830,10 @@ class BytecodeCompiler(
val loopLabel = builder.label()
val continueLabel = builder.label()
val endLabel = builder.label()
if (useLoopScope) {
builder.emit(Opcode.PUSH_SCOPE, planId)
resetAddrCache()
}
builder.mark(loopLabel)
val cmpSlot = allocSlot()
builder.emit(Opcode.CMP_GTE_INT, iSlot, endSlot, cmpSlot)
@ -2855,6 +2881,10 @@ class BytecodeCompiler(
}
builder.mark(afterElse)
}
if (useLoopScope) {
builder.emit(Opcode.POP_SCOPE)
resetAddrCache()
}
return resultSlot
} finally {
if (usedOverride) {

View File

@ -905,7 +905,6 @@ class ScriptTest {
eval(code)
}
@Ignore("bytecode fallback in labeled break")
@Test
fun whileNonLocalBreakTest() = runTest {
assertEquals(
@ -3752,7 +3751,6 @@ class ScriptTest {
)
}
@Ignore("incremental enable: closure capture in acc?.let { acc + f(x) } mis-evaluates")
@Test
fun testThisInClosure() = runTest {
eval(
@ -4428,7 +4426,6 @@ class ScriptTest {
println(r)
}
@Ignore("incremental enable: parent scope capture for child eval not wired")
@Test
fun testScopeShortCircuit() = runTest() {
val baseScope = Script.newScope()
@ -4862,7 +4859,6 @@ class ScriptTest {
assertContains(x1.message!!, "tc2")
}
@Ignore("incremental enable: filtered stack trace missing source frame")
@Test
fun testFilterStackTrace() = runTest {
var x = try {