Add ObjCProtocol type to interop runtime
This commit is contained in:
committed by
SvyatoslavScherbina
parent
3c8e12328c
commit
d1222907d4
@@ -27,6 +27,8 @@ interface ObjCClass : ObjCObject
|
||||
interface ObjCClassOf<T : ObjCObject> : ObjCClass // TODO: T should be added to ObjCClass and all meta-classes instead.
|
||||
typealias ObjCObjectMeta = ObjCClass
|
||||
|
||||
interface ObjCProtocol : ObjCObject
|
||||
|
||||
@ExportTypeInfo("theForeignObjCObjectTypeInfo")
|
||||
@kotlin.native.internal.Frozen
|
||||
internal open class ForeignObjCObject : kotlin.native.internal.ObjCObjectWrapper
|
||||
|
||||
+1
@@ -191,6 +191,7 @@ object KotlinTypes {
|
||||
val objCObjectMeta by InteropClassifier
|
||||
val objCClass by InteropClassifier
|
||||
val objCClassOf by InteropClassifier
|
||||
val objCProtocol by InteropClassifier
|
||||
|
||||
val cValuesRef by InteropClassifier
|
||||
|
||||
|
||||
+10
@@ -490,6 +490,11 @@ abstract class ObjCContainerStub(stubGenerator: StubGenerator,
|
||||
supers.add(classifier.type)
|
||||
}
|
||||
|
||||
if (!isMeta && container.isProtocolClass()) {
|
||||
// TODO: map Protocol type to ObjCProtocol instead.
|
||||
supers.add(KotlinTypes.objCProtocol.type)
|
||||
}
|
||||
|
||||
val keywords = when (container) {
|
||||
is ObjCClass -> "open class"
|
||||
is ObjCProtocol -> "interface"
|
||||
@@ -690,3 +695,8 @@ private fun genProtocolGetter(
|
||||
|
||||
return functionName
|
||||
}
|
||||
|
||||
private fun ObjCClassOrProtocol.isProtocolClass(): Boolean = when (this) {
|
||||
is ObjCClass -> (name == "Protocol" || binaryName == "Protocol")
|
||||
is ObjCProtocol -> false
|
||||
}
|
||||
|
||||
+7
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.types.typeUtil.supertypes
|
||||
internal val interopPackageName = InteropFqNames.packageName
|
||||
internal val objCObjectFqName = interopPackageName.child(Name.identifier("ObjCObject"))
|
||||
private val objCClassFqName = interopPackageName.child(Name.identifier("ObjCClass"))
|
||||
private val objCProtocolFqName = interopPackageName.child(Name.identifier("ObjCProtocol"))
|
||||
internal val externalObjCClassFqName = interopPackageName.child(Name.identifier("ExternalObjCClass"))
|
||||
private val objCMethodFqName = interopPackageName.child(Name.identifier("ObjCMethod"))
|
||||
private val objCConstructorFqName = FqName("kotlinx.cinterop.ObjCConstructor")
|
||||
@@ -70,6 +71,12 @@ fun ClassDescriptor.isObjCMetaClass(): Boolean = this.getAllSuperClassifiers().a
|
||||
it.fqNameSafe == objCClassFqName
|
||||
}
|
||||
|
||||
fun IrClass.isObjCProtocolClass(): Boolean =
|
||||
this.fqNameSafe == objCProtocolFqName
|
||||
|
||||
fun ClassDescriptor.isObjCProtocolClass(): Boolean =
|
||||
this.fqNameSafe == objCProtocolFqName
|
||||
|
||||
fun FunctionDescriptor.isObjCClassMethod() =
|
||||
this.containingDeclaration.let { it is ClassDescriptor && it.isObjCClass() }
|
||||
|
||||
|
||||
+9
-5
@@ -9,7 +9,6 @@ package org.jetbrains.kotlin.backend.konan.llvm
|
||||
import kotlinx.cinterop.*
|
||||
import llvm.*
|
||||
import org.jetbrains.kotlin.backend.konan.*
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.objc.*
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
@@ -17,6 +16,7 @@ import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.konan.target.*
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.resolveFakeOverride
|
||||
import org.jetbrains.kotlin.backend.konan.ir.*
|
||||
import org.jetbrains.kotlin.descriptors.konan.CompiledKonanModuleOrigin
|
||||
|
||||
internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
|
||||
@@ -832,12 +832,11 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
||||
assert(!irClass.isInterface)
|
||||
|
||||
return if (irClass.isExternalObjCClass()) {
|
||||
context.llvm.imports.add(irClass.llvmSymbolOrigin)
|
||||
val llvmSymbolOrigin = irClass.llvmSymbolOrigin
|
||||
|
||||
if (irClass.isObjCMetaClass()) {
|
||||
val name = irClass.descriptor.getExternalObjCMetaClassBinaryName()
|
||||
|
||||
val objCClass = load(codegen.objCDataGenerator!!.genClassRef(name).llvm)
|
||||
val objCClass = getObjCClass(name, llvmSymbolOrigin)
|
||||
|
||||
val getClass = context.llvm.externalFunction(
|
||||
"object_getClass",
|
||||
@@ -847,7 +846,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
||||
|
||||
call(getClass, listOf(objCClass), exceptionHandler = exceptionHandler)
|
||||
} else {
|
||||
load(codegen.objCDataGenerator!!.genClassRef(irClass.descriptor.getExternalObjCClassBinaryName()).llvm)
|
||||
getObjCClass(irClass.descriptor.getExternalObjCClassBinaryName(), llvmSymbolOrigin)
|
||||
}
|
||||
} else {
|
||||
if (irClass.isObjCMetaClass()) {
|
||||
@@ -874,6 +873,11 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
||||
}
|
||||
}
|
||||
|
||||
fun getObjCClass(binaryName: String, llvmSymbolOrigin: CompiledKonanModuleOrigin): LLVMValueRef {
|
||||
context.llvm.imports.add(llvmSymbolOrigin)
|
||||
return load(codegen.objCDataGenerator!!.genClassRef(binaryName).llvm)
|
||||
}
|
||||
|
||||
fun resetDebugLocation() {
|
||||
if (!context.shouldContainDebugInfo()) return
|
||||
currentPositionHolder.resetBuilderDebugLocation()
|
||||
|
||||
+9
@@ -1403,6 +1403,15 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
call(isClass, listOf(objCObject)).let {
|
||||
functionGenerationContext.icmpNe(it, Int8(0).llvm)
|
||||
}
|
||||
} else if (dstClass.isObjCProtocolClass()) {
|
||||
// Note: it is not clear whether this class should be looked up this way.
|
||||
// clang does the same, however swiftc uses dynamic lookup.
|
||||
val protocolClass =
|
||||
functionGenerationContext.getObjCClass("Protocol", context.standardLlvmSymbolsOrigin)
|
||||
call(
|
||||
context.llvm.Kotlin_Interop_IsObjectKindOfClass,
|
||||
listOf(objCObject, protocolClass)
|
||||
)
|
||||
} else {
|
||||
kTrue
|
||||
}
|
||||
|
||||
+13
-4
@@ -801,16 +801,15 @@ internal class ObjCExportTranslatorImpl(
|
||||
// TODO: more precise types can be used.
|
||||
|
||||
if (descriptor.isObjCMetaClass()) return ObjCMetaClassType
|
||||
if (descriptor.isObjCProtocolClass()) return foreignClassType("Protocol")
|
||||
|
||||
if (descriptor.isExternalObjCClass() || descriptor.isObjCForwardDeclaration()) {
|
||||
return if (descriptor.isInterface) {
|
||||
val name = descriptor.name.asString().removeSuffix("Protocol")
|
||||
generator?.referenceProtocol(name)
|
||||
ObjCProtocolType(name)
|
||||
foreignProtocolType(name)
|
||||
} else {
|
||||
val name = descriptor.name.asString()
|
||||
generator?.referenceClass(name)
|
||||
ObjCClassType(name)
|
||||
foreignClassType(name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -821,6 +820,16 @@ internal class ObjCExportTranslatorImpl(
|
||||
return ObjCIdType
|
||||
}
|
||||
|
||||
private fun foreignProtocolType(name: String): ObjCProtocolType {
|
||||
generator?.referenceProtocol(name)
|
||||
return ObjCProtocolType(name)
|
||||
}
|
||||
|
||||
private fun foreignClassType(name: String): ObjCClassType {
|
||||
generator?.referenceClass(name)
|
||||
return ObjCClassType(name)
|
||||
}
|
||||
|
||||
internal fun mapFunctionTypeIgnoringNullability(
|
||||
functionType: KotlinType,
|
||||
objCExportScope: ObjCExportScope,
|
||||
|
||||
@@ -205,3 +205,11 @@ NSObject* createNSObject() {
|
||||
-(int)hashCode:(int)p;
|
||||
-(BOOL)equals;
|
||||
@end;
|
||||
|
||||
id getPrinterProtocolRaw() {
|
||||
return @protocol(Printer);
|
||||
}
|
||||
|
||||
Protocol* getPrinterProtocol() {
|
||||
return @protocol(Printer);
|
||||
}
|
||||
|
||||
@@ -151,6 +151,11 @@ fun testTypeOps() {
|
||||
assertTrue(NSObject.asAny() is ObjCClass)
|
||||
assertTrue(NSObject.asAny() is ObjCClassOf<*>)
|
||||
|
||||
assertFalse(Any() is ObjCProtocol)
|
||||
assertTrue(getPrinterProtocolRaw() is ObjCProtocol)
|
||||
val printerProtocol = getPrinterProtocol()!!
|
||||
assertTrue(printerProtocol.asAny() is ObjCProtocol)
|
||||
|
||||
assertEquals(3u, ("foo" as NSString).length())
|
||||
assertEquals(4u, ((1..4).joinToString("") as NSString).length())
|
||||
assertEquals(2u, (listOf(0, 1) as NSArray).count())
|
||||
|
||||
Reference in New Issue
Block a user