avoid suspend lambdas in var declaration statements

This commit is contained in:
Sergey Chernov 2026-01-24 19:04:22 +03:00
parent 062f9e7866
commit 9b580bafb6

View File

@ -3472,22 +3472,42 @@ class Compiler(
}
}
return statement(start) { context ->
return object : Statement() {
override val pos: Pos = start
override suspend fun execute(context: Scope): Obj {
if (extTypeName != null) {
val prop = if (getter != null || setter != null) {
ObjProperty(name, getter, setter)
} else {
// Simple val extension with initializer
val initExpr = initialExpression ?: throw ScriptError(start, "Extension val must be initialized")
ObjProperty(name, statement(initExpr.pos) { scp -> initExpr.execute(scp) }, null)
ObjProperty(
name,
object : Statement() {
override val pos: Pos = initExpr.pos
override suspend fun execute(scp: Scope): Obj = initExpr.execute(scp)
},
null
)
}
val type = context[extTypeName]?.value ?: context.raiseSymbolNotFound("class $extTypeName not found")
if (type !is ObjClass) context.raiseClassCastError("$extTypeName is not the class instance")
context.addExtension(type, name, ObjRecord(prop, isMutable = false, visibility = visibility, writeVisibility = setterVisibility, declaringClass = null, type = ObjRecord.Type.Property))
context.addExtension(
type,
name,
ObjRecord(
prop,
isMutable = false,
visibility = visibility,
writeVisibility = setterVisibility,
declaringClass = null,
type = ObjRecord.Type.Property
)
)
return@statement prop
return prop
}
// In true class bodies (not inside a function), store fields under a class-qualified key to support MI collisions
// Do NOT infer declaring class from runtime thisObj here; only the compile-time captured
@ -3522,12 +3542,18 @@ class Compiler(
isClosed = isClosed,
isOverride = isOverride
)
cls.instanceInitializers += statement(start) { scp ->
cls.instanceInitializers += object : Statement() {
override val pos: Pos = start
override suspend fun execute(scp: Scope): Obj {
val initValue = initialExpression!!.execute(scp)
val accessTypeStr = if (isMutable) "Var" else "Val"
val accessType = scp.resolveQualifiedIdentifier("DelegateAccess.$accessTypeStr")
val finalDelegate = try {
initValue.invokeInstanceMethod(scp, "bind", Arguments(ObjString(name), accessType, scp.thisObj))
initValue.invokeInstanceMethod(
scp,
"bind",
Arguments(ObjString(name), accessType, scp.thisObj)
)
} catch (e: Exception) {
initValue
}
@ -3541,15 +3567,20 @@ class Compiler(
).apply {
delegate = finalDelegate
}
ObjVoid
return ObjVoid
}
return@statement ObjVoid
}
return ObjVoid
} else {
val initValue = initialExpression!!.execute(context)
val accessTypeStr = if (isMutable) "Var" else "Val"
val accessType = context.resolveQualifiedIdentifier("DelegateAccess.$accessTypeStr")
val finalDelegate = try {
initValue.invokeInstanceMethod(context, "bind", Arguments(ObjString(name), accessType, context.thisObj))
initValue.invokeInstanceMethod(
context,
"bind",
Arguments(ObjString(name), accessType, context.thisObj)
)
} catch (e: Exception) {
initValue
}
@ -3562,7 +3593,7 @@ class Compiler(
isTransient = isTransient
)
rec.delegate = finalDelegate
return@statement finalDelegate
return finalDelegate
}
} else {
val initValue = initialExpression!!.execute(context)
@ -3582,7 +3613,7 @@ class Compiler(
isTransient = isTransient
)
rec.delegate = finalDelegate
return@statement finalDelegate
return finalDelegate
}
} else if (getter != null || setter != null) {
val declaringClassName = declaringClassNameCaptured!!
@ -3622,7 +3653,9 @@ class Compiler(
// Register the property/field initialization thunk
if (!isAbstract) {
cls.instanceInitializers += statement(start) { scp ->
cls.instanceInitializers += object : Statement() {
override val pos: Pos = start
override suspend fun execute(scp: Scope): Obj {
scp.addItem(
storageName,
isMutable,
@ -3634,10 +3667,11 @@ class Compiler(
isClosed = isClosed,
isOverride = isOverride
)
ObjVoid
return ObjVoid
}
}
ObjVoid
}
return ObjVoid
} else {
// We are in instance scope already: perform initialization immediately
context.addItem(
@ -3648,7 +3682,7 @@ class Compiler(
isOverride = isOverride,
isTransient = isTransient
)
prop
return prop
}
} else {
val isLateInitVal = !isMutable && initialExpression == null
@ -3675,7 +3709,9 @@ class Compiler(
// Defer: at instance construction, evaluate initializer in instance scope and store under mangled name
if (!isAbstract) {
val initStmt = statement(start) { scp ->
val initStmt = object : Statement() {
override val pos: Pos = start
override suspend fun execute(scp: Scope): Obj {
val initValue =
initialExpression?.execute(scp)?.byValueCopy()
?: if (isLateInitVal) ObjUnset else ObjNull
@ -3688,15 +3724,17 @@ class Compiler(
isOverride = isOverride,
isTransient = isTransient
)
ObjVoid
return ObjVoid
}
}
cls.instanceInitializers += initStmt
}
ObjVoid
return ObjVoid
} else {
// We are in instance scope already: perform initialization immediately
val initValue =
initialExpression?.execute(context)?.byValueCopy() ?: if (isLateInitVal) ObjUnset else ObjNull
initialExpression?.execute(context)?.byValueCopy()
?: if (isLateInitVal) ObjUnset else ObjNull
// Preserve mutability of declaration: create record with correct mutability
context.addItem(
storageName, isMutable, initValue, visibility, setterVisibility,
@ -3706,13 +3744,14 @@ class Compiler(
isOverride = isOverride,
isTransient = isTransient
)
initValue
return initValue
}
} else {
// Not in class body: regular local/var declaration
val initValue = initialExpression?.execute(context)?.byValueCopy() ?: ObjNull
context.addItem(name, isMutable, initValue, visibility, recordType = ObjRecord.Type.Other, isTransient = isTransient)
initValue
return initValue
}
}
}
}