Don't rely on stdlib when generating framework header
This commit is contained in:
committed by
SvyatoslavScherbina
parent
3632ed495d
commit
fe7685eb03
+9
-4
@@ -9,15 +9,17 @@ import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType
|
||||
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
|
||||
import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
|
||||
internal interface CustomTypeMapper {
|
||||
val mappedClassDescriptor: ClassDescriptor
|
||||
val mappedClassId: ClassId
|
||||
fun mapType(mappedSuperType: KotlinType): ObjCNonNullReferenceType
|
||||
|
||||
class Simple(
|
||||
override val mappedClassDescriptor: ClassDescriptor,
|
||||
override val mappedClassId: ClassId,
|
||||
private val objCClassName: String
|
||||
) : CustomTypeMapper {
|
||||
|
||||
@@ -27,9 +29,12 @@ internal interface CustomTypeMapper {
|
||||
|
||||
class Collection(
|
||||
private val generator: ObjCExportHeaderGenerator,
|
||||
override val mappedClassDescriptor: ClassDescriptor,
|
||||
mappedClassDescriptor: ClassDescriptor,
|
||||
private val objCClassName: String
|
||||
) : CustomTypeMapper {
|
||||
|
||||
override val mappedClassId = mappedClassDescriptor.classId!!
|
||||
|
||||
override fun mapType(mappedSuperType: KotlinType): ObjCNonNullReferenceType {
|
||||
val typeArguments = mappedSuperType.arguments.map {
|
||||
val argument = it.type
|
||||
@@ -49,7 +54,7 @@ internal interface CustomTypeMapper {
|
||||
private val generator: ObjCExportHeaderGenerator,
|
||||
parameterCount: Int
|
||||
) : CustomTypeMapper {
|
||||
override val mappedClassDescriptor = generator.builtIns.getFunction(parameterCount)
|
||||
override val mappedClassId: ClassId = generator.builtIns.getFunction(parameterCount).classId!!
|
||||
|
||||
override fun mapType(mappedSuperType: KotlinType): ObjCNonNullReferenceType {
|
||||
val functionType = mappedSuperType
|
||||
|
||||
+49
-52
@@ -8,11 +8,10 @@ package org.jetbrains.kotlin.backend.konan.objcexport
|
||||
import org.jetbrains.kotlin.backend.konan.*
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.UnsignedType
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.konan.isKonanStdlib
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.constants.ArrayValue
|
||||
import org.jetbrains.kotlin.resolve.constants.KClassValue
|
||||
@@ -50,7 +49,7 @@ abstract class ObjCExportHeaderGenerator(
|
||||
override fun isSpecialMapped(descriptor: ClassDescriptor): Boolean {
|
||||
// TODO: this method duplicates some of the [mapReferenceType] logic.
|
||||
return descriptor == builtIns.any ||
|
||||
descriptor.getAllSuperClassifiers().any { it in customTypeMappers }
|
||||
descriptor.getAllSuperClassifiers().any { it.classId in customTypeMappers }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,19 +58,12 @@ abstract class ObjCExportHeaderGenerator(
|
||||
internal val generatedClasses = mutableSetOf<ClassDescriptor>()
|
||||
internal val topLevel = mutableMapOf<SourceFile, MutableList<CallableMemberDescriptor>>()
|
||||
|
||||
private val stdlibModule = moduleDescriptors.first().allDependencyModules.single { it.isKonanStdlib() }
|
||||
|
||||
private val mappedToNSNumber: List<ClassDescriptor> = with(builtIns) {
|
||||
val result = mutableListOf(boolean, byte, short, int, long, float, double)
|
||||
|
||||
UnsignedType.values().mapTo(result) { unsignedType ->
|
||||
stdlibModule.findClassAcrossModuleDependencies(unsignedType.classId)!!
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
private val customTypeMappers: Map<ClassDescriptor, CustomTypeMapper> = with(builtIns) {
|
||||
/**
|
||||
* Custom type mappers.
|
||||
*
|
||||
* Don't forget to update [hiddenTypes] after adding new one.
|
||||
*/
|
||||
private val customTypeMappers: Map<ClassId, CustomTypeMapper> = with(builtIns) {
|
||||
val result = mutableListOf<CustomTypeMapper>()
|
||||
|
||||
val generator = this@ObjCExportHeaderGenerator
|
||||
@@ -85,32 +77,39 @@ abstract class ObjCExportHeaderGenerator(
|
||||
|
||||
NSNumberKind.values().forEach {
|
||||
// TODO: NSNumber seem to have different equality semantics.
|
||||
if (it.mappedKotlinClassId != null) {
|
||||
val descriptor = stdlibModule.findClassAcrossModuleDependencies(it.mappedKotlinClassId)!!
|
||||
result += CustomTypeMapper.Simple(descriptor, namer.numberBoxName(descriptor).objCName)
|
||||
val classId = it.mappedKotlinClassId
|
||||
if (classId != null) {
|
||||
result += CustomTypeMapper.Simple(classId, namer.numberBoxName(classId).objCName)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
result += CustomTypeMapper.Simple(string, "NSString")
|
||||
result += CustomTypeMapper.Simple(string.classId!!, "NSString")
|
||||
|
||||
(0..mapper.maxFunctionTypeParameterCount).forEach {
|
||||
result += CustomTypeMapper.Function(generator, it)
|
||||
}
|
||||
|
||||
result.associateBy { it.mappedClassDescriptor }
|
||||
result.associateBy { it.mappedClassId }
|
||||
}
|
||||
|
||||
private val hiddenTypes: Set<ClassDescriptor> = run {
|
||||
val customMappedTypes = customTypeMappers.keys
|
||||
|
||||
customMappedTypes
|
||||
.asSequence()
|
||||
.flatMap { it.getAllSuperClassifiers().asSequence() }
|
||||
.map { it as ClassDescriptor }
|
||||
.filter { !customMappedTypes.contains(it) }
|
||||
.toSet()
|
||||
}
|
||||
/**
|
||||
* Types to be "hidden" during mapping, i.e. represented as `id`.
|
||||
*
|
||||
* Currently contains super types of classes handled by [customTypeMappers].
|
||||
* Note: can be generated programmatically, but requires stdlib in this case.
|
||||
*/
|
||||
private val hiddenTypes: Set<ClassId> = listOf(
|
||||
"kotlin.Any",
|
||||
"kotlin.CharSequence",
|
||||
"kotlin.Comparable",
|
||||
"kotlin.Function",
|
||||
"kotlin.Number",
|
||||
"kotlin.collections.Collection",
|
||||
"kotlin.collections.Iterable",
|
||||
"kotlin.collections.MutableCollection",
|
||||
"kotlin.collections.MutableIterable"
|
||||
).map { ClassId.topLevel(FqName(it)) }.toSet()
|
||||
|
||||
private val kotlinAnyName = namer.kotlinAnyName
|
||||
|
||||
@@ -294,8 +293,7 @@ abstract class ObjCExportHeaderGenerator(
|
||||
}
|
||||
|
||||
private fun genKotlinNumber(kotlinClassId: ClassId, kind: NSNumberKind): ObjCInterface {
|
||||
val descriptor = stdlibModule.findClassAcrossModuleDependencies(kotlinClassId)!!
|
||||
val name = namer.numberBoxName(descriptor)
|
||||
val name = namer.numberBoxName(kotlinClassId)
|
||||
|
||||
val members = buildMembers {
|
||||
+nsNumberFactory(kind)
|
||||
@@ -834,26 +832,25 @@ abstract class ObjCExportHeaderGenerator(
|
||||
}
|
||||
|
||||
internal fun mapReferenceTypeIgnoringNullability(kotlinType: KotlinType): ObjCNonNullReferenceType {
|
||||
val typeToMapper = (listOf(kotlinType) + kotlinType.supertypes()).mapNotNull { type ->
|
||||
val mapper = customTypeMappers[type.constructor.declarationDescriptor]
|
||||
if (mapper != null) {
|
||||
type to mapper
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}.toMap()
|
||||
class TypeMappingMatch(val type: KotlinType, val descriptor: ClassDescriptor, val mapper: CustomTypeMapper)
|
||||
|
||||
val mostSpecificTypeToMapper = typeToMapper.filter { (_, mapper) ->
|
||||
typeToMapper.values.all {
|
||||
it.mappedClassDescriptor == mapper.mappedClassDescriptor ||
|
||||
!it.mappedClassDescriptor.isSubclassOf(mapper.mappedClassDescriptor)
|
||||
val typeMappingMatches = (listOf(kotlinType) + kotlinType.supertypes()).mapNotNull { type ->
|
||||
(type.constructor.declarationDescriptor as? ClassDescriptor)?.let { descriptor ->
|
||||
customTypeMappers[descriptor.classId]?.let { mapper ->
|
||||
TypeMappingMatch(type, descriptor, mapper)
|
||||
}
|
||||
}
|
||||
|
||||
// E.g. if both List and MutableList are present, then retain only MutableList.
|
||||
}
|
||||
|
||||
if (mostSpecificTypeToMapper.size > 1) {
|
||||
val types = mostSpecificTypeToMapper.keys.toList()
|
||||
val mostSpecificMatches = typeMappingMatches.filter { match ->
|
||||
typeMappingMatches.all { otherMatch ->
|
||||
otherMatch.descriptor == match.descriptor ||
|
||||
!otherMatch.descriptor.isSubclassOf(match.descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
if (mostSpecificMatches.size > 1) {
|
||||
val types = mostSpecificMatches.map { it.type }
|
||||
val firstType = types[0]
|
||||
val secondType = types[1]
|
||||
|
||||
@@ -863,8 +860,8 @@ abstract class ObjCExportHeaderGenerator(
|
||||
// TODO: the same warning for such classes.
|
||||
}
|
||||
|
||||
mostSpecificTypeToMapper.entries.firstOrNull()?.let { (type, mapper) ->
|
||||
return mapper.mapType(type)
|
||||
mostSpecificMatches.firstOrNull()?.let {
|
||||
return it.mapper.mapType(it.type)
|
||||
}
|
||||
|
||||
val classDescriptor = kotlinType.getErasedTypeClass()
|
||||
@@ -872,7 +869,7 @@ abstract class ObjCExportHeaderGenerator(
|
||||
// TODO: translate `where T : BaseClass, T : SomeInterface` to `BaseClass* <SomeInterface>`
|
||||
|
||||
// TODO: expose custom inline class boxes properly.
|
||||
if (classDescriptor == builtIns.any || classDescriptor in hiddenTypes || classDescriptor.isInlined()) {
|
||||
if (classDescriptor == builtIns.any || classDescriptor.classId in hiddenTypes || classDescriptor.isInlined()) {
|
||||
return ObjCIdType
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.konan.isKonanStdlib
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.*
|
||||
@@ -70,8 +71,8 @@ internal class ObjCExportNamerImpl(
|
||||
val mutableSetName = "MutableSet".toSpecialStandardClassOrProtocolName()
|
||||
val mutableMapName = "MutableDictionary".toSpecialStandardClassOrProtocolName()
|
||||
|
||||
fun numberBoxName(descriptor: ClassDescriptor): ObjCExportNamer.ClassOrProtocolName =
|
||||
descriptor.name.asString().toSpecialStandardClassOrProtocolName()
|
||||
fun numberBoxName(classId: ClassId): ObjCExportNamer.ClassOrProtocolName =
|
||||
classId.shortClassName.asString().toSpecialStandardClassOrProtocolName()
|
||||
|
||||
val kotlinNumberName = "Number".toSpecialStandardClassOrProtocolName()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user