Properly handle extensions to inlined classes when producing framework
See https://github.com/JetBrains/kotlin-native/issues/2120#issuecomment-424262886
This commit is contained in:
committed by
SvyatoslavScherbina
parent
9b2a03b6cd
commit
080ecf0d11
+3
-6
@@ -11,12 +11,10 @@ import org.jetbrains.kotlin.backend.konan.*
|
|||||||
import org.jetbrains.kotlin.backend.konan.descriptors.allOverriddenDescriptors
|
import org.jetbrains.kotlin.backend.konan.descriptors.allOverriddenDescriptors
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.isArray
|
import org.jetbrains.kotlin.backend.konan.descriptors.isArray
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
|
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|
||||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||||
import org.jetbrains.kotlin.builtins.UnsignedType
|
import org.jetbrains.kotlin.builtins.UnsignedType
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.*
|
import org.jetbrains.kotlin.resolve.descriptorUtil.*
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
@@ -34,18 +32,17 @@ internal abstract class ObjCExportMapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ObjCExportMapper.isRepresentedAsObjCInterface(descriptor: ClassDescriptor): Boolean =
|
|
||||||
!descriptor.isInterface && !isSpecialMapped(descriptor)
|
|
||||||
|
|
||||||
internal fun ObjCExportMapper.getClassIfCategory(descriptor: CallableMemberDescriptor): ClassDescriptor? {
|
internal fun ObjCExportMapper.getClassIfCategory(descriptor: CallableMemberDescriptor): ClassDescriptor? {
|
||||||
if (descriptor.dispatchReceiverParameter != null) return null
|
if (descriptor.dispatchReceiverParameter != null) return null
|
||||||
|
|
||||||
val extensionReceiverType = descriptor.extensionReceiverParameter?.type ?: return null
|
val extensionReceiverType = descriptor.extensionReceiverParameter?.type ?: return null
|
||||||
|
|
||||||
|
// FIXME: this code must rely on type mapping instead of copying its logic.
|
||||||
|
|
||||||
if (extensionReceiverType.isObjCObjectType()) return null
|
if (extensionReceiverType.isObjCObjectType()) return null
|
||||||
|
|
||||||
val erasedClass = extensionReceiverType.getErasedTypeClass()
|
val erasedClass = extensionReceiverType.getErasedTypeClass()
|
||||||
return if (this.isRepresentedAsObjCInterface(erasedClass)) {
|
return if (!erasedClass.isInterface && !erasedClass.isInlined() && !this.isSpecialMapped(erasedClass)) {
|
||||||
erasedClass
|
erasedClass
|
||||||
} else {
|
} else {
|
||||||
// E.g. receiver is protocol, or some type with custom mapping.
|
// E.g. receiver is protocol, or some type with custom mapping.
|
||||||
|
|||||||
@@ -132,6 +132,9 @@ fun Any?.toString(): String = this?.toString() ?: "null"
|
|||||||
|
|
||||||
fun Any?.print() = println(this.toString())
|
fun Any?.print() = println(this.toString())
|
||||||
|
|
||||||
|
fun Char.boxChar(): Char? = this
|
||||||
|
fun Char?.isA(): Boolean = (this == 'A')
|
||||||
|
|
||||||
// Lambdas
|
// Lambdas
|
||||||
val sumLambda = { x: Int, y: Int -> x + y }
|
val sumLambda = { x: Int, y: Int -> x + y }
|
||||||
|
|
||||||
@@ -224,3 +227,12 @@ fun box(ic3: IC3): Any = ic3
|
|||||||
|
|
||||||
fun concatenateInlineClassValues(ic1: IC1, ic1N: IC1?, ic2: IC2, ic2N: IC2?, ic3: IC3, ic3N: IC3?): String =
|
fun concatenateInlineClassValues(ic1: IC1, ic1N: IC1?, ic2: IC2, ic2N: IC2?, ic3: IC3, ic3N: IC3?): String =
|
||||||
"${ic1.value} ${ic1N?.value} ${ic2.value} ${ic2N?.value} ${ic3.value} ${ic3N?.value}"
|
"${ic1.value} ${ic1N?.value} ${ic2.value} ${ic2N?.value} ${ic3.value} ${ic3N?.value}"
|
||||||
|
|
||||||
|
fun IC1.getValue1() = this.value
|
||||||
|
fun IC1?.getValueOrNull1() = this?.value
|
||||||
|
|
||||||
|
fun IC2.getValue2() = value
|
||||||
|
fun IC2?.getValueOrNull2() = this?.value
|
||||||
|
|
||||||
|
fun IC3.getValue3() = value
|
||||||
|
fun IC3?.getValueOrNull3() = this?.value
|
||||||
|
|||||||
@@ -314,6 +314,11 @@ func testAnyPrint() throws {
|
|||||||
print("END")
|
print("END")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testCharExtensions() throws {
|
||||||
|
try assertTrue(ValuesKt.isA(ValuesKt.boxChar(65)))
|
||||||
|
try assertFalse(ValuesKt.isA(ValuesKt.boxChar(66)))
|
||||||
|
}
|
||||||
|
|
||||||
func testLambda() throws {
|
func testLambda() throws {
|
||||||
try assertEquals(actual: ValuesKt.sumLambda(3, 4), expected: 7)
|
try assertEquals(actual: ValuesKt.sumLambda(3, 4), expected: 7)
|
||||||
}
|
}
|
||||||
@@ -404,6 +409,15 @@ func testInlineClasses() throws {
|
|||||||
actual: ValuesKt.concatenateInlineClassValues(ic1: ic1, ic1N: nil, ic2: ic2, ic2N: nil, ic3: nil, ic3N: nil),
|
actual: ValuesKt.concatenateInlineClassValues(ic1: ic1, ic1N: nil, ic2: ic2, ic2N: nil, ic3: nil, ic3N: nil),
|
||||||
expected: "42 null foo null null null"
|
expected: "42 null foo null null null"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
try assertEquals(actual: ValuesKt.getValue1(ic1), expected: 42)
|
||||||
|
try assertEquals(actual: ValuesKt.getValueOrNull1(ic1N) as! Int, expected: 17)
|
||||||
|
|
||||||
|
try assertEquals(actual: ValuesKt.getValue2(ic2), expected: "foo")
|
||||||
|
try assertEquals(actual: ValuesKt.getValueOrNull2(ic2N), expected: "bar")
|
||||||
|
|
||||||
|
try assertEquals(actual: ValuesKt.getValue3(ic3), expected: ic3)
|
||||||
|
try assertEquals(actual: ValuesKt.getValueOrNull3(ic3N), expected: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------- Execution of the test --------
|
// -------- Execution of the test --------
|
||||||
@@ -431,6 +445,7 @@ class ValuesTests : TestProvider {
|
|||||||
TestCase(name: "TestStringExtension", method: withAutorelease(testStrExtFun)),
|
TestCase(name: "TestStringExtension", method: withAutorelease(testStrExtFun)),
|
||||||
TestCase(name: "TestAnyToString", method: withAutorelease(testAnyToString)),
|
TestCase(name: "TestAnyToString", method: withAutorelease(testAnyToString)),
|
||||||
TestCase(name: "TestAnyPrint", method: withAutorelease(testAnyPrint)),
|
TestCase(name: "TestAnyPrint", method: withAutorelease(testAnyPrint)),
|
||||||
|
TestCase(name: "TestCharExtensions", method: withAutorelease(testCharExtensions)),
|
||||||
TestCase(name: "TestLambda", method: withAutorelease(testLambda)),
|
TestCase(name: "TestLambda", method: withAutorelease(testLambda)),
|
||||||
TestCase(name: "TestInterfaceExtension", method: withAutorelease(testInterfaceExtension)),
|
TestCase(name: "TestInterfaceExtension", method: withAutorelease(testInterfaceExtension)),
|
||||||
TestCase(name: "TestClassInstances", method: withAutorelease(testClassInstances)),
|
TestCase(name: "TestClassInstances", method: withAutorelease(testClassInstances)),
|
||||||
|
|||||||
Reference in New Issue
Block a user