From e9251954955ec9bd2a487cfac9faa7de1f90ccec Mon Sep 17 00:00:00 2001 From: sergeych Date: Mon, 13 Apr 2026 22:48:52 +0300 Subject: [PATCH] yet another import fix --- .gitignore | 1 + .../CliLocalModuleImportRegressionJvmTest.kt | 16 +++++++++++++-- .../kotlin/net/sergeych/lyng/Compiler.kt | 20 ++++++++++++++++++- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 6685d49..45bafa8 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ debug.log /compile_metadata_output.txt test_output*.txt /site/src/version-template/lyng-version.js +/bugs/ diff --git a/lyng/src/jvmTest/kotlin/net/sergeych/CliLocalModuleImportRegressionJvmTest.kt b/lyng/src/jvmTest/kotlin/net/sergeych/CliLocalModuleImportRegressionJvmTest.kt index bdcaf81..6adddae 100644 --- a/lyng/src/jvmTest/kotlin/net/sergeych/CliLocalModuleImportRegressionJvmTest.kt +++ b/lyng/src/jvmTest/kotlin/net/sergeych/CliLocalModuleImportRegressionJvmTest.kt @@ -146,18 +146,27 @@ class CliLocalModuleImportRegressionJvmTest { val headers = Map() fn startListen(port, host) { + var eager = Bravo() + eager.doSomething() tcpServer = Net.tcpListen(port, host) - // println("tcpServer.isOpen: " + tcpServer.isOpen()) // historical workaround; should not be needed + println("tcpServer.isOpen: " + tcpServer.isOpen()) launch { try { while (true) { + println("wait for accept...") val tcpSocket = tcpServer.accept() + println("var bravo = Bravo()") var bravo = Bravo() + println("bravo.doSomething()...") bravo.doSomething() + println("bravo.doSomething()... OK") tcpSocket.close() break } + } catch (e) { + println("ERR [Alpha.startListen]: '", e, "'") } finally { + println("FIN [Alpha.startListen]") tcpServer.close() } } @@ -259,6 +268,7 @@ class CliLocalModuleImportRegressionJvmTest { delay(50) val socket = Net.tcpConnect("127.0.0.1", $port) + println("send ping...") socket.writeUtf8("ping") socket.flush() socket.close() @@ -269,8 +279,10 @@ class CliLocalModuleImportRegressionJvmTest { val result = runCli(mainFile.toString()) assertTrue(result.err.isBlank(), result.err) + assertFalse(result.out.contains("ERR [Alpha.startListen]"), result.out) assertFalse(result.out.contains("module capture 'Bravo'"), result.out) - assertTrue(result.out.contains("Bravo.doSomething"), result.out) + assertTrue(result.out.contains("bravo.doSomething()... OK"), result.out) + assertEquals(2, Regex("Bravo\\.doSomething").findAll(result.out).count(), result.out) } finally { root.toFile().deleteRecursively() } diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt index 0f73d74..05ed355 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt @@ -2086,7 +2086,7 @@ class Compiler( return null } if (scopeSeedNames.contains(name)) { - val isModuleSlot = modulePlan != null && slotLoc.scopeId == modulePlan.id + val isModuleSlot = resolvesToModuleSeedSlot(name, slotLoc) if (!isModuleSlot || useScopeSlots) return null } recordCaptureSlot(name, slotLoc) @@ -2105,6 +2105,24 @@ class Compiler( ) } + private fun resolvesToModuleSeedSlot(name: String, slotLoc: SlotLocation): Boolean { + val modulePlan = moduleSlotPlan() ?: return false + var current: SlotLocation? = slotLoc + val visitedScopeIds = HashSet() + while (current != null && visitedScopeIds.add(current.scopeId)) { + if (current.scopeId == modulePlan.id) { + return true + } + val owner = capturePlanStack + .firstOrNull { it.slotPlan.id == current.scopeId } + ?.captureOwners + ?.get(name) + ?: return false + current = owner + } + return false + } + private fun captureSlotRef(name: String, pos: Pos): ObjRef? { if (capturePlanStack.isEmpty()) return null if (name == "this") return null