Fix lazy delegate type resolution across modules
This commit is contained in:
1 parent
217787e17a
commit
7c059b4741
6 files changed
+103
-122
No files matched your search
@@ -8401,7 +8401,7 @@ class Compiler(
|
||||
is ImplicitThisMethodCallRef -> {
|
||||
when (directRef.methodName()) {
|
||||
"iterator" -> ObjIterator
|
||||
"lazy" -> ObjLazyDelegate.type
|
||||
"lazy" -> resolveClassByName("lazy") ?: inferMethodCallReturnClass(directRef.methodName())
|
||||
else -> inferMethodCallReturnClass(directRef.methodName())
|
||||
}
|
||||
}
|
||||
@@ -8420,7 +8420,7 @@ class Compiler(
|
||||
when {
|
||||
target is LocalSlotRef -> {
|
||||
when (target.name) {
|
||||
"lazy" -> ObjLazyDelegate.type
|
||||
"lazy" -> resolveClassByName("lazy")
|
||||
"iterator" -> ObjIterator
|
||||
"flow" -> ObjFlow.type
|
||||
"launch" -> ObjDeferred.type
|
||||
@@ -8431,7 +8431,7 @@ class Compiler(
|
||||
}
|
||||
target is LocalVarRef -> {
|
||||
when (target.name) {
|
||||
"lazy" -> ObjLazyDelegate.type
|
||||
"lazy" -> resolveClassByName("lazy")
|
||||
"iterator" -> ObjIterator
|
||||
"flow" -> ObjFlow.type
|
||||
"launch" -> ObjDeferred.type
|
||||
@@ -8470,7 +8470,9 @@ class Compiler(
|
||||
?: unwrapDirectRef(initializer)?.let { inferObjClassFromRef(it) }
|
||||
?: throw ScriptError(initializer.pos, "Delegate type must be known at compile time")
|
||||
if (initClass !== delegateClass &&
|
||||
initClass.className != delegateClass.className &&
|
||||
!initClass.allParentsSet.contains(delegateClass) &&
|
||||
!initClass.allParentsSet.any { it.className == delegateClass.className } &&
|
||||
!initClass.allImplementingNames.contains(delegateClass.className)
|
||||
) {
|
||||
throw ScriptError(
|
||||
@@ -8980,7 +8982,7 @@ class Compiler(
|
||||
|
||||
if (isDelegate && initialExpression != null) {
|
||||
ensureDelegateType(initialExpression)
|
||||
if (isMutable && resolveInitializerObjClass(initialExpression) == ObjLazyDelegate.type) {
|
||||
if (isMutable && resolveInitializerObjClass(initialExpression)?.className == "lazy") {
|
||||
throw ScriptError(initialExpression.pos, "lazy delegate is read-only")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -540,14 +540,6 @@ class Script(
|
||||
cachedValue
|
||||
}
|
||||
}
|
||||
addFn("lazy") {
|
||||
val builder = requireOnlyArg<Obj>()
|
||||
ObjLazyDelegate(builder, requireScope().snapshotForClosure())
|
||||
}
|
||||
addFn("__builtinLazy") {
|
||||
val builder = requireOnlyArg<Obj>()
|
||||
ObjLazyDelegate(builder, requireScope().snapshotForClosure())
|
||||
}
|
||||
addVoidFn("delay") {
|
||||
val a = args.firstAndOnly()
|
||||
when (a) {
|
||||
|
||||
@@ -1089,7 +1089,6 @@ class BytecodeCompiler(
|
||||
|
||||
private fun isDelegateClass(receiverClass: ObjClass): Boolean =
|
||||
receiverClass.className == "Delegate" ||
|
||||
receiverClass.className == "LazyDelegate" ||
|
||||
receiverClass.implementingNames.contains("Delegate")
|
||||
|
||||
private fun operatorMemberName(op: BinOp): String? = when (op) {
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package net.sergeych.lyng.obj
|
||||
|
||||
import net.sergeych.lyng.Arguments
|
||||
import net.sergeych.lyng.BytecodeBodyProvider
|
||||
import net.sergeych.lyng.Pos
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.Statement
|
||||
import net.sergeych.lyng.bytecode.BytecodeStatement
|
||||
import net.sergeych.lyng.Visibility
|
||||
import net.sergeych.lyng.executeBytecodeWithSeed
|
||||
|
||||
/**
|
||||
* Lazy delegate used by `val x by lazy { ... }`.
|
||||
*/
|
||||
class ObjLazyDelegate(
|
||||
private val builder: Obj,
|
||||
private val capturedScope: Scope,
|
||||
) : Obj() {
|
||||
override val objClass: ObjClass = type
|
||||
|
||||
private var calculated = false
|
||||
private var cachedValue: Obj = ObjVoid
|
||||
|
||||
override suspend fun invokeInstanceMethod(
|
||||
scope: Scope,
|
||||
name: String,
|
||||
args: Arguments,
|
||||
onNotFoundResult: (suspend () -> Obj?)?,
|
||||
): Obj {
|
||||
return when (name) {
|
||||
"bind" -> {
|
||||
val access = args.getOrNull(1)?.toString() ?: ""
|
||||
if (!access.endsWith("Val")) {
|
||||
scope.raiseIllegalArgument("lazy delegate can only be used with 'val'")
|
||||
}
|
||||
this
|
||||
}
|
||||
"getValue" -> {
|
||||
if (!calculated) {
|
||||
val receiver = args.getOrNull(0) ?: ObjNull
|
||||
val callScope = scope.createChildScope(
|
||||
scope.pos,
|
||||
args = Arguments.EMPTY,
|
||||
newThisObj = receiver
|
||||
)
|
||||
cachedValue = if (builder is BytecodeStatement || builder is BytecodeBodyProvider) {
|
||||
executeBytecodeWithSeed(callScope, builder as Statement, "lazy delegate")
|
||||
} else {
|
||||
builder.invoke(callScope, receiver, Arguments.EMPTY)
|
||||
}
|
||||
calculated = true
|
||||
}
|
||||
cachedValue
|
||||
}
|
||||
"setValue" -> scope.raiseIllegalAssignment("lazy delegate is read-only")
|
||||
else -> super.invokeInstanceMethod(scope, name, args, onNotFoundResult)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val type = ObjClass("LazyDelegate").apply {
|
||||
implementingNames.add("Delegate")
|
||||
createField(
|
||||
"getValue",
|
||||
ObjNull,
|
||||
isMutable = false,
|
||||
visibility = Visibility.Public,
|
||||
pos = Pos.builtIn,
|
||||
declaringClass = this,
|
||||
type = ObjRecord.Type.Fun
|
||||
)
|
||||
createField(
|
||||
"setValue",
|
||||
ObjNull,
|
||||
isMutable = false,
|
||||
visibility = Visibility.Public,
|
||||
pos = Pos.builtIn,
|
||||
declaringClass = this,
|
||||
type = ObjRecord.Type.Fun
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user