Native: support Objective-C instancetype in more cases in cinterop
Objective-C has a special type, "instancetype". Generally, it is a type that matches the method receiver type. So, if `Foo.foo` method returns `instancetype`, then `Foo.foo()` would be of type `Foo`, while `Bar.foo()` would be of type `Bar` (where `Bar` is a subclass of `Foo`). Surprisingly, `instancetype` can be used not only as a return type, but also somewhere inside a return type. cinterop wasn't ready for this. This commit expands implementation of `instancetype` in cinterop to cover more cases. ^KT-59597 Fixed
This commit is contained in:
committed by
Space Team
parent
149e1e02f6
commit
2cdf8cd7b1
+29
-6
@@ -260,18 +260,41 @@ data class ObjCMethod(
|
||||
val isOptional: Boolean, val isInit: Boolean, val isExplicitlyDesignatedInitializer: Boolean, val isDirect: Boolean
|
||||
) {
|
||||
|
||||
fun returnsInstancetype(): Boolean = returnType is ObjCInstanceType
|
||||
fun containsInstancetype(): Boolean = returnType.containsInstancetype() // Clang doesn't allow parameter types to use instancetype.
|
||||
|
||||
fun getReturnType(container: ObjCClassOrProtocol): Type = if (returnType is ObjCInstanceType) {
|
||||
when (container) {
|
||||
is ObjCClass -> ObjCObjectPointer(container, returnType.nullability, protocols = emptyList())
|
||||
is ObjCProtocol -> ObjCIdType(returnType.nullability, protocols = listOf(container))
|
||||
}
|
||||
fun getReturnType(container: ObjCClassOrProtocol): Type = if (returnType.containsInstancetype()) {
|
||||
returnType.substituteInstancetype(container)
|
||||
} else {
|
||||
// Fast path, avoid allocating copies.
|
||||
returnType
|
||||
}
|
||||
}
|
||||
|
||||
// Clang seems to allow using instancetype only inside certain kinds of types.
|
||||
// The implementation below therefore covers only particular cases, based on the experiments with Clang and common sense.
|
||||
private fun Type.containsInstancetype(): Boolean = when (this) {
|
||||
is ObjCInstanceType -> true
|
||||
|
||||
is ObjCBlockPointer -> this.returnType.containsInstancetype()
|
||||
is FunctionType -> this.returnType.containsInstancetype()
|
||||
is PointerType -> this.pointeeType.containsInstancetype()
|
||||
|
||||
else -> false
|
||||
}
|
||||
|
||||
private fun Type.substituteInstancetype(container: ObjCClassOrProtocol): Type = when (this) {
|
||||
is ObjCInstanceType -> when (container) {
|
||||
is ObjCClass -> ObjCObjectPointer(container, this.nullability, protocols = emptyList())
|
||||
is ObjCProtocol -> ObjCIdType(this.nullability, protocols = listOf(container))
|
||||
}
|
||||
|
||||
is ObjCBlockPointer -> this.copy(returnType = this.returnType.substituteInstancetype(container))
|
||||
is FunctionType -> this.copy(returnType = this.returnType.substituteInstancetype(container))
|
||||
is PointerType -> this.copy(pointeeType = this.pointeeType.substituteInstancetype(container))
|
||||
|
||||
else -> this
|
||||
}
|
||||
|
||||
data class ObjCProperty(val name: String, val getter: ObjCMethod, val setter: ObjCMethod?) {
|
||||
fun getType(container: ObjCClassOrProtocol): Type = getter.getReturnType(container)
|
||||
}
|
||||
|
||||
+1
-1
@@ -388,7 +388,7 @@ internal abstract class ObjCContainerStubBuilder(
|
||||
methods -= superMethods
|
||||
|
||||
// Add some special methods from super types:
|
||||
methods += superMethods.filter { it.returnsInstancetype() || it.isInit }
|
||||
methods += superMethods.filter { it.containsInstancetype() || it.isInit }
|
||||
|
||||
// Add methods from adopted protocols that must be implemented according to Kotlin rules:
|
||||
if (container is ObjCClass) {
|
||||
|
||||
Reference in New Issue
Block a user