fixed wrong error message in val ++/--

This commit is contained in:
Sergey Chernov 2026-04-22 08:56:02 +03:00
parent 0973a6afeb
commit d0f51928de
2 changed files with 32 additions and 15 deletions

View File

@ -2559,11 +2559,7 @@ class BytecodeCompiler(
return value return value
} }
if (!localTarget.isMutable || localTarget.isDelegated) { if (!localTarget.isMutable || localTarget.isDelegated) {
val msgId = builder.addConst(BytecodeConst.StringVal("can't reassign val ${localTarget.name}")) emitImmutableLocalReassignError(localTarget.name, localTarget.pos())
val msgSlot = allocSlot()
builder.emit(Opcode.CONST_OBJ, msgId, msgSlot)
val posId = builder.addConst(BytecodeConst.PosVal(localTarget.pos()))
builder.emit(Opcode.THROW, posId, msgSlot)
return value return value
} }
val slot = resolveCapturedOwnerScopeSlot(localTarget) val slot = resolveCapturedOwnerScopeSlot(localTarget)
@ -2607,12 +2603,8 @@ class BytecodeCompiler(
return value return value
} }
if (!isMutable) { 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 pos = (ref.target as? LocalVarRef)?.pos() ?: Pos.builtIn
val posId = builder.addConst(BytecodeConst.PosVal(pos)) emitImmutableLocalReassignError(nameTarget, pos)
builder.emit(Opcode.THROW, posId, msgSlot)
return value return value
} }
if (slot < scopeSlotCount && value.type != SlotType.UNKNOWN) { if (slot < scopeSlotCount && value.type != SlotType.UNKNOWN) {
@ -3904,7 +3896,10 @@ class BytecodeCompiler(
val errorSlot = emitLoopVarReassignError(target.name, target.pos()) val errorSlot = emitLoopVarReassignError(target.name, target.pos())
return CompiledValue(errorSlot, SlotType.OBJ) 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) { if (target.isDelegated) {
val slot = resolveSlot(target) ?: return null val slot = resolveSlot(target) ?: return null
if (slot < scopeSlotCount) return null if (slot < scopeSlotCount) return null
@ -4078,6 +4073,10 @@ class BytecodeCompiler(
val errorSlot = emitLoopVarReassignError(varTarget.name, varTarget.pos()) val errorSlot = emitLoopVarReassignError(varTarget.name, varTarget.pos())
return CompiledValue(errorSlot, SlotType.OBJ) 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 val thisFieldTarget = ref.target as? ThisFieldSlotRef
@ -8438,6 +8437,15 @@ class BytecodeCompiler(
builder.emit(Opcode.THROW, posId, msgSlot) builder.emit(Opcode.THROW, posId, msgSlot)
return 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 binaryLeft(ref: BinaryOpRef): ObjRef = ref.left
private fun binaryRight(ref: BinaryOpRef): ObjRef = ref.right private fun binaryRight(ref: BinaryOpRef): ObjRef = ref.right
private fun binaryOp(ref: BinaryOpRef): BinOp = ref.op private fun binaryOp(ref: BinaryOpRef): BinOp = ref.op

View File

@ -17,12 +17,12 @@
package net.sergeych.lyng package net.sergeych.lyng
import kotlinx.coroutines.delay
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import net.sergeych.lyng.obj.toInt import net.sergeych.lyng.obj.toInt
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertContains
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.time.Duration.Companion.milliseconds import kotlin.test.assertFailsWith
import kotlin.time.TimeSource import kotlin.time.TimeSource
class OptTest { class OptTest {
@ -42,7 +42,6 @@ class OptTest {
repeat(3) { pass -> repeat(3) { pass ->
val size = scope.eval("buildArray(200000)").toInt() val size = scope.eval("buildArray(200000)").toInt()
assertEquals(200000, size, "warmup pass ${pass + 1} failed") assertEquals(200000, size, "warmup pass ${pass + 1} failed")
delay(100)
} }
@ -80,5 +79,15 @@ class OptTest {
""".trimIndent() """.trimIndent()
) )
} }
}
@Test
fun testErrorMessage() = runTest {
val ex = assertFailsWith<ScriptError> {
eval("""
val a = 1
a++
""".trimIndent())
}
assertContains(ex.errorMessage, "can't reassign val a")
}
}