[ObjCExport] Support nullable type arguments in translating known Collection types

^KT-65167
This commit is contained in:
Sebastian Sellmair
2024-01-24 11:19:33 +01:00
committed by Space Team
parent 858af02a24
commit 3111678f8b
3 changed files with 74 additions and 56 deletions
@@ -6,7 +6,6 @@ import com.intellij.openapi.util.io.FileUtil
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.annotations.annotationInfos
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.backend.konan.InternalKotlinNativeApi
import org.jetbrains.kotlin.backend.konan.KonanFqNames
import org.jetbrains.kotlin.backend.konan.objcexport.*
@@ -14,7 +13,6 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.NameUtils
import org.jetbrains.kotlin.objcexport.Predefined.anyMethodSelectors
import org.jetbrains.kotlin.objcexport.analysisApiUtils.getFunctionMethodBridge
import org.jetbrains.kotlin.objcexport.analysisApiUtils.getInlineTargetTypeOrNull
import org.jetbrains.kotlin.objcexport.analysisApiUtils.isVisibleInObjC
import org.jetbrains.kotlin.psi.KtFile
@@ -327,7 +325,7 @@ fun KtFunctionLikeSymbol.mapReturnType(returnBridge: MethodBridge.ReturnValue):
MethodBridge.ReturnValue.Void,
-> ObjCVoidType
MethodBridge.ReturnValue.HashCode -> ObjCPrimitiveType.NSUInteger
is MethodBridge.ReturnValue.Mapped -> returnType.mapType(returnBridge.bridge)
is MethodBridge.ReturnValue.Mapped -> returnType.translateToObjCType(returnBridge.bridge)
MethodBridge.ReturnValue.WithError.Success -> ObjCPrimitiveType.BOOL
is MethodBridge.ReturnValue.WithError.ZeroForError -> {
val successReturnType = mapReturnType(returnBridge.successBridge)
@@ -349,44 +347,3 @@ fun KtFunctionLikeSymbol.mapReturnType(returnBridge: MethodBridge.ReturnValue):
-> ObjCInstanceType
}
}
/**
* [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportTranslatorImpl.mapType]
*/
context(KtAnalysisSession, KtObjCExportSession)
private fun KtType.mapType(typeBridge: TypeBridge): ObjCType {
//if (!this.isObjCObjectType()) return null //TODO implement isObjCObjectType
return when (typeBridge) {
is ReferenceBridge -> this.translateToObjCReferenceType()
is BlockPointerBridge -> this.translateToObjCFunctionType(typeBridge)
is ValueTypeBridge -> when (typeBridge.objCValueType) {
ObjCValueType.BOOL -> ObjCPrimitiveType.BOOL
ObjCValueType.UNICHAR -> ObjCPrimitiveType.unichar
ObjCValueType.CHAR -> ObjCPrimitiveType.int8_t
ObjCValueType.SHORT -> ObjCPrimitiveType.int16_t
ObjCValueType.INT -> ObjCPrimitiveType.int32_t
ObjCValueType.LONG_LONG -> ObjCPrimitiveType.int64_t
ObjCValueType.UNSIGNED_CHAR -> ObjCPrimitiveType.uint8_t
ObjCValueType.UNSIGNED_SHORT -> ObjCPrimitiveType.uint16_t
ObjCValueType.UNSIGNED_INT -> ObjCPrimitiveType.uint32_t
ObjCValueType.UNSIGNED_LONG_LONG -> ObjCPrimitiveType.uint64_t
ObjCValueType.FLOAT -> ObjCPrimitiveType.float
ObjCValueType.DOUBLE -> ObjCPrimitiveType.double
ObjCValueType.POINTER -> ObjCPointerType(ObjCVoidType, isBinaryRepresentationNullable())
}
}
}
context(KtAnalysisSession)
private fun KtType.isBinaryRepresentationNullable(): Boolean {
if (fullyExpandedType.isMarkedNullable) return true
getInlineTargetTypeOrNull()?.let { inlineTargetType ->
if (inlineTargetType.isMarkedNullable) return true
}
return false
}
@@ -42,7 +42,7 @@ internal fun KtFunctionLikeSymbol.translateToObjCParameters(baseMethodBridge: Me
val type = when (bridge) {
is MethodBridgeValueParameter.Mapped ->
parameter!!.returnType.translateToObjCReferenceType()
parameter!!.returnType.translateToObjCType(bridge.bridge)
MethodBridgeValueParameter.ErrorOutParameter ->
ObjCPointerType(ObjCNullableReferenceType(ObjCClassType("NSError")), nullable = true)
@@ -8,10 +8,53 @@ import org.jetbrains.kotlin.backend.konan.objcexport.*
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.objcexport.analysisApiUtils.getInlineTargetTypeOrNull
import org.jetbrains.kotlin.objcexport.analysisApiUtils.isError
import org.jetbrains.kotlin.objcexport.analysisApiUtils.objCErrorType
/**
* [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportTranslatorImpl.mapType]
*/
context(KtAnalysisSession, KtObjCExportSession)
internal fun KtType.translateToObjCType(typeBridge: TypeBridge): ObjCType {
//if (!this.isObjCObjectType()) return null //TODO implement isObjCObjectType
return when (typeBridge) {
is ReferenceBridge -> this.translateToObjCReferenceType()
is BlockPointerBridge -> this.translateToObjCFunctionType(typeBridge)
is ValueTypeBridge -> when (typeBridge.objCValueType) {
ObjCValueType.BOOL -> ObjCPrimitiveType.BOOL
ObjCValueType.UNICHAR -> ObjCPrimitiveType.unichar
ObjCValueType.CHAR -> ObjCPrimitiveType.int8_t
ObjCValueType.SHORT -> ObjCPrimitiveType.int16_t
ObjCValueType.INT -> ObjCPrimitiveType.int32_t
ObjCValueType.LONG_LONG -> ObjCPrimitiveType.int64_t
ObjCValueType.UNSIGNED_CHAR -> ObjCPrimitiveType.uint8_t
ObjCValueType.UNSIGNED_SHORT -> ObjCPrimitiveType.uint16_t
ObjCValueType.UNSIGNED_INT -> ObjCPrimitiveType.uint32_t
ObjCValueType.UNSIGNED_LONG_LONG -> ObjCPrimitiveType.uint64_t
ObjCValueType.FLOAT -> ObjCPrimitiveType.float
ObjCValueType.DOUBLE -> ObjCPrimitiveType.double
ObjCValueType.POINTER -> ObjCPointerType(ObjCVoidType, isBinaryRepresentationNullable())
}
}
}
context(KtAnalysisSession)
private fun KtType.isBinaryRepresentationNullable(): Boolean {
if (fullyExpandedType.isMarkedNullable) return true
getInlineTargetTypeOrNull()?.let { inlineTargetType ->
if (inlineTargetType.isMarkedNullable) return true
}
return false
}
/**
* [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportTranslatorImpl.mapReferenceType]
*/
@@ -36,7 +79,7 @@ private fun KtType.mapToReferenceTypeIgnoringNullability(): ObjCNonNullReference
return ObjCIdType
}
if (classId in hiddenTypes) {
if (classId in hiddenClassIds) {
return ObjCIdType
}
@@ -76,18 +119,30 @@ private fun KtType.mapToReferenceTypeIgnoringNullability(): ObjCNonNullReference
val typeName = typesMap[classId]
?: classId!!.shortClassName.asString().getObjCKotlinStdlibClassOrProtocolName().objCName
val typeArguments = run {
if (this !is KtNonErrorClassType) {
return@run listOf<ObjCNonNullReferenceType>()
}
ownTypeArguments.mapNotNull { typeArgument -> typeArgument.type }
.map { typeArgumentType -> typeArgumentType.mapToReferenceTypeIgnoringNullability() }
}
val typeArguments = translateToObjCTypeArguments()
return ObjCClassType(typeName, typeArguments)
}
context(KtAnalysisSession, KtObjCExportSession)
private fun KtType.translateToObjCTypeArguments(): List<ObjCNonNullReferenceType> {
if (this !is KtNonErrorClassType) return emptyList()
/* See special casing below */
val isKnownCollectionType = classId in collectionClassIds
return ownTypeArguments.mapNotNull { typeArgument -> typeArgument.type }
.map { typeArgumentType ->
/*
Kotlin `null` keys and values are represented as `NSNull` singleton in collections
*/
if (isKnownCollectionType && typeArgumentType.isMarkedNullable) return@map ObjCIdType
typeArgumentType.mapToReferenceTypeIgnoringNullability()
}
}
private fun ObjCNonNullReferenceType.withNullabilityOf(kotlinType: KtType): ObjCReferenceType {
return if (kotlinType.nullability.isNullable) {
ObjCNullableReferenceType(this)
@@ -102,7 +157,7 @@ private fun ObjCNonNullReferenceType.withNullabilityOf(kotlinType: KtType): ObjC
* Currently contains super types of classes handled by custom type mappers.
* Note: can be generated programmatically, but requires stdlib in this case.
*/
private val hiddenTypes: Set<ClassId> = listOf(
private val hiddenClassIds: Set<ClassId> = listOf(
"kotlin.Any",
"kotlin.CharSequence",
"kotlin.Comparable",
@@ -112,4 +167,10 @@ private val hiddenTypes: Set<ClassId> = listOf(
"kotlin.collections.Iterable",
"kotlin.collections.MutableCollection",
"kotlin.collections.MutableIterable"
).map { ClassId.topLevel(FqName(it)) }.toSet()
).map { ClassId.topLevel(FqName(it)) }.toSet()
private val collectionClassIds = setOf(
StandardClassIds.List, StandardClassIds.MutableList,
StandardClassIds.Set, StandardClassIds.MutableSet,
StandardClassIds.Map, StandardClassIds.MutableMap
)