Step 24E: isolate interpreter-only capture logic

This commit is contained in:
Sergey Chernov 2026-02-10 07:58:29 +03:00
parent 54ca886753
commit 8b196c7b0c
4 changed files with 6 additions and 1 deletions

View File

@ -105,7 +105,7 @@ Goal: migrate the compiler so all values live in frames/bytecode, keeping JVM te
- [ ] Avoid `ClosureScope` in bytecode-related call paths (Block/Lambda/ObjDynamic/ObjProperty). - [ ] Avoid `ClosureScope` in bytecode-related call paths (Block/Lambda/ObjDynamic/ObjProperty).
- [ ] Keep interpreter path using `ClosureScope` until interpreter removal. - [ ] Keep interpreter path using `ClosureScope` until interpreter removal.
- [ ] JVM tests must be green before commit. - [ ] JVM tests must be green before commit.
- [ ] Step 24E: Isolate interpreter-only capture logic. - [x] Step 24E: Isolate interpreter-only capture logic.
- [ ] Mark `resolveCaptureRecord` paths as interpreter-only. - [ ] Mark `resolveCaptureRecord` paths as interpreter-only.
- [ ] Guard or delete any bytecode path that tries to sync captures into scopes. - [ ] Guard or delete any bytecode path that tries to sync captures into scopes.
- [ ] JVM tests must be green before commit. - [ ] JVM tests must be green before commit.

View File

@ -33,6 +33,7 @@ class BlockStatement(
if (captureSlots.isNotEmpty()) { if (captureSlots.isNotEmpty()) {
val applyScope = scope as? ApplyScope val applyScope = scope as? ApplyScope
for (capture in captureSlots) { for (capture in captureSlots) {
// Interpreter-only capture resolution; bytecode paths must use captureRecords instead.
val rec = if (applyScope != null) { val rec = if (applyScope != null) {
applyScope.resolveCaptureRecord(capture.name) applyScope.resolveCaptureRecord(capture.name)
?: applyScope.callScope.resolveCaptureRecord(capture.name) ?: applyScope.callScope.resolveCaptureRecord(capture.name)

View File

@ -7034,6 +7034,7 @@ class Compiler(
val captureBase = captureContext ?: closure val captureBase = captureContext ?: closure
if (captureBase != null && captureSlots.isNotEmpty()) { if (captureBase != null && captureSlots.isNotEmpty()) {
for (capture in captureSlots) { for (capture in captureSlots) {
// Interpreter-only capture resolution; bytecode functions do not use resolveCaptureRecord.
val rec = captureBase.resolveCaptureRecord(capture.name) val rec = captureBase.resolveCaptureRecord(capture.name)
?: captureBase.raiseSymbolNotFound("symbol ${capture.name} not found") ?: captureBase.raiseSymbolNotFound("symbol ${capture.name} not found")
context.updateSlotFor(capture.name, rec) context.updateSlotFor(capture.name, rec)

View File

@ -170,6 +170,9 @@ open class Scope(
} }
internal fun resolveCaptureRecord(name: String): ObjRecord? { internal fun resolveCaptureRecord(name: String): ObjRecord? {
if (captureRecords != null) {
raiseIllegalState("resolveCaptureRecord is interpreter-only; bytecode captures use captureRecords")
}
return chainLookupIgnoreClosure(name, followClosure = true, caller = currentClassCtx) return chainLookupIgnoreClosure(name, followClosure = true, caller = currentClassCtx)
} }