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 builtFunctionNClasses get() =
|
||||
builtClassesMap.values
|
||||
.filter { it -> (it.descriptor as FunctionClassDescriptor).functionKind == FunctionClassDescriptor.Kind.Function }
|
||||
.map { FunctionalInterface(it, (it.descriptor as FunctionClassDescriptor).arity) }
|
||||
val builtFunctionNClasses get() = builtClassesMap.values.mapNotNull {
|
||||
with(it.descriptor as FunctionClassDescriptor) {
|
||||
if (functionKind == FunctionClassDescriptor.Kind.Function)
|
||||
FunctionalInterface(it, arity)
|
||||
else null
|
||||
}
|
||||
}
|
||||
|
||||
private fun createTypeParameter(descriptor: TypeParameterDescriptor) =
|
||||
symbolTable?.declareGlobalTypeParameter(
|
||||
@@ -343,4 +346,4 @@ internal class BuiltInFictitiousFunctionIrClassFactory(
|
||||
|
||||
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() {
|
||||
require(context.producedLlvmModuleContainsStdlib)
|
||||
var count = context.ir.symbols.functionIrClassFactory.builtFunctionNClasses.size
|
||||
// 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 ->
|
||||
mappedFunctionNClasses.forEach { functionClass ->
|
||||
val converter = kotlinFunctionToBlockConverter(BlockPointerBridge(functionClass.arity, returnsVoid = false))
|
||||
|
||||
val writableTypeInfoValue = buildWritableTypeInfoValue(converter = constPointer(converter))
|
||||
@@ -619,22 +616,15 @@ private fun ObjCExportBlockCodeGenerator.emitFunctionConverters() {
|
||||
|
||||
private fun ObjCExportBlockCodeGenerator.emitBlockToKotlinFunctionConverters() {
|
||||
require(context.producedLlvmModuleContainsStdlib)
|
||||
val functionClassesByArity =
|
||||
context.ir.symbols.functionIrClassFactory.builtFunctionNClasses.associateBy { it.arity }
|
||||
val functionClassesByArity = mappedFunctionNClasses.associateBy { it.arity }
|
||||
|
||||
var count = ((functionClassesByArity.keys.maxOrNull() ?: -1) + 1)
|
||||
// TODO: ugly hack to avoid huge unneeded adaptors linked into every binary, needs rework.
|
||||
if (context.config.produce.isCache) {
|
||||
count = count.coerceAtMost(maxConvertorsInCache)
|
||||
}
|
||||
val converters = (0 until count).map { arity ->
|
||||
val functionClass = functionClassesByArity[arity]
|
||||
if (functionClass != null) {
|
||||
val bridge = BlockPointerBridge(numberOfParameters = functionClass.arity, returnsVoid = false)
|
||||
val arityLimit = (functionClassesByArity.keys.maxOrNull() ?: -1) + 1
|
||||
|
||||
val converters = (0 until arityLimit).map { arity ->
|
||||
functionClassesByArity[arity]?.let {
|
||||
val bridge = BlockPointerBridge(numberOfParameters = arity, returnsVoid = false)
|
||||
constPointer(blockToKotlinFunctionConverter(bridge))
|
||||
} else {
|
||||
NullPointer(objCToKotlinFunctionType)
|
||||
}
|
||||
} ?: NullPointer(objCToKotlinFunctionType)
|
||||
}
|
||||
|
||||
val ptr = staticData.placeGlobalArray(
|
||||
@@ -645,7 +635,7 @@ private fun ObjCExportBlockCodeGenerator.emitBlockToKotlinFunctionConverters() {
|
||||
|
||||
// Note: defining globals declared in runtime.
|
||||
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() {
|
||||
|
||||
+8
-4
@@ -15,6 +15,11 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
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 {
|
||||
val mappedClassId: ClassId
|
||||
fun mapType(mappedSuperType: KotlinType, translator: ObjCExportTranslatorImpl, objCExportScope: ObjCExportScope): ObjCNonNullReferenceType
|
||||
@@ -50,6 +55,8 @@ internal object CustomTypeMappers {
|
||||
result.associateBy { it.mappedClassId }
|
||||
}
|
||||
|
||||
internal val functionTypeMappersArityLimit = 33 // not including, i.e. [0..33)
|
||||
|
||||
fun hasMapper(descriptor: ClassDescriptor): Boolean {
|
||||
// Should be equivalent to `getMapper(descriptor) != null`.
|
||||
if (descriptor.classId in predefined) return true
|
||||
@@ -72,9 +79,6 @@ internal object CustomTypeMappers {
|
||||
return null
|
||||
}
|
||||
|
||||
private fun ClassDescriptor.isMappedFunctionClass() =
|
||||
this.getFunctionalClassKind() == FunctionClassDescriptor.Kind.Function
|
||||
|
||||
/**
|
||||
* 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,6 +308,17 @@ __attribute__((swift_name("CoroutinesKt")))
|
||||
+ (void)throwCancellationExceptionWithCompletionHandler:(void (^)(KtKotlinUnit * _Nullable, NSError * _Nullable))completionHandler __attribute__((swift_name("throwCancellationException(completionHandler:)")));
|
||||
@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")))
|
||||
@interface KtGH4002ArgumentBase : KtBase
|
||||
- (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