Retain typed generics in ObjC export stubs (#4727)
* Add ObjC export test with disabled generics * Retain typed generics in ObjC export stubs * Introduce ObjC variance enum to decouple stubs from Kotlin variance (cherry picked from commit 4d7c78b952a467ca3318c8c49d36b768fdc1ef9c)
This commit is contained in:
+61
-57
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
import org.jetbrains.kotlin.types.typeUtil.isInterface
|
||||
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
|
||||
@@ -79,19 +78,23 @@ internal class ObjCExportTranslatorImpl(
|
||||
|
||||
// TODO: only if appears
|
||||
add {
|
||||
val generics = listOf("ObjectType")
|
||||
objCInterface(
|
||||
namer.mutableSetName,
|
||||
generics = listOf("ObjectType"),
|
||||
superClass = "NSMutableSet<ObjectType>"
|
||||
generics = generics,
|
||||
superClass = "NSMutableSet",
|
||||
superClassGenerics = generics
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: only if appears
|
||||
add {
|
||||
val generics = listOf("KeyType", "ObjectType")
|
||||
objCInterface(
|
||||
namer.mutableMapName,
|
||||
generics = listOf("KeyType", "ObjectType"),
|
||||
superClass = "NSMutableDictionary<KeyType, ObjectType>"
|
||||
generics = generics,
|
||||
superClass = "NSMutableDictionary",
|
||||
superClassGenerics = generics
|
||||
)
|
||||
}
|
||||
|
||||
@@ -192,23 +195,14 @@ internal class ObjCExportTranslatorImpl(
|
||||
}
|
||||
|
||||
private fun referenceClass(descriptor: ClassDescriptor): ObjCExportNamer.ClassOrProtocolName {
|
||||
fun forwardDeclarationObjcClassName(objcGenerics: Boolean, descriptor: ClassDescriptor, namer:ObjCExportNamer): String {
|
||||
val className = translateClassOrInterfaceName(descriptor)
|
||||
val builder = StringBuilder(className.objCName)
|
||||
if (objcGenerics)
|
||||
formatGenerics(builder, descriptor.typeConstructor.parameters.map { typeParameterDescriptor ->
|
||||
"${typeParameterDescriptor.variance.objcDeclaration()}${namer.getTypeParameterName(typeParameterDescriptor)}"
|
||||
})
|
||||
return builder.toString()
|
||||
}
|
||||
|
||||
assert(mapper.shouldBeExposed(descriptor)) { "Shouldn't be exposed: $descriptor" }
|
||||
assert(!descriptor.isInterface)
|
||||
generator?.requireClassOrInterface(descriptor)
|
||||
|
||||
return translateClassOrInterfaceName(descriptor).also {
|
||||
val objcName = forwardDeclarationObjcClassName(objcGenerics, descriptor, namer)
|
||||
generator?.referenceClass(objcName)
|
||||
return translateClassOrInterfaceName(descriptor).also { className ->
|
||||
val generics = mapTypeConstructorParameters(descriptor)
|
||||
val forwardDeclaration = ObjCClassForwardDeclaration(className.objCName, generics)
|
||||
generator?.referenceClass(forwardDeclaration)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,14 +290,14 @@ internal class ObjCExportTranslatorImpl(
|
||||
}
|
||||
|
||||
fun superClassGenerics(genericExportScope: ObjCExportScope): List<ObjCNonNullReferenceType> {
|
||||
val parentType = computeSuperClassType(descriptor)
|
||||
return if(parentType != null) {
|
||||
parentType.arguments.map { typeProjection ->
|
||||
mapReferenceTypeIgnoringNullability(typeProjection.type, genericExportScope)
|
||||
if (objcGenerics) {
|
||||
computeSuperClassType(descriptor)?.let { parentType ->
|
||||
return parentType.arguments.map { typeProjection ->
|
||||
mapReferenceTypeIgnoringNullability(typeProjection.type, genericExportScope)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
val superClass = descriptor.getSuperClassNotAny()
|
||||
@@ -397,20 +391,8 @@ internal class ObjCExportTranslatorImpl(
|
||||
val attributes = if (descriptor.isFinalOrEnum) listOf(OBJC_SUBCLASSING_RESTRICTED) else emptyList()
|
||||
|
||||
val name = translateClassOrInterfaceName(descriptor)
|
||||
|
||||
val generics = if (objcGenerics) {
|
||||
descriptor.typeConstructor.parameters.map {
|
||||
"${it.variance.objcDeclaration()}${namer.getTypeParameterName(it)}"
|
||||
}
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
|
||||
val superClassGenerics = if (objcGenerics) {
|
||||
superClassGenerics(genericExportScope)
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
val generics = mapTypeConstructorParameters(descriptor)
|
||||
val superClassGenerics = superClassGenerics(genericExportScope)
|
||||
|
||||
return objCInterface(
|
||||
name,
|
||||
@@ -424,6 +406,15 @@ internal class ObjCExportTranslatorImpl(
|
||||
)
|
||||
}
|
||||
|
||||
private fun mapTypeConstructorParameters(descriptor: ClassDescriptor): List<ObjCGenericTypeParameterDeclaration> {
|
||||
if (objcGenerics) {
|
||||
return descriptor.typeConstructor.parameters.map {
|
||||
ObjCGenericTypeParameterDeclaration(it, namer)
|
||||
}
|
||||
}
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
private fun buildEnumValuesMethod(
|
||||
enumValues: SimpleFunctionDescriptor,
|
||||
genericExportScope: ObjCExportScope
|
||||
@@ -822,9 +813,9 @@ internal class ObjCExportTranslatorImpl(
|
||||
}
|
||||
|
||||
if(objcGenerics && kotlinType.isTypeParameter()){
|
||||
val genericTypeDeclaration = objCExportScope.getGenericDeclaration(TypeUtils.getTypeParameterDescriptorOrNull(kotlinType))
|
||||
if(genericTypeDeclaration != null)
|
||||
return genericTypeDeclaration
|
||||
val genericTypeUsage = objCExportScope.getGenericTypeUsage(TypeUtils.getTypeParameterDescriptorOrNull(kotlinType))
|
||||
if(genericTypeUsage != null)
|
||||
return genericTypeUsage
|
||||
}
|
||||
|
||||
val classDescriptor = kotlinType.getErasedTypeClass()
|
||||
@@ -892,7 +883,7 @@ internal class ObjCExportTranslatorImpl(
|
||||
}
|
||||
|
||||
private fun foreignClassType(name: String): ObjCClassType {
|
||||
generator?.referenceClass(name)
|
||||
generator?.referenceClass(ObjCClassForwardDeclaration(name))
|
||||
return ObjCClassType(name)
|
||||
}
|
||||
|
||||
@@ -971,7 +962,7 @@ abstract class ObjCExportHeaderGenerator internal constructor(
|
||||
) {
|
||||
private val stubs = mutableListOf<Stub<*>>()
|
||||
|
||||
private val classForwardDeclarations = linkedSetOf<String>()
|
||||
private val classForwardDeclarations = linkedSetOf<ObjCClassForwardDeclaration>()
|
||||
private val protocolForwardDeclarations = linkedSetOf<String>()
|
||||
private val extraClassesToTranslate = mutableSetOf<ClassDescriptor>()
|
||||
|
||||
@@ -989,7 +980,14 @@ abstract class ObjCExportHeaderGenerator internal constructor(
|
||||
add("")
|
||||
|
||||
if (classForwardDeclarations.isNotEmpty()) {
|
||||
add("@class ${classForwardDeclarations.joinToString()};")
|
||||
add("@class ${
|
||||
classForwardDeclarations.joinToString {
|
||||
buildString {
|
||||
append(it.className)
|
||||
formatGenerics(this, it.typeDeclarations)
|
||||
}
|
||||
}
|
||||
};")
|
||||
add("")
|
||||
}
|
||||
|
||||
@@ -1163,8 +1161,8 @@ abstract class ObjCExportHeaderGenerator internal constructor(
|
||||
}
|
||||
}
|
||||
|
||||
internal fun referenceClass(objCName: String) {
|
||||
classForwardDeclarations += objCName
|
||||
internal fun referenceClass(forwardDeclaration: ObjCClassForwardDeclaration) {
|
||||
classForwardDeclarations += forwardDeclaration
|
||||
}
|
||||
|
||||
internal fun referenceProtocol(objCName: String) {
|
||||
@@ -1192,7 +1190,19 @@ abstract class ObjCExportHeaderGenerator internal constructor(
|
||||
|
||||
private fun objCInterface(
|
||||
name: ObjCExportNamer.ClassOrProtocolName,
|
||||
generics: List<String> = emptyList(),
|
||||
generics: List<String>,
|
||||
superClass: String,
|
||||
superClassGenerics: List<String>
|
||||
): ObjCInterface = objCInterface(
|
||||
name,
|
||||
generics = generics.map { ObjCGenericTypeRawDeclaration(it) },
|
||||
superClass = superClass,
|
||||
superClassGenerics = superClassGenerics.map { ObjCGenericTypeRawUsage(it) }
|
||||
)
|
||||
|
||||
private fun objCInterface(
|
||||
name: ObjCExportNamer.ClassOrProtocolName,
|
||||
generics: List<ObjCGenericTypeDeclaration> = emptyList(),
|
||||
descriptor: ClassDescriptor? = null,
|
||||
superClass: String? = null,
|
||||
superClassGenerics: List<ObjCNonNullReferenceType> = emptyList(),
|
||||
@@ -1234,7 +1244,7 @@ private fun swiftNameAttribute(swiftName: String) = "swift_name(\"$swiftName\")"
|
||||
private fun objcRuntimeNameAttribute(name: String) = "objc_runtime_name(\"$name\")"
|
||||
|
||||
interface ObjCExportScope{
|
||||
fun getGenericDeclaration(typeParameterDescriptor: TypeParameterDescriptor?): ObjCGenericTypeDeclaration?
|
||||
fun getGenericTypeUsage(typeParameterDescriptor: TypeParameterDescriptor?): ObjCGenericTypeUsage?
|
||||
}
|
||||
|
||||
internal class ObjCClassExportScope constructor(container:DeclarationDescriptor, val namer: ObjCExportNamer): ObjCExportScope {
|
||||
@@ -1244,7 +1254,7 @@ internal class ObjCClassExportScope constructor(container:DeclarationDescriptor,
|
||||
emptyList<TypeParameterDescriptor>()
|
||||
}
|
||||
|
||||
override fun getGenericDeclaration(typeParameterDescriptor: TypeParameterDescriptor?): ObjCGenericTypeDeclaration? {
|
||||
override fun getGenericTypeUsage(typeParameterDescriptor: TypeParameterDescriptor?): ObjCGenericTypeUsage? {
|
||||
val localTypeParam = typeNames.firstOrNull {
|
||||
typeParameterDescriptor != null &&
|
||||
(it == typeParameterDescriptor || (it.isCapturedFromOuterDeclaration && it.original == typeParameterDescriptor))
|
||||
@@ -1253,19 +1263,13 @@ internal class ObjCClassExportScope constructor(container:DeclarationDescriptor,
|
||||
return if(localTypeParam == null) {
|
||||
null
|
||||
} else {
|
||||
ObjCGenericTypeDeclaration(localTypeParam, namer)
|
||||
ObjCGenericTypeParameterUsage(localTypeParam, namer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal object ObjCNoneExportScope: ObjCExportScope{
|
||||
override fun getGenericDeclaration(typeParameterDescriptor: TypeParameterDescriptor?): ObjCGenericTypeDeclaration? = null
|
||||
}
|
||||
|
||||
internal fun Variance.objcDeclaration():String = when(this){
|
||||
Variance.OUT_VARIANCE -> "__covariant "
|
||||
Variance.IN_VARIANCE -> "__contravariant "
|
||||
else -> ""
|
||||
override fun getGenericTypeUsage(typeParameterDescriptor: TypeParameterDescriptor?): ObjCGenericTypeUsage? = null
|
||||
}
|
||||
|
||||
private fun computeSuperClassType(descriptor: ClassDescriptor): KotlinType? = descriptor.typeConstructor.supertypes.filter { !it.isInterface() }.firstOrNull()
|
||||
|
||||
+10
-5
@@ -150,9 +150,14 @@ internal class ObjCExportLazyImpl(
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateGenerics(ktClassOrObject: KtClassOrObject): List<String> = if (configuration.objcGenerics) {
|
||||
private fun translateGenerics(ktClassOrObject: KtClassOrObject): List<ObjCGenericTypeDeclaration> = if (configuration.objcGenerics) {
|
||||
ktClassOrObject.typeParametersWithOuter
|
||||
.map { nameTranslator.getTypeParameterName(it) }
|
||||
.map {
|
||||
ObjCGenericTypeRawDeclaration(
|
||||
nameTranslator.getTypeParameterName(it),
|
||||
ObjCVariance.fromKotlinVariance(it.variance)
|
||||
)
|
||||
}
|
||||
.toList()
|
||||
} else {
|
||||
emptyList()
|
||||
@@ -316,7 +321,7 @@ internal class ObjCExportLazyImpl(
|
||||
private class LazyObjCInterfaceImpl(
|
||||
name: ObjCExportNamer.ClassOrProtocolName,
|
||||
attributes: List<String>,
|
||||
generics: List<String>,
|
||||
generics: List<ObjCGenericTypeDeclaration>,
|
||||
override val psi: KtClassOrObject,
|
||||
private val lazy: ObjCExportLazyImpl
|
||||
) : LazyObjCInterface(name = name, generics = generics, categoryName = null, attributes = attributes) {
|
||||
@@ -382,14 +387,14 @@ private abstract class LazyObjCInterface : ObjCInterface {
|
||||
|
||||
constructor(
|
||||
name: ObjCExportNamer.ClassOrProtocolName,
|
||||
generics: List<String>,
|
||||
generics: List<ObjCGenericTypeDeclaration>,
|
||||
categoryName: String?,
|
||||
attributes: List<String>
|
||||
) : super(name.objCName, generics, categoryName, attributes + name.toNameAttributes())
|
||||
|
||||
constructor(
|
||||
name: String,
|
||||
generics: List<String>,
|
||||
generics: List<ObjCGenericTypeDeclaration>,
|
||||
categoryName: String,
|
||||
attributes: List<String>
|
||||
) : super(name, generics, categoryName, attributes)
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
package org.jetbrains.kotlin.backend.konan.objcexport
|
||||
|
||||
data class ObjCExportedStubs(
|
||||
val classForwardDeclarations: Set<String>,
|
||||
val classForwardDeclarations: Set<ObjCClassForwardDeclaration>,
|
||||
val protocolForwardDeclarations: Set<String>,
|
||||
val stubs: List<Stub<*>>
|
||||
)
|
||||
+2
-2
@@ -159,7 +159,7 @@ object StubRenderer {
|
||||
private fun ObjCInterface.renderInterfaceHeader() = buildString {
|
||||
fun appendSuperClass() {
|
||||
if (superClass != null) append(" : $superClass")
|
||||
formatGenerics(this, superClassGenerics.map { it.render() })
|
||||
formatGenerics(this, superClassGenerics)
|
||||
}
|
||||
|
||||
fun appendGenerics() {
|
||||
@@ -210,7 +210,7 @@ object StubRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun formatGenerics(buffer: Appendable, generics:List<String>) {
|
||||
fun formatGenerics(buffer: Appendable, generics: List<Any>) {
|
||||
if (generics.isNotEmpty()) {
|
||||
generics.joinTo(buffer, separator = ", ", prefix = "<", postfix = ">")
|
||||
}
|
||||
|
||||
+56
-12
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.backend.konan.objcexport
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
sealed class ObjCType {
|
||||
final override fun toString(): String = this.render()
|
||||
@@ -18,7 +19,7 @@ sealed class ObjCType {
|
||||
if (attrsAndName.isEmpty()) this else "$this ${attrsAndName.trimStart()}"
|
||||
}
|
||||
|
||||
class ObjCRawType(
|
||||
data class ObjCRawType(
|
||||
val rawText: String
|
||||
) : ObjCType() {
|
||||
override fun render(attrsAndName: String): String = rawText.withAttrsAndName(attrsAndName)
|
||||
@@ -34,7 +35,7 @@ data class ObjCNullableReferenceType(
|
||||
override fun render(attrsAndName: String) = nonNullType.render(" _Nullable".withAttrsAndName(attrsAndName))
|
||||
}
|
||||
|
||||
class ObjCClassType(
|
||||
data class ObjCClassType(
|
||||
val className: String,
|
||||
val typeArguments: List<ObjCNonNullReferenceType> = emptyList()
|
||||
) : ObjCNonNullReferenceType() {
|
||||
@@ -51,16 +52,24 @@ class ObjCClassType(
|
||||
}
|
||||
}
|
||||
|
||||
class ObjCGenericTypeDeclaration(
|
||||
val typeParameterDescriptor: TypeParameterDescriptor,
|
||||
val namer: ObjCExportNamer
|
||||
) : ObjCNonNullReferenceType() {
|
||||
override fun render(attrsAndName: String): String {
|
||||
return namer.getTypeParameterName(typeParameterDescriptor).withAttrsAndName(attrsAndName)
|
||||
sealed class ObjCGenericTypeUsage: ObjCNonNullReferenceType() {
|
||||
abstract val typeName: String
|
||||
final override fun render(attrsAndName: String): String {
|
||||
return typeName.withAttrsAndName(attrsAndName)
|
||||
}
|
||||
}
|
||||
|
||||
class ObjCProtocolType(
|
||||
data class ObjCGenericTypeRawUsage(override val typeName: String) : ObjCGenericTypeUsage()
|
||||
|
||||
data class ObjCGenericTypeParameterUsage(
|
||||
val typeParameterDescriptor: TypeParameterDescriptor,
|
||||
val namer: ObjCExportNamer
|
||||
) : ObjCGenericTypeUsage() {
|
||||
override val typeName: String
|
||||
get() = namer.getTypeParameterName(typeParameterDescriptor)
|
||||
}
|
||||
|
||||
data class ObjCProtocolType(
|
||||
val protocolName: String
|
||||
) : ObjCNonNullReferenceType() {
|
||||
override fun render(attrsAndName: String) = "id<$protocolName>".withAttrsAndName(attrsAndName)
|
||||
@@ -74,7 +83,7 @@ object ObjCInstanceType : ObjCNonNullReferenceType() {
|
||||
override fun render(attrsAndName: String): String = "instancetype".withAttrsAndName(attrsAndName)
|
||||
}
|
||||
|
||||
class ObjCBlockPointerType(
|
||||
data class ObjCBlockPointerType(
|
||||
val returnType: ObjCType,
|
||||
val parameterTypes: List<ObjCReferenceType>
|
||||
) : ObjCNonNullReferenceType() {
|
||||
@@ -124,7 +133,7 @@ sealed class ObjCPrimitiveType(
|
||||
override fun render(attrsAndName: String) = cName.withAttrsAndName(attrsAndName)
|
||||
}
|
||||
|
||||
class ObjCPointerType(
|
||||
data class ObjCPointerType(
|
||||
val pointee: ObjCType,
|
||||
val nullable: Boolean = false
|
||||
) : ObjCType() {
|
||||
@@ -156,6 +165,41 @@ internal enum class ObjCValueType(val encoding: String) {
|
||||
POINTER("^v")
|
||||
}
|
||||
|
||||
enum class ObjCVariance(internal val declaration: String) {
|
||||
INVARIANT(""),
|
||||
COVARIANT("__covariant "),
|
||||
CONTRAVARIANT("__contravariant ");
|
||||
|
||||
companion object {
|
||||
fun fromKotlinVariance(variance: Variance): ObjCVariance = when (variance) {
|
||||
Variance.OUT_VARIANCE -> COVARIANT
|
||||
Variance.IN_VARIANCE -> CONTRAVARIANT
|
||||
else -> INVARIANT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class ObjCGenericTypeDeclaration {
|
||||
abstract val typeName: String
|
||||
abstract val variance: ObjCVariance
|
||||
final override fun toString(): String = variance.declaration + typeName
|
||||
}
|
||||
|
||||
data class ObjCGenericTypeRawDeclaration(
|
||||
override val typeName: String,
|
||||
override val variance: ObjCVariance = ObjCVariance.INVARIANT
|
||||
) : ObjCGenericTypeDeclaration()
|
||||
|
||||
data class ObjCGenericTypeParameterDeclaration(
|
||||
val typeParameterDescriptor: TypeParameterDescriptor,
|
||||
val namer: ObjCExportNamer
|
||||
) : ObjCGenericTypeDeclaration() {
|
||||
override val typeName: String
|
||||
get() = namer.getTypeParameterName(typeParameterDescriptor)
|
||||
override val variance: ObjCVariance
|
||||
get() = ObjCVariance.fromKotlinVariance(typeParameterDescriptor.variance)
|
||||
}
|
||||
|
||||
internal fun ObjCType.makeNullableIfReferenceOrPointer(): ObjCType = when (this) {
|
||||
is ObjCPointerType -> ObjCPointerType(this.pointee, nullable = true)
|
||||
|
||||
@@ -167,4 +211,4 @@ internal fun ObjCType.makeNullableIfReferenceOrPointer(): ObjCType = when (this)
|
||||
internal fun ObjCReferenceType.makeNullable(): ObjCNullableReferenceType = when (this) {
|
||||
is ObjCNonNullReferenceType -> ObjCNullableReferenceType(this)
|
||||
is ObjCNullableReferenceType -> this
|
||||
}
|
||||
}
|
||||
+7
-2
@@ -14,6 +14,11 @@ class ObjCComment(val contentLines: List<String>) {
|
||||
constructor(vararg contentLines: String) : this(contentLines.toList())
|
||||
}
|
||||
|
||||
data class ObjCClassForwardDeclaration(
|
||||
val className: String,
|
||||
val typeDeclarations: List<ObjCGenericTypeDeclaration> = emptyList()
|
||||
)
|
||||
|
||||
abstract class Stub<out D : DeclarationDescriptor>(val name: String, val comment: ObjCComment? = null) {
|
||||
abstract val descriptor: D?
|
||||
open val psi: PsiElement?
|
||||
@@ -41,7 +46,7 @@ class ObjCProtocolImpl(
|
||||
attributes: List<String> = emptyList()) : ObjCProtocol(name, attributes)
|
||||
|
||||
abstract class ObjCInterface(name: String,
|
||||
val generics: List<String>,
|
||||
val generics: List<ObjCGenericTypeDeclaration>,
|
||||
val categoryName: String?,
|
||||
attributes: List<String>) : ObjCClass<ClassDescriptor>(name, attributes) {
|
||||
abstract val superClass: String?
|
||||
@@ -50,7 +55,7 @@ abstract class ObjCInterface(name: String,
|
||||
|
||||
class ObjCInterfaceImpl(
|
||||
name: String,
|
||||
generics: List<String> = emptyList(),
|
||||
generics: List<ObjCGenericTypeDeclaration> = emptyList(),
|
||||
override val descriptor: ClassDescriptor? = null,
|
||||
override val superClass: String? = null,
|
||||
override val superClassGenerics: List<ObjCNonNullReferenceType> = emptyList(),
|
||||
|
||||
@@ -4730,6 +4730,59 @@ if (isAppleTarget(project)) {
|
||||
swiftSources = ['objcexport']
|
||||
}
|
||||
|
||||
frameworkTest('testObjCExportNoGenerics') {
|
||||
enabled = !isExperimentalMM // Experimental MM doesn't support ObjC blocks yet.
|
||||
final String frameworkName = 'KtNoGenerics'
|
||||
final String frameworkArtifactName = 'Kt'
|
||||
final String dir = "$testOutputFramework/testObjCExportNoGenerics"
|
||||
final File lazyHeader = file("$dir/$target-lazy.h")
|
||||
|
||||
doLast {
|
||||
final String expectedLazyHeaderName = "expectedLazyNoGenerics.h"
|
||||
final String expectedLazyHeaderDir = file("objcexport/")
|
||||
final File expectedLazyHeader = new File(expectedLazyHeaderDir, expectedLazyHeaderName)
|
||||
|
||||
if (expectedLazyHeader.readLines() != lazyHeader.readLines()) {
|
||||
exec {
|
||||
commandLine 'diff', '-u', expectedLazyHeader, lazyHeader
|
||||
ignoreExitValue = true
|
||||
}
|
||||
|
||||
copy {
|
||||
from(lazyHeader)
|
||||
into(expectedLazyHeaderDir)
|
||||
rename { expectedLazyHeaderName }
|
||||
}
|
||||
|
||||
throw new Error("$expectedLazyHeader file patched;\nre-run the test and don't forget to commit the patch")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def libraryName = frameworkName + "Library"
|
||||
konanArtifacts {
|
||||
library(libraryName, targets: [target.name]) {
|
||||
srcDir "objcexport/library"
|
||||
artifactName "test-library"
|
||||
|
||||
if (!useCustomDist) {
|
||||
dependsOn ":${target.name}CrossDistRuntime", ':distCompiler'
|
||||
}
|
||||
|
||||
extraOpts "-Xshort-module-name=MyLibrary"
|
||||
extraOpts "-module-name", "org.jetbrains.kotlin.native.test-library"
|
||||
}
|
||||
}
|
||||
framework(frameworkName) {
|
||||
sources = ['objcexport']
|
||||
artifact = frameworkArtifactName
|
||||
library = libraryName
|
||||
opts = ["-Xemit-lazy-objc-header=$lazyHeader", "-Xno-objc-generics"]
|
||||
}
|
||||
swiftSources = ['objcexport']
|
||||
swiftExtraOpts = [ '-D', 'NO_GENERICS' ]
|
||||
}
|
||||
|
||||
frameworkTest('testObjCExportStatic') {
|
||||
enabled = !isExperimentalMM // Experimental MM doesn't support ObjC blocks yet.
|
||||
final String frameworkName = 'KtStatic'
|
||||
|
||||
@@ -51,7 +51,11 @@ private func testSuspendFuncAsync(doThrow: Bool) throws {
|
||||
var result: AnyObject? = nil
|
||||
var error: Error? = nil
|
||||
|
||||
#if NO_GENERICS
|
||||
let continuationHolder = ContinuationHolder()
|
||||
#else
|
||||
let continuationHolder = ContinuationHolder<AnyObject>()
|
||||
#endif
|
||||
|
||||
CoroutinesKt.suspendFunAsync(result: nil, continuationHolder: continuationHolder) { _result, _error in
|
||||
completionCalled += 1
|
||||
@@ -114,7 +118,11 @@ private class SuspendFunImpl : SuspendFun {
|
||||
}
|
||||
|
||||
private func testSuspendFunImpl(doYield: Bool, doThrow: Bool) throws {
|
||||
#if NO_GENERICS
|
||||
let resultHolder = ResultHolder()
|
||||
#else
|
||||
let resultHolder = ResultHolder<KotlinInt>()
|
||||
#endif
|
||||
|
||||
let impl = SuspendFunImpl()
|
||||
|
||||
@@ -141,7 +149,7 @@ private func testSuspendFunImpl(doYield: Bool, doThrow: Bool) throws {
|
||||
try fail()
|
||||
}
|
||||
} else {
|
||||
try assertEquals(actual: resultHolder.result, expected: 17)
|
||||
try assertEquals(actual: resultHolder.result as! Int, expected: 17)
|
||||
try assertNil(resultHolder.exception)
|
||||
}
|
||||
}
|
||||
@@ -213,12 +221,16 @@ private class SwiftSuspendBridge : AbstractSuspendBridge {
|
||||
}
|
||||
|
||||
private func testBridges() throws {
|
||||
#if NO_GENERICS
|
||||
let resultHolder = ResultHolder()
|
||||
#else
|
||||
let resultHolder = ResultHolder<KotlinUnit>()
|
||||
#endif
|
||||
try CoroutinesKt.callSuspendBridge(bridge: SwiftSuspendBridge(), resultHolder: resultHolder)
|
||||
|
||||
try assertEquals(actual: resultHolder.completed, expected: 1)
|
||||
try assertNil(resultHolder.exception)
|
||||
try assertSame(actual: resultHolder.result, expected: KotlinUnit())
|
||||
try assertSame(actual: resultHolder.result as AnyObject, expected: KotlinUnit())
|
||||
}
|
||||
|
||||
private func testImplicitThrows1() throws {
|
||||
|
||||
@@ -33,7 +33,11 @@ private class DeallocRetain : DeallocRetainBase {
|
||||
static var deallocated = false
|
||||
static var retainObject: DeallocRetain? = nil
|
||||
static weak var weakObject: DeallocRetain? = nil
|
||||
#if NO_GENERICS
|
||||
static var kotlinWeakRef: KotlinWeakReference? = nil
|
||||
#else
|
||||
static var kotlinWeakRef: KotlinWeakReference<AnyObject>? = nil
|
||||
#endif
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
@@ -43,7 +47,7 @@ private class DeallocRetain : DeallocRetainBase {
|
||||
|
||||
func checkWeak() throws {
|
||||
try assertSame(actual: DeallocRetain.weakObject, expected: self)
|
||||
try assertSame(actual: DeallocRetain.kotlinWeakRef!.value, expected: self)
|
||||
try assertSame(actual: DeallocRetain.kotlinWeakRef!.value as AnyObject, expected: self)
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
||||
@@ -5,10 +5,10 @@ private func testEnumValues() throws {
|
||||
|
||||
try assertEquals(actual: values.size, expected: 4)
|
||||
|
||||
try assertSame(actual: values.get(index: 0), expected: EnumLeftRightUpDown.left)
|
||||
try assertSame(actual: values.get(index: 1), expected: EnumLeftRightUpDown.right)
|
||||
try assertSame(actual: values.get(index: 2), expected: EnumLeftRightUpDown.up)
|
||||
try assertSame(actual: values.get(index: 3), expected: EnumLeftRightUpDown.down)
|
||||
try assertSame(actual: values.get(index: 0) as AnyObject, expected: EnumLeftRightUpDown.left)
|
||||
try assertSame(actual: values.get(index: 1) as AnyObject, expected: EnumLeftRightUpDown.right)
|
||||
try assertSame(actual: values.get(index: 2) as AnyObject, expected: EnumLeftRightUpDown.up)
|
||||
try assertSame(actual: values.get(index: 3) as AnyObject, expected: EnumLeftRightUpDown.down)
|
||||
}
|
||||
|
||||
private func testEnumValuesMangled() throws {
|
||||
@@ -16,10 +16,10 @@ private func testEnumValuesMangled() throws {
|
||||
|
||||
try assertEquals(actual: values.size, expected: 4)
|
||||
|
||||
try assertSame(actual: values.get(index: 0), expected: EnumOneTwoThreeValues.one)
|
||||
try assertSame(actual: values.get(index: 1), expected: EnumOneTwoThreeValues.two)
|
||||
try assertSame(actual: values.get(index: 2), expected: EnumOneTwoThreeValues.three)
|
||||
try assertSame(actual: values.get(index: 3), expected: EnumOneTwoThreeValues.values)
|
||||
try assertSame(actual: values.get(index: 0) as AnyObject, expected: EnumOneTwoThreeValues.one)
|
||||
try assertSame(actual: values.get(index: 1) as AnyObject, expected: EnumOneTwoThreeValues.two)
|
||||
try assertSame(actual: values.get(index: 2) as AnyObject, expected: EnumOneTwoThreeValues.three)
|
||||
try assertSame(actual: values.get(index: 3) as AnyObject, expected: EnumOneTwoThreeValues.values)
|
||||
}
|
||||
|
||||
private func testEnumValuesMangledTwice() throws {
|
||||
@@ -27,8 +27,8 @@ private func testEnumValuesMangledTwice() throws {
|
||||
|
||||
try assertEquals(actual: values.size, expected: 2)
|
||||
|
||||
try assertSame(actual: values.get(index: 0), expected: EnumValuesValues_.values)
|
||||
try assertSame(actual: values.get(index: 1), expected: EnumValuesValues_.values_)
|
||||
try assertSame(actual: values.get(index: 0) as AnyObject, expected: EnumValuesValues_.values)
|
||||
try assertSame(actual: values.get(index: 1) as AnyObject, expected: EnumValuesValues_.values_)
|
||||
}
|
||||
|
||||
private func testEnumValuesEmpty() throws {
|
||||
|
||||
@@ -2227,3 +2227,42 @@ __attribute__((swift_name("ValuesKt")))
|
||||
@property (class) int32_t gh3525InitCount __attribute__((swift_name("gh3525InitCount")));
|
||||
@end;
|
||||
|
||||
__attribute__((swift_name("InvariantSuper")))
|
||||
@interface KtInvariantSuper<T> : KtBase
|
||||
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
|
||||
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
|
||||
@end;
|
||||
|
||||
__attribute__((objc_subclassing_restricted))
|
||||
__attribute__((swift_name("Invariant")))
|
||||
@interface KtInvariant<T> : KtInvariantSuper<T>
|
||||
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
|
||||
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
|
||||
@end;
|
||||
|
||||
__attribute__((swift_name("OutVariantSuper")))
|
||||
@interface KtOutVariantSuper<__covariant T> : KtBase
|
||||
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
|
||||
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
|
||||
@end;
|
||||
|
||||
__attribute__((objc_subclassing_restricted))
|
||||
__attribute__((swift_name("OutVariant")))
|
||||
@interface KtOutVariant<__covariant T> : KtOutVariantSuper<T>
|
||||
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
|
||||
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
|
||||
@end;
|
||||
|
||||
__attribute__((swift_name("InVariantSuper")))
|
||||
@interface KtInVariantSuper<__contravariant T> : KtBase
|
||||
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
|
||||
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
|
||||
@end;
|
||||
|
||||
__attribute__((objc_subclassing_restricted))
|
||||
__attribute__((swift_name("InVariant")))
|
||||
@interface KtInVariant<__contravariant T> : KtInVariantSuper<T>
|
||||
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
|
||||
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
|
||||
@end;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,7 @@ import Kt
|
||||
// It is enough to have just Kotlin declarations at the moment.
|
||||
// Adding usages for all declarations to avoid any kind of DCE that may appear later.
|
||||
|
||||
#if !NO_GENERICS
|
||||
private func testIncompatiblePropertyType() throws {
|
||||
let c = TestIncompatiblePropertyTypeWarning.ClassOverridingInterfaceWithGenericProperty(
|
||||
p: TestIncompatiblePropertyTypeWarningGeneric<NSString>(value: "cba")
|
||||
@@ -21,6 +22,7 @@ private func testIncompatiblePropertyType() throws {
|
||||
let pi: TestIncompatiblePropertyTypeWarningGeneric<AnyObject> = i.p
|
||||
try assertEquals(actual: pi.value as! String, expected: "cba")
|
||||
}
|
||||
#endif
|
||||
|
||||
private func testGH3992() throws {
|
||||
let d = TestGH3992.D(a: TestGH3992.B())
|
||||
@@ -36,7 +38,9 @@ class HeaderWarningsTests : SimpleTestProvider {
|
||||
override init() {
|
||||
super.init()
|
||||
|
||||
#if !NO_GENERICS
|
||||
test("TestIncompatiblePropertyType", testIncompatiblePropertyType)
|
||||
#endif
|
||||
test("TestGH3992", testGH3992)
|
||||
}
|
||||
}
|
||||
@@ -384,7 +384,11 @@ func testGenericsFoo() throws {
|
||||
}
|
||||
|
||||
func testVararg() throws {
|
||||
#if NO_GENERICS
|
||||
let ktArray = KotlinArray(size: 3, init: { (_) -> NSNumber in return 42 })
|
||||
#else
|
||||
let ktArray = KotlinArray<AnyObject>(size: 3, init: { (_) -> NSNumber in return 42 })
|
||||
#endif
|
||||
let arr: [Int] = ValuesKt.varargToList(args: ktArray) as! [Int]
|
||||
try assertEquals(actual: arr, expected: [42, 42, 42])
|
||||
}
|
||||
@@ -507,13 +511,21 @@ func testDataClass() throws {
|
||||
let s = "2"
|
||||
let t = "3"
|
||||
|
||||
#if NO_GENERICS
|
||||
let tripleVal = TripleVals(first: f as NSString, second: s as NSString, third: t as NSString)
|
||||
#else
|
||||
let tripleVal = TripleVals<NSString>(first: f as NSString, second: s as NSString, third: t as NSString)
|
||||
#endif
|
||||
try assertEquals(actual: tripleVal.first as! String, expected: f, "Data class' value")
|
||||
try assertEquals(actual: tripleVal.component2() as! String, expected: s, "Data class' component")
|
||||
print(tripleVal)
|
||||
try assertEquals(actual: String(describing: tripleVal), expected: "TripleVals(first=\(f), second=\(s), third=\(t))")
|
||||
|
||||
#if NO_GENERICS
|
||||
let tripleVar = TripleVars(first: f as NSString, second: s as NSString, third: t as NSString)
|
||||
#else
|
||||
let tripleVar = TripleVars<NSString>(first: f as NSString, second: s as NSString, third: t as NSString)
|
||||
#endif
|
||||
try assertEquals(actual: tripleVar.first as! String, expected: f, "Data class' value")
|
||||
try assertEquals(actual: tripleVar.component2() as! String, expected: s, "Data class' component")
|
||||
print(tripleVar)
|
||||
@@ -542,7 +554,11 @@ func testInlineClasses() throws {
|
||||
let ic1N = ValuesKt.box(ic1: 17)
|
||||
let ic2 = "foo"
|
||||
let ic2N = "bar"
|
||||
#if NO_GENERICS
|
||||
let ic3 = TripleVals(first: 1, second: 2, third: 3)
|
||||
#else
|
||||
let ic3 = TripleVals<NSNumber>(first: 1, second: 2, third: 3)
|
||||
#endif
|
||||
let ic3N = ValuesKt.box(ic3: nil)
|
||||
|
||||
try assertEquals(
|
||||
@@ -609,7 +625,11 @@ func testPureSwiftClasses() throws {
|
||||
func testNames() throws {
|
||||
try assertEquals(actual: ValuesKt.PROPERTY_NAME_MUST_NOT_BE_ALTERED_BY_SWIFT, expected: 111)
|
||||
try assertEquals(actual: Deeply.NestedType().thirtyTwo, expected: 32)
|
||||
#if NO_GENERICS
|
||||
try assertEquals(actual: WithGenericDeeply.NestedType().thirtyThree, expected: 33)
|
||||
#else
|
||||
try assertEquals(actual: WithGenericDeeplyNestedType<AnyObject>().thirtyThree, expected: 33)
|
||||
#endif
|
||||
try assertEquals(actual: CKeywords(float: 1.0, enum : 42, goto: true).goto_, expected: true)
|
||||
try assertEquals(actual: TypeOuter.Type_().thirtyFour, expected: 34)
|
||||
try assertTrue(String(describing: DeeplyNestedIType.self).hasSuffix("DeeplyNestedIType"))
|
||||
@@ -637,7 +657,11 @@ class TransformIntToLongCallingSuper : TransformIntToLong {
|
||||
}
|
||||
|
||||
func testKotlinOverride() throws {
|
||||
#if NO_GENERICS
|
||||
try assertEquals(actual: TransformInheritingDefault().map(value: 1) as! Int32, expected: 1)
|
||||
#else
|
||||
try assertEquals(actual: TransformInheritingDefault<NSNumber>().map(value: 1) as! Int32, expected: 1)
|
||||
#endif
|
||||
try assertEquals(actual: TransformIntToDecimalString().map(value: 2), expected: "2")
|
||||
try assertEquals(actual: TransformIntToDecimalString().map(intValue: 3), expected: "3")
|
||||
try assertEquals(actual: ValuesKt.createTransformDecimalStringToInt().map(value: "4") as! Int32, expected: 4)
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package variance
|
||||
|
||||
sealed class InvariantSuper<T>
|
||||
class Invariant<T> : InvariantSuper<T>()
|
||||
|
||||
sealed class OutVariantSuper<out T>
|
||||
class OutVariant<out T> : OutVariantSuper<T>()
|
||||
|
||||
sealed class InVariantSuper<in T>
|
||||
class InVariant<in T> : InVariantSuper<T>()
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
import Kt
|
||||
|
||||
// -------- Tests --------
|
||||
|
||||
func testInstantiation() {
|
||||
#if NO_GENERICS
|
||||
Invariant()
|
||||
OutVariant()
|
||||
InVariant()
|
||||
#else
|
||||
Invariant<VarianceTests>()
|
||||
OutVariant<VarianceTests>()
|
||||
InVariant<VarianceTests>()
|
||||
#endif
|
||||
}
|
||||
|
||||
// -------- Execution of the test --------
|
||||
|
||||
class VarianceTests : SimpleTestProvider {
|
||||
override init() {
|
||||
super.init()
|
||||
|
||||
test("TestInstantiation", testInstantiation)
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,9 @@ open class FrameworkTest : DefaultTask(), KonanTestExecutable {
|
||||
@Input
|
||||
lateinit var swiftSources: List<String>
|
||||
|
||||
@Input
|
||||
var swiftExtraOpts: List<String> = emptyList()
|
||||
|
||||
@Input
|
||||
lateinit var frameworks: MutableList<Framework>
|
||||
|
||||
@@ -159,7 +162,7 @@ open class FrameworkTest : DefaultTask(), KonanTestExecutable {
|
||||
"-F", frameworkParentDirPath,
|
||||
"-Xcc", "-Werror" // To fail compilation on warnings in framework header.
|
||||
)
|
||||
compileSwift(project, project.testTarget, sources, options, Paths.get(executable), fullBitcode)
|
||||
compileSwift(project, project.testTarget, sources, options + swiftExtraOpts, Paths.get(executable), fullBitcode)
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
|
||||
Reference in New Issue
Block a user