Expose big arity functional types as FunctionN interface [KT-37166] (#4267)
This commit is contained in:
+8
-5
@@ -108,10 +108,13 @@ internal class BuiltInFictitiousFunctionIrClassFactory(
|
|||||||
|
|
||||||
val builtClasses get() = builtClassesMap.values
|
val builtClasses get() = builtClassesMap.values
|
||||||
|
|
||||||
val builtFunctionNClasses get() =
|
val builtFunctionNClasses get() = builtClassesMap.values.mapNotNull {
|
||||||
builtClassesMap.values
|
with(it.descriptor as FunctionClassDescriptor) {
|
||||||
.filter { it -> (it.descriptor as FunctionClassDescriptor).functionKind == FunctionClassDescriptor.Kind.Function }
|
if (functionKind == FunctionClassDescriptor.Kind.Function)
|
||||||
.map { FunctionalInterface(it, (it.descriptor as FunctionClassDescriptor).arity) }
|
FunctionalInterface(it, arity)
|
||||||
|
else null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun createTypeParameter(descriptor: TypeParameterDescriptor) =
|
private fun createTypeParameter(descriptor: TypeParameterDescriptor) =
|
||||||
symbolTable?.declareGlobalTypeParameter(
|
symbolTable?.declareGlobalTypeParameter(
|
||||||
@@ -343,4 +346,4 @@ internal class BuiltInFictitiousFunctionIrClassFactory(
|
|||||||
|
|
||||||
declarations += fakeOverrideDescriptors.map { createFakeOverride(it) }
|
declarations += fakeOverrideDescriptors.map { createFakeOverride(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-22
@@ -600,16 +600,13 @@ private fun ObjCExportCodeGenerator.generateContinuationToCompletionConverter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val maxConvertorsInCache = 33
|
private val ObjCExportBlockCodeGenerator.mappedFunctionNClasses get() =
|
||||||
|
context.ir.symbols.functionIrClassFactory.builtFunctionNClasses
|
||||||
|
.filter { it.irClass.descriptor.isMappedFunctionClass() }
|
||||||
|
|
||||||
private fun ObjCExportBlockCodeGenerator.emitFunctionConverters() {
|
private fun ObjCExportBlockCodeGenerator.emitFunctionConverters() {
|
||||||
require(context.producedLlvmModuleContainsStdlib)
|
require(context.producedLlvmModuleContainsStdlib)
|
||||||
var count = context.ir.symbols.functionIrClassFactory.builtFunctionNClasses.size
|
mappedFunctionNClasses.forEach { functionClass ->
|
||||||
// TODO: ugly hack to avoid huge unneeded adaptors linked into every binary, needs rework.
|
|
||||||
if (context.config.produce.isCache) {
|
|
||||||
count = count.coerceAtMost(maxConvertorsInCache)
|
|
||||||
}
|
|
||||||
context.ir.symbols.functionIrClassFactory.builtFunctionNClasses.take(count).forEach { functionClass ->
|
|
||||||
val converter = kotlinFunctionToBlockConverter(BlockPointerBridge(functionClass.arity, returnsVoid = false))
|
val converter = kotlinFunctionToBlockConverter(BlockPointerBridge(functionClass.arity, returnsVoid = false))
|
||||||
|
|
||||||
val writableTypeInfoValue = buildWritableTypeInfoValue(converter = constPointer(converter))
|
val writableTypeInfoValue = buildWritableTypeInfoValue(converter = constPointer(converter))
|
||||||
@@ -619,22 +616,15 @@ private fun ObjCExportBlockCodeGenerator.emitFunctionConverters() {
|
|||||||
|
|
||||||
private fun ObjCExportBlockCodeGenerator.emitBlockToKotlinFunctionConverters() {
|
private fun ObjCExportBlockCodeGenerator.emitBlockToKotlinFunctionConverters() {
|
||||||
require(context.producedLlvmModuleContainsStdlib)
|
require(context.producedLlvmModuleContainsStdlib)
|
||||||
val functionClassesByArity =
|
val functionClassesByArity = mappedFunctionNClasses.associateBy { it.arity }
|
||||||
context.ir.symbols.functionIrClassFactory.builtFunctionNClasses.associateBy { it.arity }
|
|
||||||
|
|
||||||
var count = ((functionClassesByArity.keys.maxOrNull() ?: -1) + 1)
|
val arityLimit = (functionClassesByArity.keys.maxOrNull() ?: -1) + 1
|
||||||
// TODO: ugly hack to avoid huge unneeded adaptors linked into every binary, needs rework.
|
|
||||||
if (context.config.produce.isCache) {
|
val converters = (0 until arityLimit).map { arity ->
|
||||||
count = count.coerceAtMost(maxConvertorsInCache)
|
functionClassesByArity[arity]?.let {
|
||||||
}
|
val bridge = BlockPointerBridge(numberOfParameters = arity, returnsVoid = false)
|
||||||
val converters = (0 until count).map { arity ->
|
|
||||||
val functionClass = functionClassesByArity[arity]
|
|
||||||
if (functionClass != null) {
|
|
||||||
val bridge = BlockPointerBridge(numberOfParameters = functionClass.arity, returnsVoid = false)
|
|
||||||
constPointer(blockToKotlinFunctionConverter(bridge))
|
constPointer(blockToKotlinFunctionConverter(bridge))
|
||||||
} else {
|
} ?: NullPointer(objCToKotlinFunctionType)
|
||||||
NullPointer(objCToKotlinFunctionType)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val ptr = staticData.placeGlobalArray(
|
val ptr = staticData.placeGlobalArray(
|
||||||
@@ -645,7 +635,7 @@ private fun ObjCExportBlockCodeGenerator.emitBlockToKotlinFunctionConverters() {
|
|||||||
|
|
||||||
// Note: defining globals declared in runtime.
|
// Note: defining globals declared in runtime.
|
||||||
staticData.placeGlobal("Kotlin_ObjCExport_blockToFunctionConverters", ptr, isExported = true)
|
staticData.placeGlobal("Kotlin_ObjCExport_blockToFunctionConverters", ptr, isExported = true)
|
||||||
staticData.placeGlobal("Kotlin_ObjCExport_blockToFunctionConverters_size", Int32(count), isExported = true)
|
staticData.placeGlobal("Kotlin_ObjCExport_blockToFunctionConverters_size", Int32(arityLimit), isExported = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ObjCExportCodeGenerator.emitSpecialClassesConvertions() {
|
private fun ObjCExportCodeGenerator.emitSpecialClassesConvertions() {
|
||||||
|
|||||||
+8
-4
@@ -15,6 +15,11 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
|||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
|
|
||||||
|
internal fun ClassDescriptor.isMappedFunctionClass() =
|
||||||
|
this.getFunctionalClassKind() == FunctionClassDescriptor.Kind.Function &&
|
||||||
|
// Type parameters include return type.
|
||||||
|
declaredTypeParameters.size - 1 < CustomTypeMappers.functionTypeMappersArityLimit
|
||||||
|
|
||||||
internal interface CustomTypeMapper {
|
internal interface CustomTypeMapper {
|
||||||
val mappedClassId: ClassId
|
val mappedClassId: ClassId
|
||||||
fun mapType(mappedSuperType: KotlinType, translator: ObjCExportTranslatorImpl, objCExportScope: ObjCExportScope): ObjCNonNullReferenceType
|
fun mapType(mappedSuperType: KotlinType, translator: ObjCExportTranslatorImpl, objCExportScope: ObjCExportScope): ObjCNonNullReferenceType
|
||||||
@@ -50,6 +55,8 @@ internal object CustomTypeMappers {
|
|||||||
result.associateBy { it.mappedClassId }
|
result.associateBy { it.mappedClassId }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal val functionTypeMappersArityLimit = 33 // not including, i.e. [0..33)
|
||||||
|
|
||||||
fun hasMapper(descriptor: ClassDescriptor): Boolean {
|
fun hasMapper(descriptor: ClassDescriptor): Boolean {
|
||||||
// Should be equivalent to `getMapper(descriptor) != null`.
|
// Should be equivalent to `getMapper(descriptor) != null`.
|
||||||
if (descriptor.classId in predefined) return true
|
if (descriptor.classId in predefined) return true
|
||||||
@@ -72,9 +79,6 @@ internal object CustomTypeMappers {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ClassDescriptor.isMappedFunctionClass() =
|
|
||||||
this.getFunctionalClassKind() == FunctionClassDescriptor.Kind.Function
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Types to be "hidden" during mapping, i.e. represented as `id`.
|
* Types to be "hidden" during mapping, i.e. represented as `id`.
|
||||||
*
|
*
|
||||||
@@ -142,4 +146,4 @@ internal object CustomTypeMappers {
|
|||||||
return translator.mapFunctionTypeIgnoringNullability(mappedSuperType, objCExportScope, returnsVoid = false)
|
return translator.mapFunctionTypeIgnoringNullability(mappedSuperType, objCExportScope, returnsVoid = false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -308,6 +308,17 @@ __attribute__((swift_name("CoroutinesKt")))
|
|||||||
+ (void)throwCancellationExceptionWithCompletionHandler:(void (^)(KtKotlinUnit * _Nullable, NSError * _Nullable))completionHandler __attribute__((swift_name("throwCancellationException(completionHandler:)")));
|
+ (void)throwCancellationExceptionWithCompletionHandler:(void (^)(KtKotlinUnit * _Nullable, NSError * _Nullable))completionHandler __attribute__((swift_name("throwCancellationException(completionHandler:)")));
|
||||||
@end;
|
@end;
|
||||||
|
|
||||||
|
__attribute__((objc_subclassing_restricted))
|
||||||
|
__attribute__((swift_name("FunctionalTypesKt")))
|
||||||
|
@interface KtFunctionalTypesKt : KtBase
|
||||||
|
+ (void)callDynType2List:(NSArray<id _Nullable (^)(id _Nullable, id _Nullable)> *)list param:(id _Nullable)param __attribute__((swift_name("callDynType2(list:param:)")));
|
||||||
|
+ (void)callStaticType2Fct:(id _Nullable (^)(id _Nullable, id _Nullable))fct param:(id _Nullable)param __attribute__((swift_name("callStaticType2(fct:param:)")));
|
||||||
|
+ (void)callDynType32List:(NSArray<id _Nullable (^)(id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable)> *)list param:(id _Nullable)param __attribute__((swift_name("callDynType32(list:param:)")));
|
||||||
|
+ (void)callStaticType32Fct:(id _Nullable (^)(id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable))fct param:(id _Nullable)param __attribute__((swift_name("callStaticType32(fct:param:)")));
|
||||||
|
+ (void)callDynType33List:(NSArray<id<KtKotlinFunction33>> *)list param:(id _Nullable)param __attribute__((swift_name("callDynType33(list:param:)")));
|
||||||
|
+ (void)callStaticType33Fct:(id _Nullable (^)(id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable, id _Nullable))fct param:(id _Nullable)param __attribute__((swift_name("callStaticType33(fct:param:)")));
|
||||||
|
@end;
|
||||||
|
|
||||||
__attribute__((swift_name("GH4002ArgumentBase")))
|
__attribute__((swift_name("GH4002ArgumentBase")))
|
||||||
@interface KtGH4002ArgumentBase : KtBase
|
@interface KtGH4002ArgumentBase : KtBase
|
||||||
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
|
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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 functionalTypes
|
||||||
|
|
||||||
|
import kotlin.test.*
|
||||||
|
|
||||||
|
typealias AN = Any?
|
||||||
|
|
||||||
|
typealias F2 = (AN, AN) -> AN
|
||||||
|
typealias F5 = (AN, AN, AN, AN, AN) -> AN
|
||||||
|
typealias F6 = (AN, AN, AN, AN, AN, AN,) -> AN
|
||||||
|
typealias F32 = (AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN,
|
||||||
|
AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN,
|
||||||
|
AN, AN, AN, AN, AN, AN, AN, AN) -> AN
|
||||||
|
typealias F33 = (AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN,
|
||||||
|
AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN,
|
||||||
|
AN, AN, AN, AN, AN, AN, AN, AN, AN) -> AN
|
||||||
|
|
||||||
|
fun callDynType2(list: List<F2>, param: AN) {
|
||||||
|
val fct = list.first()
|
||||||
|
val ret = fct(param, null)
|
||||||
|
assertEquals(param, ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun callStaticType2(fct: F2, param: AN) {
|
||||||
|
val ret = fct(param, null)
|
||||||
|
assertEquals(param, ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun callDynType32(list: List<F32>, param: AN) {
|
||||||
|
val fct = list.first()
|
||||||
|
val ret = fct(param
|
||||||
|
, null, null, null, null, null, null, null
|
||||||
|
, null, null, null, null, null, null, null, null
|
||||||
|
, null, null, null, null, null, null, null, null
|
||||||
|
, null, null, null, null, null, null, null, null
|
||||||
|
)
|
||||||
|
assertEquals(param, ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun callStaticType32(fct: F32, param: AN) {
|
||||||
|
val ret = fct(param
|
||||||
|
, null, null, null, null, null, null, null
|
||||||
|
, null, null, null, null, null, null, null, null
|
||||||
|
, null, null, null, null, null, null, null, null
|
||||||
|
, null, null, null, null, null, null, null, null
|
||||||
|
)
|
||||||
|
assertEquals(param, ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun callDynType33(list: List<F33>, param: AN) {
|
||||||
|
val fct = list.first()
|
||||||
|
val ret = fct(param
|
||||||
|
, null, null, null, null, null, null, null
|
||||||
|
, null, null, null, null, null, null, null, null
|
||||||
|
, null, null, null, null, null, null, null, null
|
||||||
|
, null, null, null, null, null, null, null, null, null
|
||||||
|
)
|
||||||
|
assertEquals(param, ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun callStaticType33(fct: F33, param: AN) {
|
||||||
|
val ret = fct(param
|
||||||
|
, null, null, null, null, null, null, null
|
||||||
|
, null, null, null, null, null, null, null, null
|
||||||
|
, null, null, null, null, null, null, null, null
|
||||||
|
, null, null, null, null, null, null, null, null, null
|
||||||
|
)
|
||||||
|
assertEquals(param, ret)
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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 Kt
|
||||||
|
|
||||||
|
private func test1() {
|
||||||
|
FunctionalTypesKt.callStaticType2(fct: foo2, param: "from swift")
|
||||||
|
FunctionalTypesKt.callDynType2(list: [ foo2 ], param: "from swift")
|
||||||
|
|
||||||
|
FunctionalTypesKt.callStaticType2(fct : {a1, _ in return a1 }, param: "from swift block")
|
||||||
|
FunctionalTypesKt.callDynType2(list: [ {a1, _ in return a1 } ], param: "from swift block")
|
||||||
|
|
||||||
|
// 32 params is mapped as regular; block is OK
|
||||||
|
FunctionalTypesKt.callStaticType32(fct : {
|
||||||
|
a1, _, _, _, _, _, _, _,
|
||||||
|
_, _, _, _, _, _, _, _,
|
||||||
|
_, _, _, _, _, _, _, _,
|
||||||
|
_, _, _, _, _, _, _, _
|
||||||
|
in return a1 }, param: "from swift block")
|
||||||
|
|
||||||
|
FunctionalTypesKt.callDynType32(list : [{
|
||||||
|
a1, _, _, _, _, _, _, _,
|
||||||
|
_, _, _, _, _, _, _, _,
|
||||||
|
_, _, _, _, _, _, _, _,
|
||||||
|
_, _, _, _, _, _, _, _
|
||||||
|
in return a1 }], param: "from swift block")
|
||||||
|
|
||||||
|
// 33 params requires explicit implementation of KotlinFunction33
|
||||||
|
FunctionalTypesKt.callStaticType33(fct: foo33, param: "from swift")
|
||||||
|
FunctionalTypesKt.callDynType33(list: [ Foo33() ], param: "from swift")
|
||||||
|
}
|
||||||
|
|
||||||
|
class FunctionalTypesTests : SimpleTestProvider {
|
||||||
|
override init() {
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
test("Test1", test1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func foo2(a1: Any?, _: Any?) -> Any? {
|
||||||
|
return a1
|
||||||
|
}
|
||||||
|
|
||||||
|
private func foo33(a1: Any?, _: Any?, _: Any?, _: Any?, _: Any?, _: Any?, _: Any?, _: Any?,
|
||||||
|
_: Any?, _: Any?, _: Any?, _: Any?, _: Any?, _: Any?, _: Any?, _: Any?,
|
||||||
|
_: Any?, _: Any?, _: Any?, _: Any?, _: Any?, _: Any?, _: Any?, _: Any?,
|
||||||
|
_: Any?, _: Any?, _: Any?, _: Any?, _: Any?, _: Any?, _: Any?, _: Any?, _: Any?
|
||||||
|
) -> Any? {
|
||||||
|
return a1
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Foo33 : KotlinFunction33 {
|
||||||
|
func invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?,
|
||||||
|
p10: Any?, p11: Any?, p12: Any?, p13: Any?, p14: Any?, p15: Any?, p16: Any?, p17: Any?, p18: Any?, p19: Any?,
|
||||||
|
p20: Any?, p21: Any?, p22: Any?, p23: Any?, p24: Any?, p25: Any?, p26: Any?, p27: Any?, p28: Any?, p29: Any?,
|
||||||
|
p30: Any?, p31: Any?, p32: Any?, p33: Any?
|
||||||
|
) -> Any? {
|
||||||
|
return foo33(a1: p1
|
||||||
|
, nil, nil, nil, nil, nil, nil, nil, nil
|
||||||
|
, nil, nil, nil, nil, nil, nil, nil, nil
|
||||||
|
, nil, nil, nil, nil, nil, nil, nil, nil
|
||||||
|
, nil, nil, nil, nil, nil, nil, nil, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user