Step 20: bytecode NopStatement
This commit is contained in:
parent
ae88898f58
commit
b49f291bff
@ -66,6 +66,17 @@ Goal: migrate the compiler so all values live in frames/bytecode, keeping JVM te
|
|||||||
- [x] Reject Object/unknown receiver member calls without explicit cast or Dynamic.
|
- [x] Reject Object/unknown receiver member calls without explicit cast or Dynamic.
|
||||||
- [x] Add union-member dispatch with ordered type checks and runtime mismatch error.
|
- [x] Add union-member dispatch with ordered type checks and runtime mismatch error.
|
||||||
- [x] Add JVM tests for unknown receiver and union member access.
|
- [x] Add JVM tests for unknown receiver and union member access.
|
||||||
|
- [x] Step 20: Bytecode support for `NopStatement`.
|
||||||
|
- [x] Allow `NopStatement` in `containsUnsupportedForBytecode`.
|
||||||
|
- [x] Emit `ObjVoid` directly in bytecode for `NopStatement` in statement/value contexts.
|
||||||
|
- [x] Add a JVM test that exercises a code path returning `NopStatement` in bytecode (e.g., static class member decl in class body).
|
||||||
|
- [ ] Step 21: Union mismatch path in bytecode.
|
||||||
|
- [ ] Replace `UnionTypeMismatchStatement` branch with a bytecode-compilable throw path (no custom `StatementRef` that blocks bytecode).
|
||||||
|
- [ ] Add a JVM test that forces the union mismatch at runtime and asserts the error message.
|
||||||
|
- [ ] Step 22: Delegated local slots in bytecode.
|
||||||
|
- [ ] Support reads/writes/assign-ops/inc/dec for delegated locals (`LocalSlotRef.isDelegated`) in `BytecodeCompiler`.
|
||||||
|
- [ ] Remove `containsDelegatedRefs` guard once delegated locals are bytecode-safe.
|
||||||
|
- [ ] Add JVM tests that use delegated locals inside bytecode-compiled functions.
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
|||||||
@ -1934,6 +1934,7 @@ class Compiler(
|
|||||||
is ContinueStatement -> false
|
is ContinueStatement -> false
|
||||||
is ReturnStatement -> target.resultExpr?.let { containsUnsupportedForBytecode(it) } ?: false
|
is ReturnStatement -> target.resultExpr?.let { containsUnsupportedForBytecode(it) } ?: false
|
||||||
is ThrowStatement -> containsUnsupportedForBytecode(target.throwExpr)
|
is ThrowStatement -> containsUnsupportedForBytecode(target.throwExpr)
|
||||||
|
is NopStatement -> false
|
||||||
is ExtensionPropertyDeclStatement -> false
|
is ExtensionPropertyDeclStatement -> false
|
||||||
is ClassDeclStatement -> false
|
is ClassDeclStatement -> false
|
||||||
is FunctionDeclStatement -> false
|
is FunctionDeclStatement -> false
|
||||||
|
|||||||
@ -202,6 +202,23 @@ class BytecodeCompiler(
|
|||||||
localSlotMutables
|
localSlotMutables
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
is net.sergeych.lyng.NopStatement -> {
|
||||||
|
val voidId = builder.addConst(BytecodeConst.ObjRef(ObjVoid))
|
||||||
|
val slot = allocSlot()
|
||||||
|
builder.emit(Opcode.CONST_OBJ, voidId, slot)
|
||||||
|
builder.emit(Opcode.RET, slot)
|
||||||
|
builder.build(
|
||||||
|
name,
|
||||||
|
localCount = maxOf(nextSlot, slot + 1) - scopeSlotCount,
|
||||||
|
addrCount = nextAddrSlot,
|
||||||
|
returnLabels = returnLabels,
|
||||||
|
scopeSlotIndices,
|
||||||
|
scopeSlotNames,
|
||||||
|
scopeSlotIsModule,
|
||||||
|
localSlotNames,
|
||||||
|
localSlotMutables
|
||||||
|
)
|
||||||
|
}
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3920,6 +3937,12 @@ class BytecodeCompiler(
|
|||||||
private fun compileStatementValue(stmt: Statement): CompiledValue? {
|
private fun compileStatementValue(stmt: Statement): CompiledValue? {
|
||||||
return when (stmt) {
|
return when (stmt) {
|
||||||
is ExpressionStatement -> compileRefWithFallback(stmt.ref, null, stmt.pos)
|
is ExpressionStatement -> compileRefWithFallback(stmt.ref, null, stmt.pos)
|
||||||
|
is net.sergeych.lyng.NopStatement -> {
|
||||||
|
val slot = allocSlot()
|
||||||
|
val voidId = builder.addConst(BytecodeConst.ObjRef(ObjVoid))
|
||||||
|
builder.emit(Opcode.CONST_OBJ, voidId, slot)
|
||||||
|
CompiledValue(slot, SlotType.OBJ)
|
||||||
|
}
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3990,6 +4013,12 @@ class BytecodeCompiler(
|
|||||||
is net.sergeych.lyng.ReturnStatement -> compileReturn(target)
|
is net.sergeych.lyng.ReturnStatement -> compileReturn(target)
|
||||||
is net.sergeych.lyng.ThrowStatement -> compileThrow(target)
|
is net.sergeych.lyng.ThrowStatement -> compileThrow(target)
|
||||||
is net.sergeych.lyng.TryStatement -> emitTry(target, false)
|
is net.sergeych.lyng.TryStatement -> emitTry(target, false)
|
||||||
|
is net.sergeych.lyng.NopStatement -> {
|
||||||
|
val slot = allocSlot()
|
||||||
|
val voidId = builder.addConst(BytecodeConst.ObjRef(ObjVoid))
|
||||||
|
builder.emit(Opcode.CONST_OBJ, voidId, slot)
|
||||||
|
CompiledValue(slot, SlotType.OBJ)
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
emitFallbackStatement(target)
|
emitFallbackStatement(target)
|
||||||
}
|
}
|
||||||
@ -4037,6 +4066,12 @@ class BytecodeCompiler(
|
|||||||
is net.sergeych.lyng.ThrowStatement -> compileThrow(target)
|
is net.sergeych.lyng.ThrowStatement -> compileThrow(target)
|
||||||
is net.sergeych.lyng.TryStatement -> emitTry(target, false)
|
is net.sergeych.lyng.TryStatement -> emitTry(target, false)
|
||||||
is net.sergeych.lyng.WhenStatement -> compileWhen(target, false)
|
is net.sergeych.lyng.WhenStatement -> compileWhen(target, false)
|
||||||
|
is net.sergeych.lyng.NopStatement -> {
|
||||||
|
val slot = allocSlot()
|
||||||
|
val voidId = builder.addConst(BytecodeConst.ObjRef(ObjVoid))
|
||||||
|
builder.emit(Opcode.CONST_OBJ, voidId, slot)
|
||||||
|
CompiledValue(slot, SlotType.OBJ)
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
emitFallbackStatement(target)
|
emitFallbackStatement(target)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -132,6 +132,7 @@ class BytecodeStatement private constructor(
|
|||||||
target.resultExpr?.let { containsUnsupportedStatement(it) } ?: false
|
target.resultExpr?.let { containsUnsupportedStatement(it) } ?: false
|
||||||
is net.sergeych.lyng.ThrowStatement ->
|
is net.sergeych.lyng.ThrowStatement ->
|
||||||
containsUnsupportedStatement(target.throwExpr)
|
containsUnsupportedStatement(target.throwExpr)
|
||||||
|
is net.sergeych.lyng.NopStatement -> false
|
||||||
is net.sergeych.lyng.ExtensionPropertyDeclStatement -> false
|
is net.sergeych.lyng.ExtensionPropertyDeclStatement -> false
|
||||||
is net.sergeych.lyng.ClassDeclStatement -> false
|
is net.sergeych.lyng.ClassDeclStatement -> false
|
||||||
is net.sergeych.lyng.FunctionDeclStatement -> false
|
is net.sergeych.lyng.FunctionDeclStatement -> false
|
||||||
|
|||||||
@ -209,6 +209,18 @@ class BytecodeRecentOpsTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun staticMemberDeclNopStatement() = runTest {
|
||||||
|
eval(
|
||||||
|
"""
|
||||||
|
class C {
|
||||||
|
static fun ping() { 7 }
|
||||||
|
}
|
||||||
|
assertEquals(7, C.ping())
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun objectReceiverMemberError() = runTest {
|
fun objectReceiverMemberError() = runTest {
|
||||||
val failed = try {
|
val failed = try {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user