From eefa4c8f1a80190f86ae0ba702ab9989c4a8281a Mon Sep 17 00:00:00 2001 From: sergeych Date: Sat, 11 Apr 2026 20:24:44 +0300 Subject: [PATCH] Fix stdlib import aliasing and launch captures --- .../kotlin/net/sergeych/lyng/ModuleScope.kt | 20 +++++++++++++++++-- .../net/sergeych/lyng/bytecode/CmdRuntime.kt | 3 ++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ModuleScope.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ModuleScope.kt index 1eae982..3be9117 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ModuleScope.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ModuleScope.kt @@ -19,6 +19,8 @@ package net.sergeych.lyng import net.sergeych.lyng.bytecode.BytecodeFrame import net.sergeych.lyng.bytecode.CmdFunction +import net.sergeych.lyng.obj.ObjClass +import net.sergeych.lyng.obj.ObjExternCallable import net.sergeych.lyng.obj.ObjRecord import net.sergeych.lyng.obj.ObjString import net.sergeych.lyng.pacman.ImportProvider @@ -33,6 +35,20 @@ class ModuleScope( override val packageName: String ) : Scope(importProvider.rootScope, Arguments.EMPTY, pos) { + private fun ObjRecord.isEquivalentStdlibAlias(other: ObjRecord): Boolean { + val leftOrigin = importedFrom?.packageName + val rightOrigin = other.importedFrom?.packageName + val origins = setOf(leftOrigin, rightOrigin) + val rootStdlibAlias = + "lyng.stdlib" in origins && + origins.all { it == null || it == "" || it == "lyng.stdlib" } + if (!rootStdlibAlias) return false + if (value !== other.value) return false + if (receiver !== other.receiver || delegate !== other.delegate) return false + if (memberName != other.memberName || fieldId != other.fieldId || methodId != other.methodId) return false + return value is ObjExternCallable || value is ObjClass + } + constructor(importProvider: ImportProvider, source: Source) : this(importProvider, source.startPos, source.fileName) internal var importedModules: List = emptyList() @@ -96,8 +112,8 @@ class ModuleScope( if (existing != null) { val sameBinding = existing === record || - existing.importedFrom == record.importedFrom || - existing.value === record.value + existing.importedFrom == record.importedFrom || + existing.isEquivalentStdlibAlias(record) if (!sameBinding) scope.raiseError("symbol ${existing.importedFrom?.packageName}.$newName already exists, redefinition on import is not allowed") // already imported diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdRuntime.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdRuntime.kt index df45f71..af10be9 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdRuntime.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdRuntime.kt @@ -3784,6 +3784,7 @@ class BytecodeLambdaCallable( override val pos: Pos, ) : Statement(), BytecodeCallable { private fun freezeRecord(record: ObjRecord): ObjRecord { + if (record.isMutable) return record val frozenValue = when (val raw = record.value) { is net.sergeych.lyng.FrameSlotRef -> raw.read() is net.sergeych.lyng.RecordSlotRef -> raw.read() @@ -3808,7 +3809,7 @@ class BytecodeLambdaCallable( return BytecodeLambdaCallable( fn = fn, closureScope = newClosureScope, - captureRecords = resolveCaptureRecords(newClosureScope) ?: captureRecords, + captureRecords = captureRecords ?: resolveCaptureRecords(newClosureScope), captureNames = captureNames, paramSlotPlan = paramSlotPlan, argsDeclaration = argsDeclaration,