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