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:
Svyatoslav Scherbina
2018-09-25 14:41:30 +03:00
committed by SvyatoslavScherbina
parent 9b2a03b6cd
commit 080ecf0d11
3 changed files with 31 additions and 7 deletions
@@ -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.isArray
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.UnsignedType
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.resolve.descriptorUtil.*
import org.jetbrains.kotlin.types.KotlinType
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? {
if (descriptor.dispatchReceiverParameter != null) 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
val erasedClass = extensionReceiverType.getErasedTypeClass()
return if (this.isRepresentedAsObjCInterface(erasedClass)) {
return if (!erasedClass.isInterface && !erasedClass.isInlined() && !this.isSpecialMapped(erasedClass)) {
erasedClass
} else {
// 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 Char.boxChar(): Char? = this
fun Char?.isA(): Boolean = (this == 'A')
// Lambdas
val sumLambda = { x: Int, y: Int -> x + y }
@@ -223,4 +226,13 @@ fun box(ic2: IC2): Any = ic2
fun box(ic3: IC3): Any = ic3
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")
}
func testCharExtensions() throws {
try assertTrue(ValuesKt.isA(ValuesKt.boxChar(65)))
try assertFalse(ValuesKt.isA(ValuesKt.boxChar(66)))
}
func testLambda() throws {
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),
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 --------
@@ -431,6 +445,7 @@ class ValuesTests : TestProvider {
TestCase(name: "TestStringExtension", method: withAutorelease(testStrExtFun)),
TestCase(name: "TestAnyToString", method: withAutorelease(testAnyToString)),
TestCase(name: "TestAnyPrint", method: withAutorelease(testAnyPrint)),
TestCase(name: "TestCharExtensions", method: withAutorelease(testCharExtensions)),
TestCase(name: "TestLambda", method: withAutorelease(testLambda)),
TestCase(name: "TestInterfaceExtension", method: withAutorelease(testInterfaceExtension)),
TestCase(name: "TestClassInstances", method: withAutorelease(testClassInstances)),