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 774e13c..7b4b57c 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt @@ -909,6 +909,7 @@ class BytecodeCompiler( val slot = allocSlot() builder.emit(Opcode.MAKE_LAMBDA_FN, id, slot) updateSlotType(slot, SlotType.OBJ) + trackExactLambdaAtSlot(slot, ref) return CompiledValue(slot, SlotType.OBJ) } val pos = (ref as? LambdaFnRef)?.pos ?: Pos.builtIn @@ -7724,6 +7725,7 @@ class BytecodeCompiler( private fun emitMove(value: CompiledValue, dstSlot: Int) { val srcSlot = value.slot + if (srcSlot == dstSlot) return val srcIsScope = srcSlot < scopeSlotCount val dstIsScope = dstSlot < scopeSlotCount if (value.type != SlotType.UNKNOWN) { @@ -7731,12 +7733,14 @@ class BytecodeCompiler( val addrSlot = ensureScopeAddr(srcSlot) emitLoadFromAddr(addrSlot, dstSlot, value.type) propagateObjClass(value.type, srcSlot, dstSlot) + propagateExactLambdaRef(value.type, srcSlot, dstSlot) return } if (dstIsScope) { val addrSlot = ensureScopeAddr(dstSlot) emitStoreToAddr(srcSlot, addrSlot, value.type) propagateObjClass(value.type, srcSlot, dstSlot) + propagateExactLambdaRef(value.type, srcSlot, dstSlot) return } } @@ -7748,6 +7752,7 @@ class BytecodeCompiler( else -> builder.emit(Opcode.BOX_OBJ, srcSlot, dstSlot) } propagateObjClass(value.type, srcSlot, dstSlot) + propagateExactLambdaRef(value.type, srcSlot, dstSlot) } private fun propagateObjClass(type: SlotType, srcSlot: Int, dstSlot: Int) { @@ -7776,6 +7781,14 @@ class BytecodeCompiler( } } + private fun propagateExactLambdaRef(type: SlotType, srcSlot: Int, dstSlot: Int) { + if (type == SlotType.OBJ || type == SlotType.UNKNOWN) { + trackExactLambdaAtSlot(dstSlot, exactLambdaRefBySlot[srcSlot]) + } else { + trackExactLambdaAtSlot(dstSlot, null) + } + } + private fun setPos(pos: Pos?) { currentPos = pos builder.setPos(pos) diff --git a/lynglib/src/commonTest/kotlin/BytecodeRecentOpsTest.kt b/lynglib/src/commonTest/kotlin/BytecodeRecentOpsTest.kt index 89d17d8..bde156f 100644 --- a/lynglib/src/commonTest/kotlin/BytecodeRecentOpsTest.kt +++ b/lynglib/src/commonTest/kotlin/BytecodeRecentOpsTest.kt @@ -346,6 +346,21 @@ class BytecodeRecentOpsTest { assertEquals(12, scope.eval("calc()").toInt()) } + @Test + fun nestedInlineLambdaParamCallAvoidsCallSlot() = runTest { + val scope = Script.newScope() + scope.eval( + """ + fun calc() { + { g -> g(10) }({ x -> x + 1 }) + } + """.trimIndent() + ) + val disasm = scope.disassembleSymbol("calc") + assertFalse(disasm.contains("CALL_SLOT"), disasm) + assertEquals(11, scope.eval("calc()").toInt()) + } + @Test fun letLiteralUsesInlineBytecode() = runTest { val scope = Script.newScope()