diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt index 2ac1ea2..43a4b7f 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt @@ -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) diff --git a/lynglib/src/commonTest/kotlin/ScriptTest.kt b/lynglib/src/commonTest/kotlin/ScriptTest.kt index 187c223..c1b5ab6 100644 --- a/lynglib/src/commonTest/kotlin/ScriptTest.kt +++ b/lynglib/src/commonTest/kotlin/ScriptTest.kt @@ -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( diff --git a/notes/nested_range_baseline.md b/notes/nested_range_baseline.md new file mode 100644 index 0000000..ea233d6 --- /dev/null +++ b/notes/nested_range_baseline.md @@ -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