Expose big arity functional types as FunctionN interface [KT-37166] (#4267)

This commit is contained in:
Vladimir Ivanov
2020-07-08 00:14:36 +03:00
committed by GitHub
parent c195ade201
commit 8084bc7a3b
6 changed files with 178 additions and 31 deletions
@@ -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) }
}
}
}
@@ -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() {
@@ -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)
}
}