From d0f51928deba8dfe166d4cf4920672633a667572 Mon Sep 17 00:00:00 2001 From: sergeych Date: Wed, 22 Apr 2026 08:56:02 +0300 Subject: [PATCH] fixed wrong error message in val ++/-- --- .../lyng/bytecode/BytecodeCompiler.kt | 30 ++++++++++++------- .../kotlin/net/sergeych/lyng/OptTest.kt | 17 ++++++++--- 2 files changed, 32 insertions(+), 15 deletions(-) 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 2b67ffe..cc7f558 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt @@ -2559,11 +2559,7 @@ class BytecodeCompiler( return value } if (!localTarget.isMutable || localTarget.isDelegated) { - val msgId = builder.addConst(BytecodeConst.StringVal("can't reassign val ${localTarget.name}")) - val msgSlot = allocSlot() - builder.emit(Opcode.CONST_OBJ, msgId, msgSlot) - val posId = builder.addConst(BytecodeConst.PosVal(localTarget.pos())) - builder.emit(Opcode.THROW, posId, msgSlot) + emitImmutableLocalReassignError(localTarget.name, localTarget.pos()) return value } val slot = resolveCapturedOwnerScopeSlot(localTarget) @@ -2607,12 +2603,8 @@ class BytecodeCompiler( return value } if (!isMutable) { - val msgId = builder.addConst(BytecodeConst.StringVal("can't reassign val $nameTarget")) - val msgSlot = allocSlot() - builder.emit(Opcode.CONST_OBJ, msgId, msgSlot) val pos = (ref.target as? LocalVarRef)?.pos() ?: Pos.builtIn - val posId = builder.addConst(BytecodeConst.PosVal(pos)) - builder.emit(Opcode.THROW, posId, msgSlot) + emitImmutableLocalReassignError(nameTarget, pos) return value } if (slot < scopeSlotCount && value.type != SlotType.UNKNOWN) { @@ -3904,7 +3896,10 @@ class BytecodeCompiler( val errorSlot = emitLoopVarReassignError(target.name, target.pos()) return CompiledValue(errorSlot, SlotType.OBJ) } - if (!target.isMutable) return null + if (!target.isMutable) { + val errorSlot = emitImmutableLocalReassignError(target.name, target.pos()) + return CompiledValue(errorSlot, SlotType.OBJ) + } if (target.isDelegated) { val slot = resolveSlot(target) ?: return null if (slot < scopeSlotCount) return null @@ -4078,6 +4073,10 @@ class BytecodeCompiler( val errorSlot = emitLoopVarReassignError(varTarget.name, varTarget.pos()) return CompiledValue(errorSlot, SlotType.OBJ) } + if (resolved != null && !resolved.second) { + val errorSlot = emitImmutableLocalReassignError(varTarget.name, varTarget.pos()) + return CompiledValue(errorSlot, SlotType.OBJ) + } } val thisFieldTarget = ref.target as? ThisFieldSlotRef @@ -8438,6 +8437,15 @@ class BytecodeCompiler( builder.emit(Opcode.THROW, posId, msgSlot) return msgSlot } + + private fun emitImmutableLocalReassignError(name: String, pos: Pos): Int { + val msgId = builder.addConst(BytecodeConst.StringVal("can't reassign val $name")) + val msgSlot = allocSlot() + builder.emit(Opcode.CONST_OBJ, msgId, msgSlot) + val posId = builder.addConst(BytecodeConst.PosVal(pos)) + builder.emit(Opcode.THROW, posId, msgSlot) + return msgSlot + } private fun binaryLeft(ref: BinaryOpRef): ObjRef = ref.left private fun binaryRight(ref: BinaryOpRef): ObjRef = ref.right private fun binaryOp(ref: BinaryOpRef): BinOp = ref.op diff --git a/lynglib/src/commonTest/kotlin/net/sergeych/lyng/OptTest.kt b/lynglib/src/commonTest/kotlin/net/sergeych/lyng/OptTest.kt index 1cb2d8b..602acd6 100644 --- a/lynglib/src/commonTest/kotlin/net/sergeych/lyng/OptTest.kt +++ b/lynglib/src/commonTest/kotlin/net/sergeych/lyng/OptTest.kt @@ -17,12 +17,12 @@ package net.sergeych.lyng -import kotlinx.coroutines.delay import kotlinx.coroutines.test.runTest import net.sergeych.lyng.obj.toInt import kotlin.test.Test +import kotlin.test.assertContains import kotlin.test.assertEquals -import kotlin.time.Duration.Companion.milliseconds +import kotlin.test.assertFailsWith import kotlin.time.TimeSource class OptTest { @@ -42,7 +42,6 @@ class OptTest { repeat(3) { pass -> val size = scope.eval("buildArray(200000)").toInt() assertEquals(200000, size, "warmup pass ${pass + 1} failed") - delay(100) } @@ -80,5 +79,15 @@ class OptTest { """.trimIndent() ) } -} + @Test + fun testErrorMessage() = runTest { + val ex = assertFailsWith { + eval(""" + val a = 1 + a++ + """.trimIndent()) + } + assertContains(ex.errorMessage, "can't reassign val a") + } +}