Fix apply/inc-dec handling and re-enable more ScriptTests

This commit is contained in:
Sergey Chernov 2026-01-30 18:19:55 +03:00
parent eaa5713eaf
commit 64fa305aa7
6 changed files with 134 additions and 52 deletions

View File

@ -67,24 +67,40 @@ data class ArgsDeclaration(val params: List<Item>, val endTokenType: Token.Type)
for (i in params.indices) {
val a = params[i]
val value = arguments.list[i]
scope.addItem(a.name, (a.accessType ?: defaultAccessType).isMutable,
val recordType = if (declaringClass != null && a.accessType != null) {
ObjRecord.Type.ConstructorField
} else {
ObjRecord.Type.Argument
}
scope.addItem(
a.name,
(a.accessType ?: defaultAccessType).isMutable,
value.byValueCopy(),
a.visibility ?: defaultVisibility,
recordType = ObjRecord.Type.Argument,
recordType = recordType,
declaringClass = declaringClass,
isTransient = a.isTransient)
isTransient = a.isTransient
)
}
return
}
}
fun assign(a: Item, value: Obj) {
scope.addItem(a.name, (a.accessType ?: defaultAccessType).isMutable,
val recordType = if (declaringClass != null && a.accessType != null) {
ObjRecord.Type.ConstructorField
} else {
ObjRecord.Type.Argument
}
scope.addItem(
a.name,
(a.accessType ?: defaultAccessType).isMutable,
value.byValueCopy(),
a.visibility ?: defaultVisibility,
recordType = ObjRecord.Type.Argument,
recordType = recordType,
declaringClass = declaringClass,
isTransient = a.isTransient)
isTransient = a.isTransient
)
}
// Prepare positional args and parameter count, handle tail-block binding

View File

@ -391,7 +391,7 @@ class Compiler(
return LocalVarRef(name, pos)
}
resolutionSink?.reference(name, pos)
if (allowUnresolvedRefs) {
if (allowUnresolvedRefs || (name.isNotEmpty() && name[0].isUpperCase())) {
return LocalVarRef(name, pos)
}
throw ScriptError(pos, "unresolved name: $name")
@ -1741,6 +1741,11 @@ class Compiler(
else -> null
}
val effectiveAccess = if (isClassDeclaration && access == null) {
AccessType.Var
} else {
access
}
// type information (semantic + mini syntax)
val (typeInfo, miniType) = parseTypeDeclarationWithMini()
@ -1757,7 +1762,7 @@ class Compiler(
t.pos,
isEllipsis,
defaultValue,
access,
effectiveAccess,
visibility,
isTransient
)

View File

@ -190,6 +190,7 @@ class BytecodeCompiler(
private fun compileRef(ref: ObjRef): CompiledValue? {
return when (ref) {
is ConstRef -> compileConst(ref.constValue)
is IncDecRef -> compileIncDec(ref, true)
is LocalSlotRef -> {
if (ref.name == "__PACKAGE__") {
return compileNameLookup(ref.name)
@ -1625,6 +1626,83 @@ class BytecodeCompiler(
}
}
val thisFieldTarget = ref.target as? ThisFieldSlotRef
if (thisFieldTarget != null) {
val nameId = builder.addConst(BytecodeConst.StringVal(thisFieldTarget.name))
if (nameId > 0xFFFF) return null
val current = allocSlot()
builder.emit(Opcode.GET_THIS_MEMBER, nameId, current)
updateSlotType(current, SlotType.OBJ)
val oneSlot = allocSlot()
val oneId = builder.addConst(BytecodeConst.ObjRef(ObjInt.One))
builder.emit(Opcode.CONST_OBJ, oneId, oneSlot)
updateSlotType(oneSlot, SlotType.OBJ)
val result = allocSlot()
val op = if (ref.isIncrement) Opcode.ADD_OBJ else Opcode.SUB_OBJ
if (wantResult && ref.isPost) {
val old = allocSlot()
builder.emit(Opcode.MOVE_OBJ, current, old)
builder.emit(op, current, oneSlot, result)
builder.emit(Opcode.SET_THIS_MEMBER, nameId, result)
return CompiledValue(old, SlotType.OBJ)
}
builder.emit(op, current, oneSlot, result)
builder.emit(Opcode.SET_THIS_MEMBER, nameId, result)
return CompiledValue(result, SlotType.OBJ)
}
val implicitTarget = ref.target as? ImplicitThisMemberRef
if (implicitTarget != null) {
val nameId = builder.addConst(BytecodeConst.StringVal(implicitTarget.name))
if (nameId > 0xFFFF) return null
val current = allocSlot()
builder.emit(Opcode.GET_THIS_MEMBER, nameId, current)
updateSlotType(current, SlotType.OBJ)
val oneSlot = allocSlot()
val oneId = builder.addConst(BytecodeConst.ObjRef(ObjInt.One))
builder.emit(Opcode.CONST_OBJ, oneId, oneSlot)
updateSlotType(oneSlot, SlotType.OBJ)
val result = allocSlot()
val op = if (ref.isIncrement) Opcode.ADD_OBJ else Opcode.SUB_OBJ
if (wantResult && ref.isPost) {
val old = allocSlot()
builder.emit(Opcode.MOVE_OBJ, current, old)
builder.emit(op, current, oneSlot, result)
builder.emit(Opcode.SET_THIS_MEMBER, nameId, result)
return CompiledValue(old, SlotType.OBJ)
}
builder.emit(op, current, oneSlot, result)
builder.emit(Opcode.SET_THIS_MEMBER, nameId, result)
return CompiledValue(result, SlotType.OBJ)
}
val fieldTarget = ref.target as? FieldRef
if (fieldTarget != null) {
if (fieldTarget.isOptional) return null
val receiver = compileRefWithFallback(fieldTarget.target, null, Pos.builtIn) ?: return null
val nameId = builder.addConst(BytecodeConst.StringVal(fieldTarget.name))
if (nameId > 0xFFFF) return null
val current = allocSlot()
builder.emit(Opcode.GET_FIELD, receiver.slot, nameId, current)
updateSlotType(current, SlotType.OBJ)
val oneSlot = allocSlot()
val oneId = builder.addConst(BytecodeConst.ObjRef(ObjInt.One))
builder.emit(Opcode.CONST_OBJ, oneId, oneSlot)
updateSlotType(oneSlot, SlotType.OBJ)
val result = allocSlot()
val op = if (ref.isIncrement) Opcode.ADD_OBJ else Opcode.SUB_OBJ
if (wantResult && ref.isPost) {
val old = allocSlot()
builder.emit(Opcode.MOVE_OBJ, current, old)
builder.emit(op, current, oneSlot, result)
builder.emit(Opcode.SET_FIELD, receiver.slot, nameId, result)
return CompiledValue(old, SlotType.OBJ)
}
builder.emit(op, current, oneSlot, result)
builder.emit(Opcode.SET_FIELD, receiver.slot, nameId, result)
return CompiledValue(result, SlotType.OBJ)
}
val indexTarget = ref.target as? IndexRef ?: return null
if (indexTarget.optionalRef) return null
val receiver = compileRefWithFallback(indexTarget.targetRef, null, Pos.builtIn) ?: return null

View File

@ -725,7 +725,8 @@ open class Obj {
(thisObj as? ObjInstance)?.let {
body.callOn(ApplyScope(this, it.instanceScope))
} ?: run {
body.callOn(this)
val appliedScope = createChildScope(newThisObj = thisObj)
body.callOn(ApplyScope(this, appliedScope))
}
thisObj
}

View File

@ -118,9 +118,13 @@ open class ObjClass(
/**
* Map of public member names to their effective storage keys in instanceScope.objects.
* This is pre-calculated to avoid MRO traversal and string concatenation during common access.
* Cached and invalidated by layoutVersion to reflect newly added members.
*/
val publicMemberResolution: Map<String, String> by lazy {
private var publicMemberResolutionVersion: Int = -1
private var publicMemberResolutionCache: Map<String, String> = emptyMap()
val publicMemberResolution: Map<String, String>
get() {
if (publicMemberResolutionVersion == layoutVersion) return publicMemberResolutionCache
val res = mutableMapOf<String, String>()
// Traverse MRO in REVERSED order so that child classes override parent classes in the map.
for (cls in mro.reversed()) {
@ -138,7 +142,9 @@ open class ObjClass(
}
}
}
res
publicMemberResolutionCache = res
publicMemberResolutionVersion = layoutVersion
return res
}
val classNameObj by lazy { ObjString(className) }

View File

@ -2671,7 +2671,6 @@ class ScriptTest {
)
}
@Ignore("incremental enable")
@Test
fun testLet() = runTest {
eval(
@ -2685,7 +2684,6 @@ class ScriptTest {
)
}
@Ignore("incremental enable")
@Test
fun testApply() = runTest {
eval(
@ -2700,7 +2698,6 @@ class ScriptTest {
)
}
@Ignore("incremental enable")
@Test
fun testApplyThis() = runTest {
eval(
@ -2717,7 +2714,6 @@ class ScriptTest {
)
}
@Ignore("incremental enable")
@Test
fun testApplyFromStatic() = runTest {
eval(
@ -2754,7 +2750,6 @@ class ScriptTest {
}
}
@Ignore("incremental enable")
@Test
fun TestApplyFromKotlin() = runTest {
val scope = Script.newScope()
@ -2770,7 +2765,6 @@ class ScriptTest {
)
}
@Ignore("incremental enable")
@Test
fun testParallels() = runTest {
withContext(Dispatchers.Default) {
@ -2797,7 +2791,6 @@ class ScriptTest {
}
}
@Ignore("incremental enable")
@Test
fun testParallels2() = runTest {
withContext(Dispatchers.Default) {
@ -2845,7 +2838,6 @@ class ScriptTest {
}
}
@Ignore("incremental enable")
@Test
fun testExtend() = runTest() {
eval(
@ -2879,7 +2871,6 @@ class ScriptTest {
)
}
@Ignore("incremental enable")
@Test
fun testToFlow() = runTest() {
val c = Scope()
@ -2888,7 +2879,6 @@ class ScriptTest {
assertEquals(listOf(1, 2, 3), arr.toFlow(c).map { it.toInt() }.toList())
}
@Ignore("incremental enable")
@Test
fun testAssociateBy() = runTest() {
eval(
@ -2916,7 +2906,6 @@ class ScriptTest {
// assertEquals("foo1", pm.modules["lyng.foo"]!!.deferredModule.await().eval("foo()").toString())
// }
@Ignore("incremental enable")
@Test
fun testImports2() = runTest() {
val foosrc = """
@ -2936,7 +2925,6 @@ class ScriptTest {
assertEquals("foo1", scope.eval(src).toString())
}
@Ignore("incremental enable")
@Test
fun testImports3() = runTest {
val foosrc = """
@ -2968,7 +2956,6 @@ class ScriptTest {
assertEquals("foo1 / bar1", scope.eval(src).toString())
}
@Ignore("incremental enable")
@Test
fun testImportsCircular() = runTest {
val foosrc = """
@ -3002,7 +2989,6 @@ class ScriptTest {
assertEquals("foo1 / bar1", scope.eval(src).toString())
}
@Ignore("incremental enable")
@Test
fun testDefaultImportManager() = runTest {
val scope = Scope.new()
@ -3029,7 +3015,6 @@ class ScriptTest {
)
}
@Ignore("incremental enable")
@Test
fun testMaps() = runTest {
eval(
@ -3063,7 +3048,6 @@ class ScriptTest {
)
}
@Ignore("incremental enable")
@Test
fun testExternDeclarations() = runTest {
eval(
@ -3087,7 +3071,6 @@ class ScriptTest {
)
}
@Ignore("incremental enable")
@Test
fun testExternExtension() = runTest {
eval(
@ -3098,7 +3081,6 @@ class ScriptTest {
)
}
@Ignore("incremental enable")
@Test
fun testBuffer() = runTest {
eval(
@ -3125,7 +3107,6 @@ class ScriptTest {
)
}
@Ignore("incremental enable")
@Test
fun testBufferEncodings() = runTest {
eval(
@ -3148,7 +3129,6 @@ class ScriptTest {
)
}
@Ignore("incremental enable")
@Test
fun testBufferCompare() = runTest {
eval(
@ -3174,7 +3154,6 @@ class ScriptTest {
)
}
@Ignore("incremental enable")
@Test
fun testInstant() = runTest {
eval(
@ -3214,7 +3193,6 @@ class ScriptTest {
delay(1000)
}
@Ignore("incremental enable")
@Test
fun testTimeStatics() = runTest {
eval(
@ -3236,7 +3214,6 @@ class ScriptTest {
)
}
@Ignore("incremental enable")
@Test
fun testInstantFormatting() = runTest {
eval(
@ -3251,7 +3228,6 @@ class ScriptTest {
)
}
@Ignore("incremental enable")
@Test
fun testDateTimeComprehensive() = runTest {
eval(