fixed extending extern classes (extension methods)
This commit is contained in:
1 parent
8e0442670d
commit
d2a47d34a3
3 files changed
+288
-130
No files matched your search
@@ -1120,7 +1120,16 @@ class Compiler(
|
||||
if (implicitType != null) {
|
||||
resolutionSink?.referenceMember(name, pos, implicitType)
|
||||
val ids = resolveImplicitThisMemberIds(name, pos, implicitType)
|
||||
return ImplicitThisMemberRef(name, pos, ids.fieldId, ids.methodId, implicitType)
|
||||
val inClassContext = codeContexts.any { ctx -> ctx is CodeContext.ClassBody }
|
||||
val currentImplicitType = currentImplicitThisTypeName()
|
||||
val preferredType = when {
|
||||
inClassContext -> implicitType
|
||||
// Extension receiver aliases (extern class name -> host runtime class) can fail strict
|
||||
// variant casts; keep current receiver untyped but preserve non-current receivers.
|
||||
implicitType == currentImplicitType -> null
|
||||
else -> implicitType
|
||||
}
|
||||
return ImplicitThisMemberRef(name, pos, ids.fieldId, ids.methodId, preferredType)
|
||||
}
|
||||
if (classCtx != null && classCtx.classScopeMembers.contains(name)) {
|
||||
resolutionSink?.referenceMember(name, pos, classCtx.name)
|
||||
@@ -4779,6 +4788,11 @@ class Compiler(
|
||||
if (payload != null) return payload
|
||||
}
|
||||
val receiverClass = resolveReceiverClassForMember(ref.receiver)
|
||||
classMethodReturnClass(receiverClass, ref.name)?.let { return it }
|
||||
inferFieldReturnClass(receiverClass, ref.name)?.let { return it }
|
||||
if (receiverClass != null && isClassScopeCallableMember(receiverClass.className, ref.name)) {
|
||||
resolveClassByName("${receiverClass.className}.${ref.name}")?.let { return it }
|
||||
}
|
||||
return inferMethodCallReturnClass(ref.name)
|
||||
}
|
||||
|
||||
|
||||
@@ -1067,18 +1067,9 @@ class BytecodeCompiler(
|
||||
updateSlotType(dst, SlotType.OBJ)
|
||||
return CompiledValue(dst, SlotType.OBJ)
|
||||
}
|
||||
if (receiverClass == null && memberName == "negate") {
|
||||
val zeroId = builder.addConst(BytecodeConst.IntVal(0))
|
||||
val zeroSlot = allocSlot()
|
||||
builder.emit(Opcode.CONST_INT, zeroId, zeroSlot)
|
||||
updateSlotType(zeroSlot, SlotType.INT)
|
||||
val obj = ensureObjSlot(value)
|
||||
val dst = allocSlot()
|
||||
builder.emit(Opcode.SUB_OBJ, zeroSlot, obj.slot, dst)
|
||||
updateSlotType(dst, SlotType.OBJ)
|
||||
return CompiledValue(dst, SlotType.OBJ)
|
||||
}
|
||||
if (memberName == "negate" && receiverClass in setOf(ObjInt.type, ObjReal.type)) {
|
||||
if (memberName == "negate" &&
|
||||
(receiverClass == null || isDelegateClass(receiverClass) || receiverClass in setOf(ObjInt.type, ObjReal.type))
|
||||
) {
|
||||
val zeroId = builder.addConst(BytecodeConst.IntVal(0))
|
||||
val zeroSlot = allocSlot()
|
||||
builder.emit(Opcode.CONST_INT, zeroId, zeroSlot)
|
||||
@@ -1095,6 +1086,11 @@ 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) {
|
||||
BinOp.PLUS -> "plus"
|
||||
BinOp.MINUS -> "minus"
|
||||
@@ -1142,11 +1138,7 @@ class BytecodeCompiler(
|
||||
): CompiledValue? {
|
||||
val memberName = operatorMemberName(op) ?: return null
|
||||
val receiverClass = resolveReceiverClass(leftRef)
|
||||
if (receiverClass == null ||
|
||||
receiverClass.className == "Delegate" ||
|
||||
receiverClass.className == "LazyDelegate" ||
|
||||
receiverClass.implementingNames.contains("Delegate")
|
||||
) {
|
||||
if (receiverClass == null || isDelegateClass(receiverClass)) {
|
||||
val objOpcode = when (op) {
|
||||
BinOp.PLUS -> Opcode.ADD_OBJ
|
||||
BinOp.MINUS -> Opcode.SUB_OBJ
|
||||
@@ -4821,9 +4813,26 @@ class BytecodeCompiler(
|
||||
|
||||
private data class CallArgs(val base: Int, val count: Int, val planId: Int?)
|
||||
|
||||
private fun resolveExtensionCallableSlot(receiverClass: ObjClass, memberName: String): CompiledValue? {
|
||||
private fun extensionReceiverTypeNames(receiverClass: ObjClass): Set<String> {
|
||||
val names = LinkedHashSet<String>()
|
||||
for (cls in receiverClass.mro) {
|
||||
val candidate = extensionCallableName(cls.className, memberName)
|
||||
names.add(cls.className)
|
||||
for ((knownName, knownClass) in nameObjClass) {
|
||||
if (knownClass !== cls && knownClass.className != cls.className) continue
|
||||
names.add(knownName)
|
||||
names.add(knownName.substringAfterLast('.'))
|
||||
}
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
private fun resolveExtensionSlotByReceiverNames(
|
||||
receiverClass: ObjClass,
|
||||
memberName: String,
|
||||
wrapperName: (String, String) -> String
|
||||
): CompiledValue? {
|
||||
for (receiverName in extensionReceiverTypeNames(receiverClass)) {
|
||||
val candidate = wrapperName(receiverName, memberName)
|
||||
if (allowedScopeNames != null &&
|
||||
!allowedScopeNames.contains(candidate) &&
|
||||
!localSlotIndexByName.containsKey(candidate)
|
||||
@@ -4835,32 +4844,39 @@ class BytecodeCompiler(
|
||||
return null
|
||||
}
|
||||
|
||||
private fun resolveUniqueExtensionWrapperSlot(
|
||||
memberName: String,
|
||||
wrapperPrefix: String
|
||||
): CompiledValue? {
|
||||
val suffix = "__$memberName"
|
||||
val candidates = LinkedHashSet<String>()
|
||||
for (name in localSlotIndexByName.keys) {
|
||||
if (name.startsWith(wrapperPrefix) && name.endsWith(suffix)) {
|
||||
candidates.add(name)
|
||||
}
|
||||
}
|
||||
for (name in scopeSlotIndexByName.keys) {
|
||||
if (name.startsWith(wrapperPrefix) && name.endsWith(suffix)) {
|
||||
candidates.add(name)
|
||||
}
|
||||
}
|
||||
if (candidates.size != 1) return null
|
||||
return resolveDirectNameSlot(candidates.first())
|
||||
}
|
||||
|
||||
private fun resolveExtensionCallableSlot(receiverClass: ObjClass, memberName: String): CompiledValue? {
|
||||
return resolveExtensionSlotByReceiverNames(receiverClass, memberName, ::extensionCallableName)
|
||||
?: resolveUniqueExtensionWrapperSlot(memberName, "__ext__")
|
||||
}
|
||||
|
||||
private fun resolveExtensionGetterSlot(receiverClass: ObjClass, memberName: String): CompiledValue? {
|
||||
for (cls in receiverClass.mro) {
|
||||
val candidate = extensionPropertyGetterName(cls.className, memberName)
|
||||
if (allowedScopeNames != null &&
|
||||
!allowedScopeNames.contains(candidate) &&
|
||||
!localSlotIndexByName.containsKey(candidate)
|
||||
) {
|
||||
continue
|
||||
}
|
||||
resolveDirectNameSlot(candidate)?.let { return it }
|
||||
}
|
||||
return null
|
||||
return resolveExtensionSlotByReceiverNames(receiverClass, memberName, ::extensionPropertyGetterName)
|
||||
?: resolveUniqueExtensionWrapperSlot(memberName, "__ext_get__")
|
||||
}
|
||||
|
||||
private fun resolveExtensionSetterSlot(receiverClass: ObjClass, memberName: String): CompiledValue? {
|
||||
for (cls in receiverClass.mro) {
|
||||
val candidate = extensionPropertySetterName(cls.className, memberName)
|
||||
if (allowedScopeNames != null &&
|
||||
!allowedScopeNames.contains(candidate) &&
|
||||
!localSlotIndexByName.containsKey(candidate)
|
||||
) {
|
||||
continue
|
||||
}
|
||||
resolveDirectNameSlot(candidate)?.let { return it }
|
||||
}
|
||||
return null
|
||||
return resolveExtensionSlotByReceiverNames(receiverClass, memberName, ::extensionPropertySetterName)
|
||||
?: resolveUniqueExtensionWrapperSlot(memberName, "__ext_set__")
|
||||
}
|
||||
|
||||
private fun compileCallArgsWithReceiver(
|
||||
@@ -7468,7 +7484,7 @@ class BytecodeCompiler(
|
||||
if (targetClass == null) return null
|
||||
if (targetClass == ObjDynamic.type) return ObjDynamic.type
|
||||
classFieldTypesByName[targetClass.className]?.get(name)?.let { cls ->
|
||||
if (cls.className == "Delegate" || cls.className == "LazyDelegate" || cls.implementingNames.contains("Delegate")) {
|
||||
if (isDelegateClass(cls)) {
|
||||
return null
|
||||
}
|
||||
return cls
|
||||
@@ -7555,8 +7571,8 @@ class BytecodeCompiler(
|
||||
|
||||
private fun queueExtensionCallableNames(receiverClass: ObjClass, memberName: String) {
|
||||
if (!useScopeSlots && globalSlotInfo.isEmpty()) return
|
||||
for (cls in receiverClass.mro) {
|
||||
val name = extensionCallableName(cls.className, memberName)
|
||||
for (receiverName in extensionReceiverTypeNames(receiverClass)) {
|
||||
val name = extensionCallableName(receiverName, memberName)
|
||||
if (allowedScopeNames == null || allowedScopeNames.contains(name)) {
|
||||
pendingScopeNameRefs.add(name)
|
||||
}
|
||||
@@ -7565,12 +7581,12 @@ class BytecodeCompiler(
|
||||
|
||||
private fun queueExtensionPropertyNames(receiverClass: ObjClass, memberName: String) {
|
||||
if (!useScopeSlots && globalSlotInfo.isEmpty()) return
|
||||
for (cls in receiverClass.mro) {
|
||||
val getter = extensionPropertyGetterName(cls.className, memberName)
|
||||
for (receiverName in extensionReceiverTypeNames(receiverClass)) {
|
||||
val getter = extensionPropertyGetterName(receiverName, memberName)
|
||||
if (allowedScopeNames == null || allowedScopeNames.contains(getter)) {
|
||||
pendingScopeNameRefs.add(getter)
|
||||
}
|
||||
val setter = extensionPropertySetterName(cls.className, memberName)
|
||||
val setter = extensionPropertySetterName(receiverName, memberName)
|
||||
if (allowedScopeNames == null || allowedScopeNames.contains(setter)) {
|
||||
pendingScopeNameRefs.add(setter)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user