Implement qualified cast views for MI

This commit is contained in:
sergeych committed 2026-02-04 23:31:41 +03:00
1 parent 308a9c0bcb
commit 43a6a7aaf4
28 files changed
+400 -341

No files matched your search

@@ -21,6 +21,7 @@ import net.sergeych.lyng.obj.Obj
class ClassDeclStatement(
private val delegate: Statement,
private val startPos: Pos,
val declaredName: String?,
) : Statement() {
override val pos: Pos = startPos
@@ -145,6 +145,10 @@ class Compiler(
if (!record.visibility.isPublic) continue
if (plan.slots.containsKey(name)) continue
declareSlotNameIn(plan, name, record.isMutable, record.type == ObjRecord.Type.Delegated)
val instance = record.value as? ObjInstance
if (instance != null && nameObjClass[name] == null) {
nameObjClass[name] = instance.objClass
}
}
for ((cls, map) in current.extensions) {
for ((name, record) in map) {
@@ -457,6 +461,13 @@ class Compiler(
return MemberIds(fieldId, methodId)
}
if (qualifier != null) {
val classCtx = codeContexts.asReversed()
.firstOrNull { it is CodeContext.ClassBody && it.name == qualifier } as? CodeContext.ClassBody
if (classCtx != null) {
val fieldId = classCtx.memberFieldIds[name]
val methodId = classCtx.memberMethodIds[name]
if (fieldId != null || methodId != null) return MemberIds(fieldId, methodId)
}
val info = resolveCompileClassInfo(qualifier)
?: if (allowUnresolvedRefs) return MemberIds(null, null) else throw ScriptError(pos, "unknown type $qualifier")
val fieldId = info.fieldIds[name]
@@ -630,6 +641,14 @@ class Compiler(
val ids = resolveMemberIds(name, pos, null)
return ImplicitThisMemberRef(name, pos, ids.fieldId, ids.methodId, currentImplicitThisTypeName())
}
if (classCtx != null) {
val implicitType = classCtx.name
if (hasImplicitThisMember(name, implicitType)) {
resolutionSink?.referenceMember(name, pos, implicitType)
val ids = resolveImplicitThisMemberIds(name, pos, implicitType)
return ImplicitThisMemberRef(name, pos, ids.fieldId, ids.methodId, implicitType)
}
}
val implicitThisMembers = codeContexts.any { ctx ->
(ctx as? CodeContext.Function)?.implicitThisMembers == true
}
@@ -1190,6 +1209,14 @@ class Compiler(
private fun resolveImplicitThisMemberIds(name: String, pos: Pos, implicitTypeName: String?): MemberIds {
if (implicitTypeName == null) return resolveMemberIds(name, pos, null)
val classCtx = codeContexts.asReversed().firstOrNull { it is CodeContext.ClassBody } as? CodeContext.ClassBody
if (classCtx != null && classCtx.name == implicitTypeName) {
val fieldId = classCtx.memberFieldIds[name]
val methodId = classCtx.memberMethodIds[name]
if (fieldId != null || methodId != null) {
return MemberIds(fieldId, methodId)
}
}
val info = resolveCompileClassInfo(implicitTypeName)
val fieldId = info?.fieldIds?.get(name)
val methodId = info?.methodIds?.get(name)
@@ -1211,6 +1238,12 @@ class Compiler(
private fun hasImplicitThisMember(name: String, implicitTypeName: String?): Boolean {
if (implicitTypeName == null) return false
val classCtx = codeContexts.asReversed().firstOrNull { it is CodeContext.ClassBody } as? CodeContext.ClassBody
if (classCtx != null && classCtx.name == implicitTypeName) {
if (classCtx.memberFieldIds.containsKey(name) || classCtx.memberMethodIds.containsKey(name)) {
return true
}
}
val info = resolveCompileClassInfo(implicitTypeName)
if (info != null && (info.fieldIds.containsKey(name) || info.methodIds.containsKey(name))) return true
val cls = resolveClassByName(implicitTypeName)
@@ -1480,7 +1513,11 @@ class Compiler(
is ConditionalRef ->
containsUnsupportedRef(ref.condition) || containsUnsupportedRef(ref.ifTrue) || containsUnsupportedRef(ref.ifFalse)
is ElvisRef -> containsUnsupportedRef(ref.left) || containsUnsupportedRef(ref.right)
is FieldRef -> containsUnsupportedRef(ref.target)
is FieldRef -> {
val receiverClass = resolveReceiverClassForMember(ref.target)
if (receiverClass == ObjDynamic.type) return true
containsUnsupportedRef(ref.target)
}
is IndexRef -> containsUnsupportedRef(ref.targetRef) || containsUnsupportedRef(ref.indexRef)
is ListLiteralRef -> ref.entries().any {
when (it) {
@@ -1495,7 +1532,13 @@ class Compiler(
}
}
is CallRef -> containsUnsupportedRef(ref.target) || ref.args.any { containsUnsupportedForBytecode(it.value) }
is MethodCallRef -> containsUnsupportedRef(ref.receiver) || ref.args.any { containsUnsupportedForBytecode(it.value) }
is MethodCallRef -> {
val receiverClass = resolveReceiverClassForMember(ref.receiver)
if (receiverClass == ObjDynamic.type) return true
containsUnsupportedRef(ref.receiver) || ref.args.any { containsUnsupportedForBytecode(it.value) }
}
is QualifiedThisMethodSlotCallRef -> true
is QualifiedThisFieldSlotRef -> true
else -> false
}
}
@@ -3255,6 +3298,7 @@ class Compiler(
private fun inferFieldReturnClass(targetClass: ObjClass?, name: String): ObjClass? {
if (targetClass == null) return null
if (targetClass == ObjDynamic.type) return ObjDynamic.type
classFieldTypesByName[targetClass.className]?.get(name)?.let { return it }
enumEntriesByName[targetClass.className]?.let { entries ->
return when {
@@ -4632,7 +4676,7 @@ class Compiler(
return instance
}
}
return ClassDeclStatement(declStatement, startPos)
return ClassDeclStatement(declStatement, startPos, className)
}
private suspend fun parseClassDeclaration(isAbstract: Boolean = false, isExtern: Boolean = false): Statement {
@@ -4691,6 +4735,7 @@ class Compiler(
val baseSpecs = mutableListOf<BaseSpec>()
pendingTypeParamStack.add(classTypeParams)
slotPlanStack.add(classSlotPlan)
try {
if (cc.skipTokenOfType(Token.Type.COLON, isOptional = true)) {
do {
@@ -4710,6 +4755,7 @@ class Compiler(
} while (cc.skipTokenOfType(Token.Type.COMMA, isOptional = true))
}
} finally {
slotPlanStack.removeLast()
pendingTypeParamStack.removeLast()
}
@@ -5016,7 +5062,7 @@ class Compiler(
return newClass
}
}
ClassDeclStatement(classDeclStatement, startPos)
ClassDeclStatement(classDeclStatement, startPos, nameToken.value)
}
}
@@ -5397,12 +5443,10 @@ class Compiler(
resolutionSink?.declareSymbol(name, declKind, isMutable = false, pos = nameStartPos, isOverride = isOverride)
if (parentContext is CodeContext.ClassBody && extTypeName == null) {
parentContext.declaredMembers.add(name)
if (!isStatic) {
if (!parentContext.memberMethodIds.containsKey(name)) {
parentContext.memberMethodIds[name] = parentContext.nextMethodId++
}
memberMethodId = parentContext.memberMethodIds[name]
if (!parentContext.memberMethodIds.containsKey(name)) {
parentContext.memberMethodIds[name] = parentContext.nextMethodId++
}
memberMethodId = parentContext.memberMethodIds[name]
}
if (declKind != SymbolKind.MEMBER) {
declareLocalName(name, isMutable = false)
@@ -5494,11 +5538,16 @@ class Compiler(
miniSink?.onEnterFunction(node)
val implicitThisMembers = extTypeName != null || (parentContext is CodeContext.ClassBody && !isStatic)
val implicitThisTypeName = when {
extTypeName != null -> extTypeName
parentContext is CodeContext.ClassBody && !isStatic -> parentContext.name
else -> null
}
return inCodeContext(
CodeContext.Function(
name,
implicitThisMembers = implicitThisMembers,
implicitThisTypeName = extTypeName,
implicitThisTypeName = implicitThisTypeName,
typeParams = typeParams,
typeParamDecls = typeParamDecls
)
@@ -5932,7 +5981,7 @@ class Compiler(
}
val initRef = (initStmt as? ExpressionStatement)?.ref
return when (initRef) {
is StatementRef -> (initRef.statement as? ExpressionStatement)?.ref
is StatementRef -> (initRef.statement as? ExpressionStatement)?.ref ?: initRef
else -> initRef
}
}
@@ -5956,11 +6005,18 @@ class Compiler(
else -> Obj.rootObjectType
}
}
if (unwrapped is ClassDeclStatement) {
unwrapped.declaredName?.let { return resolveClassByName(it) }
}
val directRef = unwrapDirectRef(unwrapped)
return when (directRef) {
is ListLiteralRef -> ObjList.type
is MapLiteralRef -> ObjMap.type
is RangeRef -> ObjRange.type
is StatementRef -> {
val decl = directRef.statement as? ClassDeclStatement
decl?.declaredName?.let { resolveClassByName(it) }
}
is ValueFnRef -> lambdaReturnTypeByRef[directRef]
is CastRef -> resolveTypeRefClass(directRef.castTypeRef())
is BinaryOpRef -> inferBinaryOpReturnClass(directRef)
@@ -5988,6 +6044,9 @@ class Compiler(
when (target.name) {
"lazy" -> ObjLazyDelegate.type
"iterator" -> ObjIterator
"flow" -> ObjFlow.type
"launch" -> ObjDeferred.type
"dynamic" -> ObjDynamic.type
else -> callableReturnTypeByScopeId[target.scopeId]?.get(target.slot)
?: resolveClassByName(target.name)
}
@@ -5996,6 +6055,9 @@ class Compiler(
when (target.name) {
"lazy" -> ObjLazyDelegate.type
"iterator" -> ObjIterator
"flow" -> ObjFlow.type
"launch" -> ObjDeferred.type
"dynamic" -> ObjDynamic.type
else -> callableReturnTypeByName[target.name]
?: resolveClassByName(target.name)
}
@@ -6489,7 +6551,7 @@ class Compiler(
false
}
if (declaringClassNameCaptured != null && extTypeName == null && !isStatic) {
if (declaringClassNameCaptured != null && extTypeName == null) {
if (isDelegate || isProperty) {
if (classCtx != null) {
if (!classCtx.memberMethodIds.containsKey(name)) {
@@ -343,7 +343,7 @@ class Script(
result
}
addFn("dynamic") {
addFn("dynamic", callSignature = CallSignature(tailBlockReceiverType = "DelegateContext")) {
ObjDynamic.create(this, requireOnlyArg())
}
@@ -438,6 +438,8 @@ class Script(
addConst("Mutex", ObjMutex.type)
addConst("Flow", ObjFlow.type)
addConst("FlowBuilder", ObjFlowBuilder.type)
addConst("Delegate", ObjDynamic.type)
addConst("DelegateContext", ObjDynamicContext.type)
addConst("Regex", ObjRegex.type)
addConst("RegexMatch", ObjRegexMatch.type)
@@ -512,7 +512,10 @@ class BytecodeCompiler(
val typeObj = ensureObjSlot(typeValue)
if (!ref.castIsNullable()) {
builder.emit(Opcode.ASSERT_IS, objValue.slot, typeObj.slot)
return objValue
val resultSlot = allocSlot()
builder.emit(Opcode.MAKE_QUALIFIED_VIEW, objValue.slot, typeObj.slot, resultSlot)
updateSlotType(resultSlot, SlotType.OBJ)
return CompiledValue(resultSlot, SlotType.OBJ)
}
val checkSlot = allocSlot()
builder.emit(Opcode.CHECK_IS, objValue.slot, typeObj.slot, checkSlot)
@@ -529,7 +532,7 @@ class BytecodeCompiler(
builder.emit(Opcode.MOVE_OBJ, nullSlot, resultSlot)
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(endLabel)))
builder.mark(okLabel)
builder.emit(Opcode.MOVE_OBJ, objValue.slot, resultSlot)
builder.emit(Opcode.MAKE_QUALIFIED_VIEW, objValue.slot, typeObj.slot, resultSlot)
builder.mark(endLabel)
updateSlotType(resultSlot, SlotType.OBJ)
return CompiledValue(resultSlot, SlotType.OBJ)
@@ -116,7 +116,7 @@ class CmdBuilder {
Opcode.NEG_INT, Opcode.NEG_REAL, Opcode.NOT_BOOL, Opcode.INV_INT,
Opcode.ASSERT_IS ->
listOf(OperandKind.SLOT, OperandKind.SLOT)
Opcode.CHECK_IS ->
Opcode.CHECK_IS, Opcode.MAKE_QUALIFIED_VIEW ->
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
Opcode.RANGE_INT_BOUNDS ->
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
@@ -225,6 +225,7 @@ class CmdBuilder {
Opcode.MAKE_RANGE -> CmdMakeRange(operands[0], operands[1], operands[2], operands[3])
Opcode.CHECK_IS -> CmdCheckIs(operands[0], operands[1], operands[2])
Opcode.ASSERT_IS -> CmdAssertIs(operands[0], operands[1])
Opcode.MAKE_QUALIFIED_VIEW -> CmdMakeQualifiedView(operands[0], operands[1], operands[2])
Opcode.RET_LABEL -> CmdRetLabel(operands[0], operands[1])
Opcode.THROW -> CmdThrow(operands[0], operands[1])
Opcode.RESOLVE_SCOPE_SLOT -> CmdResolveScopeSlot(operands[0], operands[1])
@@ -74,6 +74,7 @@ object CmdDisassembler {
is CmdObjToBool -> Opcode.OBJ_TO_BOOL to intArrayOf(cmd.src, cmd.dst)
is CmdCheckIs -> Opcode.CHECK_IS to intArrayOf(cmd.objSlot, cmd.typeSlot, cmd.dst)
is CmdAssertIs -> Opcode.ASSERT_IS to intArrayOf(cmd.objSlot, cmd.typeSlot)
is CmdMakeQualifiedView -> Opcode.MAKE_QUALIFIED_VIEW to intArrayOf(cmd.objSlot, cmd.typeSlot, cmd.dst)
is CmdRangeIntBounds -> Opcode.RANGE_INT_BOUNDS to intArrayOf(cmd.src, cmd.startSlot, cmd.endSlot, cmd.okSlot)
is CmdMakeRange -> Opcode.MAKE_RANGE to intArrayOf(cmd.startSlot, cmd.endSlot, cmd.inclusiveSlot, cmd.dst)
is CmdResolveScopeSlot -> Opcode.RESOLVE_SCOPE_SLOT to intArrayOf(cmd.scopeSlot, cmd.addrSlot)
@@ -213,7 +214,7 @@ object CmdDisassembler {
listOf(OperandKind.SLOT, OperandKind.SLOT)
Opcode.OBJ_TO_BOOL, Opcode.ASSERT_IS ->
listOf(OperandKind.SLOT, OperandKind.SLOT)
Opcode.CHECK_IS ->
Opcode.CHECK_IS, Opcode.MAKE_QUALIFIED_VIEW ->
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
Opcode.RANGE_INT_BOUNDS, Opcode.MAKE_RANGE ->
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
@@ -232,6 +232,31 @@ class CmdAssertIs(internal val objSlot: Int, internal val typeSlot: Int) : Cmd()
}
}
class CmdMakeQualifiedView(
internal val objSlot: Int,
internal val typeSlot: Int,
internal val dst: Int,
) : Cmd() {
override suspend fun perform(frame: CmdFrame) {
val obj0 = frame.slotToObj(objSlot)
val typeObj = frame.slotToObj(typeSlot)
val clazz = typeObj as? ObjClass ?: frame.scope.raiseClassCastError(
"${typeObj.inspect(frame.scope)} is not the class instance"
)
val base = when (obj0) {
is ObjQualifiedView -> obj0.instance
else -> obj0
}
val result = if (base is ObjInstance && base.isInstanceOf(clazz)) {
ObjQualifiedView(base, clazz)
} else {
base
}
frame.storeObjResult(dst, result)
return
}
}
class CmdRangeIntBounds(
internal val src: Int,
internal val startSlot: Int,
@@ -1243,6 +1268,11 @@ class CmdGetMemberSlot(
} else null
} ?: frame.scope.raiseSymbolNotFound("member")
val name = rec.memberName ?: "<member>"
if (receiver is ObjQualifiedView) {
val resolved = receiver.readField(frame.scope, name)
frame.storeObjResult(dst, resolved.value)
return
}
val resolved = receiver.resolveRecord(frame.scope, rec, name, rec.declaringClass)
frame.storeObjResult(dst, resolved.value)
return
@@ -1267,6 +1297,10 @@ class CmdSetMemberSlot(
} else null
} ?: frame.scope.raiseSymbolNotFound("member")
val name = rec.memberName ?: "<member>"
if (receiver is ObjQualifiedView) {
receiver.writeField(frame.scope, name, frame.slotToObj(valueSlot))
return
}
frame.scope.assign(rec, name, frame.slotToObj(valueSlot))
return
}
@@ -1290,6 +1324,14 @@ class CmdCallMemberSlot(
?: frame.scope.raiseError("member id $methodId not found on ${receiver.objClass.className}")
val callArgs = frame.buildArguments(argBase, argCount)
val name = rec.memberName ?: "<member>"
if (receiver is ObjQualifiedView) {
val result = receiver.invokeInstanceMethod(frame.scope, name, callArgs)
if (frame.fn.localSlotNames.isNotEmpty()) {
frame.syncScopeToFrame()
}
frame.storeObjResult(dst, result)
return
}
val decl = rec.declaringClass ?: receiver.objClass
val result = when (rec.type) {
ObjRecord.Type.Property -> {
@@ -41,6 +41,7 @@ enum class Opcode(val code: Int) {
OBJ_TO_BOOL(0x14),
CHECK_IS(0x15),
ASSERT_IS(0x16),
MAKE_QUALIFIED_VIEW(0x17),
ADD_INT(0x20),
SUB_INT(0x21),
@@ -122,8 +122,12 @@ open class ObjDynamic(var readCallback: Statement? = null, var writeCallback: St
}
val type = object : ObjClass("Delegate") {}.apply {
addFn("getValue") { raiseError("Delegate.getValue is not implemented") }
addFn("setValue") { raiseError("Delegate.setValue is not implemented") }
addFn("invoke") { raiseError("Delegate.invoke is not implemented") }
addFn("bind") { raiseError("Delegate.bind is not implemented") }
// addClassConst("IndexGetName", operatorGetName)
}
}
}
}
@@ -191,12 +191,12 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
val d = decl ?: obj.declaringClass
if (d != null) {
val mangled = d.mangledName(name)
fieldRecordForKey(mangled)?.let {
targetRec = it
}
if (targetRec === obj) {
instanceScope.objects[mangled]?.let {
targetRec = it
val scoped = instanceScope.objects[mangled]
if (scoped != null) {
targetRec = scoped
} else {
fieldRecordForKey(mangled)?.let {
targetRec = it
}
}
}
@@ -598,7 +598,7 @@ class ObjQualifiedView(val instance: ObjInstance, private val startClass: ObjCla
override suspend fun readField(scope: Scope, name: String): ObjRecord {
// Qualified field access: prefer mangled storage for the qualified ancestor
val mangled = "${startClass.className}::$name"
instance.fieldRecordForKey(mangled)?.let { rec ->
instance.instanceScope.objects[mangled]?.let { rec ->
// Visibility: declaring class is the qualified ancestor for mangled storage
val decl = rec.declaringClass ?: startClass
val caller = scope.currentClassCtx
@@ -606,7 +606,7 @@ class ObjQualifiedView(val instance: ObjInstance, private val startClass: ObjCla
scope.raiseError(ObjIllegalAccessException(scope, "can't access field $name (declared in ${decl.className})"))
return instance.resolveRecord(scope, rec, name, decl)
}
instance.instanceScope.objects[mangled]?.let { rec ->
instance.fieldRecordForKey(mangled)?.let { rec ->
// Visibility: declaring class is the qualified ancestor for mangled storage
val decl = rec.declaringClass ?: startClass
val caller = scope.currentClassCtx
@@ -642,7 +642,7 @@ class ObjQualifiedView(val instance: ObjInstance, private val startClass: ObjCla
override suspend fun writeField(scope: Scope, name: String, newValue: Obj) {
// Qualified write: target mangled storage for the ancestor
val mangled = "${startClass.className}::$name"
instance.fieldRecordForKey(mangled)?.let { f ->
instance.instanceScope.objects[mangled]?.let { f ->
val decl = f.declaringClass ?: startClass
val caller = scope.currentClassCtx
if (!canAccessMember(f.effectiveWriteVisibility, decl, caller, name))
@@ -654,7 +654,7 @@ class ObjQualifiedView(val instance: ObjInstance, private val startClass: ObjCla
if (f.value.assign(scope, newValue) == null) f.value = newValue
return
}
instance.instanceScope.objects[mangled]?.let { f ->
instance.fieldRecordForKey(mangled)?.let { f ->
val decl = f.declaringClass ?: startClass
val caller = scope.currentClassCtx
if (!canAccessMember(f.effectiveWriteVisibility, decl, caller, name))
@@ -705,7 +705,15 @@ class ObjQualifiedView(val instance: ObjInstance, private val startClass: ObjCla
val saved = instance.instanceScope.currentClassCtx
instance.instanceScope.currentClassCtx = decl
try {
return rec.value.invoke(instance.instanceScope, instance, args)
return when (rec.type) {
ObjRecord.Type.Property -> {
if (args.isEmpty()) (rec.value as ObjProperty).callGetter(scope, instance, decl)
else scope.raiseError("property $name cannot be called with arguments")
}
ObjRecord.Type.Fun, ObjRecord.Type.Delegated ->
rec.value.invoke(instance.instanceScope, instance, args)
else -> scope.raiseError("member $name is not callable")
}
} finally {
instance.instanceScope.currentClassCtx = saved
}
@@ -522,6 +522,10 @@ class QualifiedThisFieldSlotRef(
fieldId?.let { id ->
val rec = inst.fieldRecordForId(id)
if (rec != null && (rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField) && !rec.isAbstract) {
val decl = rec.declaringClass ?: inst.objClass
if (!canAccessMember(rec.visibility, decl, scope.currentClassCtx, rec.memberName ?: name)) {
scope.raiseError(ObjIllegalAccessException(scope, "can't access field ${rec.memberName ?: name} (declared in ${decl.className})"))
}
return rec
}
}
@@ -529,6 +533,9 @@ class QualifiedThisFieldSlotRef(
val rec = inst.methodRecordForId(id)
if (rec != null && !rec.isAbstract) {
val decl = rec.declaringClass ?: inst.objClass
if (!canAccessMember(rec.visibility, decl, scope.currentClassCtx, rec.memberName ?: name)) {
scope.raiseError(ObjIllegalAccessException(scope, "can't access member ${rec.memberName ?: name} (declared in ${decl.className})"))
}
return inst.resolveRecord(scope, rec, rec.memberName ?: name, decl)
}
}
@@ -542,6 +549,10 @@ class QualifiedThisFieldSlotRef(
fieldId?.let { id ->
val rec = inst.fieldRecordForId(id)
if (rec != null) {
val decl = rec.declaringClass ?: inst.objClass
if (!canAccessMember(rec.effectiveWriteVisibility, decl, scope.currentClassCtx, rec.memberName ?: name)) {
scope.raiseError(ObjIllegalAccessException(scope, "can't assign to field ${rec.memberName ?: name} (declared in ${decl.className})"))
}
assignToRecord(scope, rec, newValue)
return
}
@@ -549,6 +560,10 @@ class QualifiedThisFieldSlotRef(
methodId?.let { id ->
val rec = inst.methodRecordForId(id)
if (rec != null) {
val decl = rec.declaringClass ?: inst.objClass
if (!canAccessMember(rec.effectiveWriteVisibility, decl, scope.currentClassCtx, rec.memberName ?: name)) {
scope.raiseError(ObjIllegalAccessException(scope, "can't assign to member ${rec.memberName ?: name} (declared in ${decl.className})"))
}
scope.assign(rec, rec.memberName ?: name, newValue)
return
}
@@ -597,6 +612,9 @@ class QualifiedThisMethodSlotCallRef(
val id = methodId ?: scope.raiseSymbolNotFound(name)
val rec = inst.methodRecordForId(id) ?: scope.raiseSymbolNotFound(name)
val decl = rec.declaringClass ?: inst.objClass
if (!canAccessMember(rec.visibility, decl, scope.currentClassCtx, rec.memberName ?: name)) {
scope.raiseError(ObjIllegalAccessException(scope, "can't invoke method ${rec.memberName ?: name} (declared in ${decl.className})"))
}
return when (rec.type) {
ObjRecord.Type.Property -> {
if (callArgs.isEmpty()) (rec.value as ObjProperty).callGetter(scope, inst, decl)