From e65ae1c9f7699ed68a6b328c90224886b53d8ba9 Mon Sep 17 00:00:00 2001 From: SvyatoslavScherbina Date: Fri, 2 Aug 2019 11:42:37 +0300 Subject: [PATCH] Avoid relying on 22 max function parameters count in ObjCExport frontend (#3235) --- .../konan/objcexport/CustomTypeMapper.kt | 40 +++++++++++++++---- .../objcexport/ObjCExportHeaderGenerator.kt | 2 +- .../konan/objcexport/ObjCExportMapper.kt | 5 ++- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/CustomTypeMapper.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/CustomTypeMapper.kt index 34dd5802da4..f28e2d1f71b 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/CustomTypeMapper.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/CustomTypeMapper.kt @@ -6,8 +6,12 @@ package org.jetbrains.kotlin.backend.konan.objcexport import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor +import org.jetbrains.kotlin.builtins.getFunctionalClassKind +import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.resolve.descriptorUtil.classId import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils @@ -22,7 +26,7 @@ internal object CustomTypeMappers { * * Don't forget to update [hiddenTypes] after adding new one. */ - val byClassId: Map = with(KotlinBuiltIns.FQ_NAMES) { + private val predefined: Map = with(KotlinBuiltIns.FQ_NAMES) { val result = mutableListOf() result += Collection(list, "NSArray") @@ -43,13 +47,34 @@ internal object CustomTypeMappers { result += Simple(ClassId.topLevel(string.toSafe()), "NSString") - (0..ObjCExportMapper.maxFunctionTypeParameterCount).forEach { - result += Function(it) - } - result.associateBy { it.mappedClassId } } + fun hasMapper(descriptor: ClassDescriptor): Boolean { + // Should be equivalent to `getMapper(descriptor) != null`. + if (descriptor.classId in predefined) return true + if (descriptor.isMappedFunctionClass()) return true + return false + } + + fun getMapper(descriptor: ClassDescriptor): CustomTypeMapper? { + val classId = descriptor.classId + + predefined[classId]?.let { return it } + + if (descriptor.isMappedFunctionClass()) { + // TODO: somewhat hacky, consider using FunctionClassDescriptor.arity later. + val arity = descriptor.declaredTypeParameters.size - 1 // Type parameters include return type. + assert(classId == KotlinBuiltIns.getFunctionClassId(arity)) + return Function(arity) + } + + return null + } + + private fun ClassDescriptor.isMappedFunctionClass() = + this.getFunctionalClassKind() == FunctionClassDescriptor.Kind.Function + /** * Types to be "hidden" during mapping, i.e. represented as `id`. * @@ -109,8 +134,9 @@ internal object CustomTypeMappers { } } - private class Function(parameterCount: Int) : CustomTypeMapper { - override val mappedClassId: ClassId = KotlinBuiltIns.getFunctionClassId(parameterCount) + private class Function(private val parameterCount: Int) : CustomTypeMapper { + override val mappedClassId: ClassId + get() = KotlinBuiltIns.getFunctionClassId(parameterCount) override fun mapType(mappedSuperType: KotlinType, translator: ObjCExportTranslatorImpl, objCExportScope: ObjCExportScope): ObjCNonNullReferenceType { return translator.mapFunctionTypeIgnoringNullability(mappedSuperType, objCExportScope, returnsVoid = false) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportHeaderGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportHeaderGenerator.kt index cebed2e79c1..10000052e4d 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportHeaderGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportHeaderGenerator.kt @@ -756,7 +756,7 @@ internal class ObjCExportTranslatorImpl( val typeMappingMatches = (listOf(kotlinType) + kotlinType.supertypes()).mapNotNull { type -> (type.constructor.declarationDescriptor as? ClassDescriptor)?.let { descriptor -> - mapper.customTypeMappers[descriptor.classId]?.let { mapper -> + mapper.getCustomTypeMapper(descriptor)?.let { mapper -> TypeMappingMatch(type, descriptor, mapper) } } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportMapper.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportMapper.kt index b635aa807d5..f753f41d0ae 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportMapper.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportMapper.kt @@ -31,13 +31,14 @@ internal class ObjCExportMapper( val maxFunctionTypeParameterCount get() = KONAN_FUNCTION_INTERFACES_MAX_PARAMETERS } - val customTypeMappers: Map get() = CustomTypeMappers.byClassId + fun getCustomTypeMapper(descriptor: ClassDescriptor): CustomTypeMapper? = CustomTypeMappers.getMapper(descriptor) + val hiddenTypes: Set get() = CustomTypeMappers.hiddenTypes fun isSpecialMapped(descriptor: ClassDescriptor): Boolean { // TODO: this method duplicates some of the [ObjCExportTranslatorImpl.mapReferenceType] logic. return KotlinBuiltIns.isAny(descriptor) || - descriptor.getAllSuperClassifiers().any { it.classId in customTypeMappers } + descriptor.getAllSuperClassifiers().any { it is ClassDescriptor && CustomTypeMappers.hasMapper(it) } } private val methodBridgeCache = mutableMapOf()