Fix for-loop real widening coercions

This commit is contained in:
Sergey Chernov 2026-02-16 16:53:53 +03:00
parent fd2da1efd3
commit a8f6aa31f1
3 changed files with 57 additions and 0 deletions

View File

@ -6002,6 +6002,11 @@ class BytecodeCompiler(
try {
val needsBreakFlag = stmt.canBreak || stmt.elseStatement != null
val realWidenSlots = collectLoopRealWidenSlots(stmt.body)
val hasRealWiden = realWidenSlots.isNotEmpty()
if (hasRealWiden) {
applySlotTypes(realWidenSlots, SlotType.REAL)
}
val breakFlagSlot = allocSlot()
if (range == null && rangeRef == null && typedRangeLocal == null) {
val sourceValue = compileStatementValueOrFallback(stmt.source) ?: return null
@ -6075,12 +6080,18 @@ class BytecodeCompiler(
)
)
val bodyValue = compileLoopBody(stmt.body, wantResult) ?: return null
if (hasRealWiden) {
applySlotTypes(realWidenSlots, SlotType.UNKNOWN)
}
loopStack.removeLast()
if (wantResult) {
val bodyObj = ensureObjSlot(bodyValue)
builder.emit(Opcode.MOVE_OBJ, bodyObj.slot, resultSlot!!)
}
builder.mark(continueLabel)
if (hasRealWiden) {
emitLoopRealCoercions(realWidenSlots)
}
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(loopLabel)))
builder.mark(endLabel)
@ -6188,6 +6199,9 @@ class BytecodeCompiler(
)
)
val bodyValue = compileLoopBody(stmt.body, wantResult) ?: return null
if (hasRealWiden) {
applySlotTypes(realWidenSlots, SlotType.UNKNOWN)
}
loopStack.removeLast()
if (wantResult) {
val bodyObj = ensureObjSlot(bodyValue)
@ -6195,6 +6209,9 @@ class BytecodeCompiler(
}
builder.mark(continueLabel)
builder.emit(Opcode.INC_INT, iSlot)
if (hasRealWiden) {
emitLoopRealCoercions(realWidenSlots)
}
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(loopLabel)))
builder.mark(endLabel)
@ -6265,6 +6282,9 @@ class BytecodeCompiler(
)
)
val bodyValue = compileLoopBody(stmt.body, wantResult) ?: return null
if (hasRealWiden) {
applySlotTypes(realWidenSlots, SlotType.UNKNOWN)
}
loopStack.removeLast()
if (wantResult) {
val bodyObj = ensureObjSlot(bodyValue)
@ -6272,6 +6292,9 @@ class BytecodeCompiler(
}
builder.mark(continueLabel)
builder.emit(Opcode.INC_INT, iSlot)
if (hasRealWiden) {
emitLoopRealCoercions(realWidenSlots)
}
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(loopLabel)))
builder.mark(endLabel)
@ -6331,6 +6354,9 @@ class BytecodeCompiler(
)
)
val bodyValue = compileLoopBody(stmt.body, wantResult) ?: return null
if (hasRealWiden) {
applySlotTypes(realWidenSlots, SlotType.UNKNOWN)
}
loopStack.removeLast()
if (wantResult) {
val bodyObj = ensureObjSlot(bodyValue)

View File

@ -1258,6 +1258,28 @@ class ScriptTest {
)
}
@Test
fun testForLoopRealWidenDisasm() = runTest {
val scope = Script.newScope()
scope.eval(
"""
fun widenFor() {
var acc = 0
for(i in 0..3) {
if (i == 1) acc = 0.5
}
}
""".trimIndent()
)
val disasm = scope.disassembleSymbol("widenFor")
println("[DEBUG_LOG] widenFor disasm:\n$disasm")
val incIndex = disasm.indexOf("INC_INT")
assertTrue(incIndex >= 0, "expected INC_INT in for-loop disasm")
val convIndex = disasm.indexOf("INT_TO_REAL")
assertTrue(convIndex >= 0, "expected INT_TO_REAL in for-loop disasm")
assertTrue(convIndex > incIndex, "INT_TO_REAL should appear after INC_INT")
}
@Test
fun testIntClosedRangeInclusive() = runTest {
eval(

View File

@ -0,0 +1,9 @@
# Nested Range Benchmark Baseline
Date: 2026-02-16
Command:
`BENCHMARKS=true timeout 20s ./gradlew :lynglib:jvmTest --tests NestedRangeBenchmarkTest --rerun-tasks`
Result:
- nested-happy elapsed=56 ms