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:
Florian Kistner
2021-03-03 20:38:57 +01:00
committed by Space
parent 6641b4f029
commit bd614aba0b
17 changed files with 2604 additions and 93 deletions
@@ -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()
@@ -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)
@@ -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<*>>
)
@@ -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 = ">")
}
@@ -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
}
}
@@ -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