[MPP] Improve creation of @UnsafeNumber w.r.t. non-aliased types and PIC

^KT-51643
This commit is contained in:
Pavel Kirpichenkov
2022-03-17 16:40:27 +03:00
committed by teamcity
parent e09f30f442
commit 621f14c5bb
12 changed files with 494 additions and 112 deletions
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.commonizer.utils.Interner
import org.jetbrains.kotlin.commonizer.utils.appendHashCode
import org.jetbrains.kotlin.commonizer.utils.hashCode
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
/**
* The hierarchy of [CirType]:
@@ -87,6 +88,9 @@ sealed class CirClassOrTypeAliasType : CirSimpleType(), AnyClassOrTypeAliasType
abstract class CirClassType : CirClassOrTypeAliasType() {
abstract val outerType: CirClassType?
abstract val attachments: List<CirTypeAttachment>
inline fun <reified T : CirTypeAttachment> getAttachment(): T? = attachments.firstIsInstanceOrNull()
override fun appendDescriptionTo(builder: StringBuilder, shortNameOnly: Boolean) {
val outerType = outerType
@@ -107,13 +111,15 @@ abstract class CirClassType : CirClassOrTypeAliasType() {
classId: CirEntityId,
outerType: CirClassType?,
arguments: List<CirTypeProjection>,
isMarkedNullable: Boolean
isMarkedNullable: Boolean,
attachments: List<CirTypeAttachment> = emptyList()
): CirClassType = interner.intern(
CirClassTypeInternedImpl(
classifierId = classId,
outerType = outerType,
arguments = arguments,
isMarkedNullable = isMarkedNullable
isMarkedNullable = isMarkedNullable,
attachments = attachments,
)
)
@@ -121,13 +127,15 @@ abstract class CirClassType : CirClassOrTypeAliasType() {
classifierId: CirEntityId = this.classifierId,
outerType: CirClassType? = this.outerType,
arguments: List<CirTypeProjection> = this.arguments,
isMarkedNullable: Boolean = this.isMarkedNullable
isMarkedNullable: Boolean = this.isMarkedNullable,
attachments: List<CirTypeAttachment> = this.attachments,
): CirClassType {
return createInterned(
classId = classifierId,
outerType = outerType,
arguments = arguments,
isMarkedNullable = isMarkedNullable
isMarkedNullable = isMarkedNullable,
attachments = attachments,
)
}
@@ -217,12 +225,14 @@ private class CirClassTypeInternedImpl(
override val outerType: CirClassType?,
override val arguments: List<CirTypeProjection>,
override val isMarkedNullable: Boolean,
override val attachments: List<CirTypeAttachment> = emptyList(),
) : CirClassType() {
private val hashCode = hashCode(classifierId)
.appendHashCode(outerType)
.appendHashCode(arguments)
.appendHashCode(isMarkedNullable)
.appendHashCode(attachments.toTypedArray())
override fun hashCode(): Int = hashCode
@@ -232,6 +242,7 @@ private class CirClassTypeInternedImpl(
&& isMarkedNullable == other.isMarkedNullable
&& arguments == other.arguments
&& outerType == other.outerType
&& attachments == other.attachments
else -> false
}
}
@@ -262,3 +273,8 @@ private class CirTypeAliasTypeInternedImpl(
else -> false
}
}
/**
* Marker interface for arbitrary metadata that can be attached to a type during commonization
*/
interface CirTypeAttachment
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DELEGATION
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class FunctionOrPropertyBaseCommonizer(
private val classifiers: CirKnownClassifiers,
@@ -49,11 +48,14 @@ class FunctionOrPropertyBaseCommonizer(
return null
}
val additionalUnsafeNumberAnnotation =
createUnsafeNumberAnnotationIfNecessary(
classifiers.classifierIndices.targets, settings, values,
getTypeIdFromDeclarationForCheck = ::getFunctionOrPropertyReturnTypeId,
)
val returnType = returnTypeCommonizer(values) ?: return null
val unsafeNumberAnnotation = createUnsafeNumberAnnotationIfNecessary(
classifiers.classifierIndices.targets, settings,
inputDeclarations = values,
inputTypes = values.map { it.returnType },
commonizedType = returnType,
)
return FunctionOrProperty(
name = values.first().name,
@@ -63,17 +65,7 @@ class FunctionOrPropertyBaseCommonizer(
extensionReceiver = (extensionReceiverCommonizer(values.map { it.extensionReceiver }) ?: return null).receiver,
returnType = returnTypeCommonizer(values) ?: return null,
typeParameters = TypeParameterListCommonizer(typeCommonizer).commonize(values.map { it.typeParameters }) ?: return null,
additionalAnnotations = listOfNotNull(additionalUnsafeNumberAnnotation)
additionalAnnotations = listOfNotNull(unsafeNumberAnnotation)
)
}
}
private fun getFunctionOrPropertyReturnTypeId(functionOrProperty: CirFunctionOrProperty): CirEntityId? {
return functionOrProperty.returnType.let { returnType ->
when (returnType) {
is CirFlexibleType -> returnType.lowerBound.safeAs<CirClassOrTypeAliasType>()?.classifierId
else -> returnType.safeAs<CirClassOrTypeAliasType>()?.classifierId
}
}
}
@@ -0,0 +1,46 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.commonizer.core
import org.jetbrains.kotlin.commonizer.cir.*
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
import org.jetbrains.kotlin.utils.addToStdlib.ifTrue
fun renderTypeForUnsafeNumberAnnotation(type: CirType): String = when (type) {
is CirSimpleType -> renderSimpleType(type)
is CirFlexibleType -> renderFlexibleType(type)
}
private fun renderFlexibleType(type: CirFlexibleType): String =
"${renderTypeForUnsafeNumberAnnotation(type.lowerBound)}..${renderTypeForUnsafeNumberAnnotation(type.upperBound)}"
private fun renderSimpleType(type: CirSimpleType): String {
return when (type) {
is CirTypeAliasType -> renderSimpleType(type.expandedType())
is CirClassType -> "${type.classifierId.toQualifiedNameString()}${renderArguments(type.arguments)}${type.renderNullable()}"
is CirTypeParameterType -> "$TYPE_PARAMETER_TYPE_PREFIX${type.index}${type.renderNullable()}"
}
}
private fun renderArguments(arguments: List<CirTypeProjection>): String {
return arguments.ifNotEmpty { joinToString(prefix = "<", postfix = ">") { renderTypeArgument(it) } }.orEmpty()
}
private fun renderTypeArgument(typeArgument: CirTypeProjection): String {
return when (typeArgument) {
is CirRegularTypeProjection -> "${renderVariance(typeArgument.projectionKind)}${renderTypeForUnsafeNumberAnnotation(typeArgument.type)}"
CirStarTypeProjection -> STAR_PROJECTION
}
}
private fun renderVariance(variance: Variance): String = "$variance ".takeIf { it.isNotBlank() }.orEmpty()
private fun CirSimpleType.renderNullable(): String = isMarkedNullable.ifTrue { NULLABLE }.orEmpty()
private const val NULLABLE: String = "?"
private const val STAR_PROJECTION: String = "*"
private const val TYPE_PARAMETER_TYPE_PREFIX = "#"
@@ -0,0 +1,68 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.commonizer.core
import org.jetbrains.kotlin.commonizer.cir.*
interface CirTypeVisitor {
fun visit(type: CirType)
fun visit(flexibleType: CirFlexibleType)
fun visit(simpleType: CirSimpleType)
fun visit(typeParameterType: CirTypeParameterType)
fun visit(classOrTypeAliasType: CirClassOrTypeAliasType)
fun visit(classType: CirClassType)
fun visit(typeAliasType: CirTypeAliasType)
fun visit(typeProjection: CirTypeProjection)
}
open class BasicCirTypeVisitor : CirTypeVisitor {
override fun visit(type: CirType) {
return when (type) {
is CirFlexibleType -> visit(type)
is CirSimpleType -> visit(type)
}
}
override fun visit(flexibleType: CirFlexibleType) {
visit(flexibleType.lowerBound)
visit(flexibleType.upperBound)
}
override fun visit(simpleType: CirSimpleType) {
when (simpleType) {
is CirTypeParameterType -> visit(simpleType)
is CirClassOrTypeAliasType -> visit(simpleType)
}
}
override fun visit(typeParameterType: CirTypeParameterType) {
}
override fun visit(classOrTypeAliasType: CirClassOrTypeAliasType) {
when (classOrTypeAliasType) {
is CirClassType -> visit(classOrTypeAliasType)
is CirTypeAliasType -> visit(classOrTypeAliasType)
}
}
override fun visit(classType: CirClassType) {
classType.outerType?.let { visit(it) }
classType.arguments.forEach { visit(it) }
}
override fun visit(typeAliasType: CirTypeAliasType) {
visit(typeAliasType.underlyingType)
}
override fun visit(typeProjection: CirTypeProjection) {
if (typeProjection is CirRegularTypeProjection)
visit(typeProjection.type)
}
}
fun CirType.accept(visitor: CirTypeVisitor) {
visitor.visit(this)
}
@@ -5,8 +5,8 @@
package org.jetbrains.kotlin.commonizer.core
import org.jetbrains.kotlin.commonizer.cir.CirClassType
import org.jetbrains.kotlin.commonizer.cir.CirEntityId
import org.jetbrains.kotlin.commonizer.cir.*
import org.jetbrains.kotlin.commonizer.cir.CirClassType.Companion.copyInterned
import org.jetbrains.kotlin.commonizer.utils.*
private typealias BitWidth = Int
@@ -72,25 +72,19 @@ private val floatingPointVars = SubstitutableNumbers(
internal object OptimisticNumbersTypeCommonizer : AssociativeCommonizer<CirClassType> {
override fun commonize(first: CirClassType, second: CirClassType): CirClassType? {
return signedIntegers.choose(first, second)
val result = signedIntegers.choose(first, second)
?: unsignedIntegers.choose(first, second)
?: floatingPoints.choose(first, second)
?: signedVarIntegers.choose(first, second)
?: unsignedVarIntegers.choose(first, second)
?: floatingPointVars.choose(first, second)
return result?.withMarker()
}
fun isOptimisticallySubstitutable(classId: CirEntityId): Boolean {
val firstPackageSegment = classId.packageName.segments.firstOrNull()
if (firstPackageSegment != "kotlinx" && firstPackageSegment != "kotlin") {
return false
}
private fun CirClassType.withMarker(): CirClassType = this.copyInterned(
attachments = attachments + OptimisticCommonizationMarker
)
return classId in signedIntegers
|| classId in unsignedIntegers
|| classId in floatingPoints
|| classId in signedVarIntegers
|| classId in unsignedVarIntegers
|| classId in floatingPointVars
}
internal object OptimisticCommonizationMarker : CirTypeAttachment
}
@@ -10,9 +10,9 @@ import org.jetbrains.kotlin.commonizer.cir.*
import org.jetbrains.kotlin.commonizer.mergedtree.CirKnownClassifiers
class TypeAliasCommonizer(
typeCommonizer: TypeCommonizer,
private val classifiers: CirKnownClassifiers,
private val settings: CommonizerSettings,
typeCommonizer: TypeCommonizer,
) : NullableSingleInvocationCommonizer<CirTypeAlias> {
private val typeCommonizer = typeCommonizer.withContext {
@@ -30,18 +30,20 @@ class TypeAliasCommonizer(
val visibility = VisibilityCommonizer.lowering().commonize(values) ?: return null
val unsafeNumberAnnotation = createUnsafeNumberAnnotationIfNecessary(
classifiers.classifierIndices.targets, settings,
inputDeclarations = values,
inputTypes = values.map { it.underlyingType },
commonizedType = underlyingType,
)
return CirTypeAlias.create(
name = name,
typeParameters = typeParameters,
visibility = visibility,
underlyingType = underlyingType,
expandedType = underlyingType.expandedType(),
annotations = listOfNotNull(
createUnsafeNumberAnnotationIfNecessary(
classifiers.classifierIndices.targets, settings, values,
getTypeIdFromDeclarationForCheck = { typeAlias -> typeAlias.expandedType.classifierId }
)
)
annotations = listOfNotNull(unsafeNumberAnnotation),
)
}
}
@@ -12,44 +12,28 @@ import org.jetbrains.kotlin.commonizer.allLeaves
import org.jetbrains.kotlin.commonizer.cir.*
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
internal fun <T : CirHasAnnotations> createUnsafeNumberAnnotationIfNecessary(
fun createUnsafeNumberAnnotationIfNecessary(
targets: List<CommonizerTarget>,
settings: CommonizerSettings,
values: List<T>,
getTypeIdFromDeclarationForCheck: (declaration: T) -> CirEntityId?,
inputDeclarations: List<CirHasAnnotations>,
inputTypes: List<CirType>,
commonizedType: CirType,
): CirAnnotation? {
val isOptimisticCommonizationEnabled = settings.getSetting(OptimisticNumberCommonizationEnabledKey)
if (!isOptimisticCommonizationEnabled)
if (!shouldCreateAnnotation(settings, commonizedType, inputDeclarations))
return null
val typeIds = values.map { annotated -> getTypeIdFromDeclarationForCheck(annotated) }
val actualPlatformTypes = mutableMapOf<String, RenderedType>()
// All typealias have to be potentially substitutable (aka have to be some kind of number type)
if (!typeIds.all { it != null && OptimisticNumbersTypeCommonizer.isOptimisticallySubstitutable(it) }) {
return null
inputTypes.zip(targets).forEach { (type, target) ->
target.allLeaves().forEach { leafCommonizerTarget ->
actualPlatformTypes[leafCommonizerTarget.name] = renderTypeForUnsafeNumberAnnotation(type)
}
}
return createUnsafeNumberAnnotation(targets, values, getTypeIdFromDeclarationForCheck)
}
private fun <T : CirHasAnnotations> createUnsafeNumberAnnotation(
targets: List<CommonizerTarget>,
values: List<T>,
getTypeIdFromDeclaration: (declaration: T) -> CirEntityId?,
): CirAnnotation? {
val actualPlatformTypes = mutableMapOf<String, CirEntityId>()
values.forEachIndexed forEach@{ index, annotated ->
inputDeclarations.forEach { annotated ->
val existingAnnotation = annotated.annotations.firstIsInstanceOrNull<UnsafeNumberAnnotation>()
if (existingAnnotation != null) {
actualPlatformTypes.putAll(existingAnnotation.actualPlatformTypes)
return@forEach
}
targets[index].allLeaves().forEach { target ->
actualPlatformTypes[target.name] = getTypeIdFromDeclaration(annotated)
?: throw IllegalStateException("Expect class or type alias type")
}
}
@@ -60,14 +44,43 @@ private fun <T : CirHasAnnotations> createUnsafeNumberAnnotation(
return null
}
private class UnsafeNumberAnnotation(val actualPlatformTypes: Map<String, CirEntityId>) : CirAnnotation {
private fun shouldCreateAnnotation(
settings: CommonizerSettings,
commonizedType: CirType,
inputDeclarations: List<CirHasAnnotations>,
): Boolean {
if (!settings.getSetting(OptimisticNumberCommonizationEnabledKey))
return false
val annotatedInputDeclarationPresent = inputDeclarations.any { declaration ->
declaration.annotations.any { annotation -> annotation is UnsafeNumberAnnotation }
}
if (annotatedInputDeclarationPresent)
return true
var isMarkedTypeFound = false
commonizedType.accept(object : BasicCirTypeVisitor() {
override fun visit(classType: CirClassType) {
classType.getAttachment<OptimisticNumbersTypeCommonizer.OptimisticCommonizationMarker>()?.let { isMarkedTypeFound = true }
?: super.visit(classType)
}
})
return isMarkedTypeFound
}
private typealias RenderedType = String
private class UnsafeNumberAnnotation(val actualPlatformTypes: Map<String, RenderedType>) : CirAnnotation {
override val type: CirClassType = UnsafeNumberAnnotation.type
override val annotationValueArguments: Map<CirName, CirAnnotation> = emptyMap()
override val constantValueArguments: Map<CirName, CirConstantValue> = mapOf(
CirName.create("actualPlatformTypes") to CirConstantValue.ArrayValue(
actualPlatformTypes.toSortedMap().map { (platform, type) ->
CirConstantValue.StringValue("$platform: ${type.toQualifiedNameString()}")
CirConstantValue.StringValue("$platform: $type")
}
)
)
@@ -130,7 +130,7 @@ internal fun buildTypeAliasNode(
storageManager = storageManager,
size = size,
nodeRelationship = null,
commonizerProducer = { TypeAliasCommonizer(TypeCommonizer(classifiers, settings), classifiers, settings = settings).asCommonizer() },
commonizerProducer = { TypeAliasCommonizer(classifiers, settings, TypeCommonizer(classifiers, settings)).asCommonizer() },
recursionMarker = CirTypeAliasRecursionMarker,
nodeProducer = { targetDeclarations, commonDeclaration ->
CirTypeAliasNode(typeAliasId, targetDeclarations, commonDeclaration).also {
@@ -575,6 +575,7 @@ class HierarchicalClassAndTypeAliasCommonizationTest : AbstractInlineSourcesComm
typealias Proxy = Short
@UnsafeNumber(["c: kotlin.Int", "d: kotlin.Short"])
typealias X = Proxy
@UnsafeNumber(["c: kotlin.Int", "d: kotlin.Short"])
expect val x: X
""".trimIndent()
)
@@ -585,6 +586,7 @@ class HierarchicalClassAndTypeAliasCommonizationTest : AbstractInlineSourcesComm
typealias Proxy = Short
@UnsafeNumber(["a: kotlin.Long", "b: kotlin.Long", "c: kotlin.Int", "d: kotlin.Short"])
typealias X = Proxy
@UnsafeNumber(["a: kotlin.Long", "b: kotlin.Long", "c: kotlin.Int", "d: kotlin.Short"])
expect val x: X
""".trimIndent()
)
@@ -595,7 +595,7 @@ class HierarchicalOptimisticNumbersTypeCommonizerTest : AbstractInlineSourcesCom
result.assertCommonized(
"(a, b)", """
@UnsafeNumber(["a: kotlinx.cinterop.UIntVarOf", "b: kotlinx.cinterop.ULongVarOf"])
@UnsafeNumber(["a: kotlinx.cinterop.UIntVarOf<kotlin.UInt>", "b: kotlinx.cinterop.ULongVarOf<kotlin.ULong>"])
typealias X = kotlinx.cinterop.UIntVarOf<UInt>
""".trimIndent()
)
@@ -612,7 +612,7 @@ class HierarchicalOptimisticNumbersTypeCommonizerTest : AbstractInlineSourcesCom
result.assertCommonized(
"(a, b)", """
@UnsafeNumber(["a: kotlinx.cinterop.IntVarOf", "b: kotlinx.cinterop.LongVarOf"])
@UnsafeNumber(["a: kotlinx.cinterop.IntVarOf<kotlin.Int>", "b: kotlinx.cinterop.LongVarOf<kotlin.Long>"])
typealias X = kotlinx.cinterop.IntVarOf<Int>
""".trimIndent()
)
@@ -744,6 +744,7 @@ class HierarchicalOptimisticNumbersTypeCommonizerTest : AbstractInlineSourcesCom
"(a, b)", """
@UnsafeNumber(["a: kotlin.UShort", "b: kotlin.ULong"])
typealias X = UShort
@UnsafeNumber(["a: kotlin.UShort", "b: kotlin.ULong"])
expect val x: X
""".trimIndent()
)
@@ -867,4 +868,76 @@ class HierarchicalOptimisticNumbersTypeCommonizerTest : AbstractInlineSourcesCom
""".trimIndent()
)
}
fun `test optimistic commonization inside parameterized types`() {
val result = commonize {
outputTarget("(a, b)", "(c, d)", "(a, b, c, d)")
setting(OptimisticNumberCommonizationEnabledKey, true)
registerFakeStdlibIntegersDependency("(a, b)", "(c, d)", "(a, b, c, d)")
"a" withSource """
typealias TA = Int
class Box<T>
fun x(): Box<TA> = Box<TA>()
fun y(a: TA) {}
""".trimIndent()
"b" withSource """
typealias TA = Long
class Box<T>
fun x(): Box<TA> = Box<TA>()
fun y(a: TA) {}
""".trimIndent()
"c" withSource """
class Box<T>
fun x(): Box<Int> = Box<Int>()
fun y(a: Int) {}
""".trimIndent()
"d" withSource """
class Box<T>
fun x(): Box<Long> = Box<Long>()
fun y(a: Long) {}
""".trimIndent()
}
result.assertCommonized(
"(a, b)", """
import kotlinx.cinterop.*
expect class Box<T>()
@UnsafeNumber(["a: kotlin.Int", "b: kotlin.Long"])
typealias TA = Int
@UnsafeNumber(["a: Box<kotlin.Int>", "b: Box<kotlin.Long>"])
expect fun x(): Box<TA>
expect fun y(a: TA)
""".trimIndent()
)
result.assertCommonized(
"(c, d)", """
import kotlinx.cinterop.*
expect class Box<T>()
@UnsafeNumber(["c: Box<kotlin.Int>", "d: Box<kotlin.Long>"])
expect fun x(): Box<Int>
""".trimIndent()
)
result.assertCommonized(
"(a, b, c, d)", """
import kotlinx.cinterop.*
expect class Box<T>()
@UnsafeNumber(["a: Box<kotlin.Int>", "b: Box<kotlin.Long>", "c: Box<kotlin.Int>", "d: Box<kotlin.Long>"])
expect fun x(): Box<Int>
""".trimIndent()
)
}
}
@@ -60,7 +60,6 @@ class HierarchicalPlatformIntegerCommonizationTest : AbstractInlineSourcesCommon
"(${LINUX_ARM64.name}, ${LINUX_ARM32_HFP.name})", """
@UnsafeNumber(["${LINUX_ARM32_HFP.name}: kotlin.Long", "${LINUX_ARM64.name}: kotlin.Int"])
typealias X = Int
@UnsafeNumber(["${LINUX_ARM32_HFP.name}: kotlin.Int", "${LINUX_ARM64.name}: kotlin.Long"])
typealias Y = PlatformInt
""".trimIndent()
)
@@ -87,7 +86,6 @@ class HierarchicalPlatformIntegerCommonizationTest : AbstractInlineSourcesCommon
"(${LINUX_ARM64.name}, ${LINUX_ARM32_HFP.name})", """
@UnsafeNumber(["${LINUX_ARM32_HFP.name}: kotlin.ULong", "${LINUX_ARM64.name}: kotlin.UInt"])
typealias X = UInt
@UnsafeNumber(["${LINUX_ARM32_HFP.name}: kotlin.UInt", "${LINUX_ARM64.name}: kotlin.ULong"])
typealias Y = PlatformUInt
""".trimIndent()
)
@@ -124,11 +122,9 @@ class HierarchicalPlatformIntegerCommonizationTest : AbstractInlineSourcesCommon
@UnsafeNumber(["${LINUX_ARM32_HFP.name}: kotlin.Long", "${LINUX_ARM64.name}: kotlin.Int"])
typealias AX = Int
@UnsafeNumber(["${LINUX_ARM32_HFP.name}: kotlin.Int", "${LINUX_ARM64.name}: kotlin.Long"])
typealias AY = PlatformInt
@UnsafeNumber(["${LINUX_ARM32_HFP.name}: kotlinx.cinterop.LongVarOf", "${LINUX_ARM64.name}: kotlinx.cinterop.IntVarOf"])
@UnsafeNumber(["${LINUX_ARM32_HFP.name}: kotlinx.cinterop.LongVarOf<kotlin.Long>", "${LINUX_ARM64.name}: kotlinx.cinterop.IntVarOf<kotlin.Int>"])
typealias X = IntVarOf<AX>
@UnsafeNumber(["${LINUX_ARM32_HFP.name}: kotlinx.cinterop.IntVarOf", "${LINUX_ARM64.name}: kotlinx.cinterop.LongVarOf"])
typealias Y = PlatformIntVarOf<AY>
""".trimIndent()
)
@@ -165,11 +161,9 @@ class HierarchicalPlatformIntegerCommonizationTest : AbstractInlineSourcesCommon
@UnsafeNumber(["${LINUX_ARM32_HFP.name}: kotlin.ULong", "${LINUX_ARM64.name}: kotlin.UInt"])
typealias AX = UInt
@UnsafeNumber(["${LINUX_ARM32_HFP.name}: kotlin.UInt", "${LINUX_ARM64.name}: kotlin.ULong"])
typealias AY = PlatformUInt
@UnsafeNumber(["${LINUX_ARM32_HFP.name}: kotlinx.cinterop.ULongVarOf", "${LINUX_ARM64.name}: kotlinx.cinterop.UIntVarOf"])
@UnsafeNumber(["${LINUX_ARM32_HFP.name}: kotlinx.cinterop.ULongVarOf<kotlin.ULong>", "${LINUX_ARM64.name}: kotlinx.cinterop.UIntVarOf<kotlin.UInt>"])
typealias X = UIntVarOf<AX>
@UnsafeNumber(["${LINUX_ARM32_HFP.name}: kotlinx.cinterop.UIntVarOf", "${LINUX_ARM64.name}: kotlinx.cinterop.ULongVarOf"])
typealias Y = PlatformUIntVarOf<AY>
""".trimIndent()
)
@@ -386,9 +380,7 @@ class HierarchicalPlatformIntegerCommonizationTest : AbstractInlineSourcesCommon
import kotlinx.cinterop.*
expect class C() {
@UnsafeNumber(["${LINUX_ARM32_HFP.name}: kotlin.Int", "${LINUX_ARM64.name}: kotlin.Long"])
val i: PlatformInt
@UnsafeNumber(["${LINUX_ARM32_HFP.name}: kotlinx.cinterop.IntVarOf", "${LINUX_ARM64.name}: kotlinx.cinterop.LongVarOf"])
fun v(): PlatformIntVarOf<PlatformInt>
fun r(): PlatformIntRange
}
@@ -549,9 +541,7 @@ class HierarchicalPlatformIntegerCommonizationTest : AbstractInlineSourcesCommon
"($intTarget3, $longTarget3)", """
import kotlinx.cinterop.*
@UnsafeNumber(["${LINUX_MIPSEL32.name}: kotlin.Int", "${MACOS_X64.name}: kotlin.Long"])
typealias X = PlatformInt
@UnsafeNumber(["${LINUX_MIPSEL32.name}: kotlinx.cinterop.IntVarOf", "${MACOS_X64.name}: kotlinx.cinterop.LongVarOf"])
typealias XV = PlatformIntVarOf<X>
""".trimIndent()
)
@@ -560,15 +550,7 @@ class HierarchicalPlatformIntegerCommonizationTest : AbstractInlineSourcesCommon
"($intTarget1, $intTarget2, $longTarget1, $longTarget2)", """
import kotlinx.cinterop.*
@UnsafeNumber([
"${LINUX_ARM32_HFP.name}: kotlin.Int", "${LINUX_ARM64.name}: kotlin.Long",
"${LINUX_MIPS32.name}: kotlin.Int", "${LINUX_X64.name}: kotlin.Long"
])
typealias X = PlatformInt
@UnsafeNumber([
"${LINUX_ARM32_HFP.name}: kotlinx.cinterop.IntVarOf", "${LINUX_ARM64.name}: kotlinx.cinterop.LongVarOf",
"${LINUX_MIPS32.name}: kotlinx.cinterop.IntVarOf", "${LINUX_X64.name}: kotlinx.cinterop.LongVarOf"
])
typealias XV = PlatformIntVarOf<X>
""".trimIndent()
)
@@ -577,15 +559,7 @@ class HierarchicalPlatformIntegerCommonizationTest : AbstractInlineSourcesCommon
"($intTarget1, $intTarget2, $intTarget3, $longTarget1)", """
import kotlinx.cinterop.*
@UnsafeNumber([
"${LINUX_ARM32_HFP.name}: kotlin.Int", "${LINUX_MIPS32.name}: kotlin.Int",
"${LINUX_MIPSEL32.name}: kotlin.Int", "${LINUX_X64.name}: kotlin.Long"
])
typealias X = PlatformInt
@UnsafeNumber([
"${LINUX_ARM32_HFP.name}: kotlinx.cinterop.IntVarOf", "${LINUX_MIPS32.name}: kotlinx.cinterop.IntVarOf",
"${LINUX_MIPSEL32.name}: kotlinx.cinterop.IntVarOf", "${LINUX_X64.name}: kotlinx.cinterop.LongVarOf"
])
typealias XV = PlatformIntVarOf<X>
""".trimIndent()
)
@@ -594,15 +568,7 @@ class HierarchicalPlatformIntegerCommonizationTest : AbstractInlineSourcesCommon
"($longTarget1, $longTarget2, $longTarget3, $intTarget1)", """
import kotlinx.cinterop.*
@UnsafeNumber([
"${LINUX_ARM32_HFP.name}: kotlin.Int", "${LINUX_ARM64.name}: kotlin.Long",
"${LINUX_X64.name}: kotlin.Long", "${MACOS_X64.name}: kotlin.Long"
])
typealias X = PlatformInt
@UnsafeNumber([
"${LINUX_ARM32_HFP.name}: kotlinx.cinterop.IntVarOf", "${LINUX_ARM64.name}: kotlinx.cinterop.LongVarOf",
"${LINUX_X64.name}: kotlinx.cinterop.LongVarOf", "${MACOS_X64.name}: kotlinx.cinterop.LongVarOf"
])
typealias XV = PlatformIntVarOf<X>
""".trimIndent()
)
@@ -706,7 +672,6 @@ class HierarchicalPlatformIntegerCommonizationTest : AbstractInlineSourcesCommon
result.assertCommonized(
"(${IOS_ARM32.name}, ${IOS_ARM64.name})", """
@UnsafeNumber(["${IOS_ARM32.name}: kotlin.UInt", "${IOS_ARM64.name}: kotlin.ULong"])
typealias OtherAlias = PlatformUInt
expect class Box<T>()
@@ -0,0 +1,211 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.commonizer.hierarchical
import org.jetbrains.kotlin.commonizer.cir.*
import org.jetbrains.kotlin.commonizer.core.renderTypeForUnsafeNumberAnnotation
import org.jetbrains.kotlin.types.Variance
import org.junit.Test
import kotlin.test.assertEquals
class UnsafeNumberAnnotationTypeRenderingTest {
@Test
fun `test simple class type with no arguments`() {
val type = CirClassType.createInterned(
classId = CirEntityId.create("kotlin/String"), outerType = null, arguments = emptyList(), isMarkedNullable = false,
)
assertEquals("kotlin.String", renderTypeForUnsafeNumberAnnotation(type))
}
@Test
fun `test simple nullable class type`() {
val type = CirClassType.createInterned(
classId = CirEntityId.create("kotlin/String"), outerType = null, arguments = emptyList(), isMarkedNullable = true,
)
assertEquals("kotlin.String?", renderTypeForUnsafeNumberAnnotation(type))
}
@Test
fun `test expanded type alias type with no arguments`() {
val type = CirTypeAliasType.createInterned(
typeAliasId = CirEntityId.create("T"),
underlyingType = CirClassType.createInterned(
classId = CirEntityId.create("kotlin/String"), outerType = null, arguments = emptyList(), isMarkedNullable = false,
),
arguments = emptyList(),
isMarkedNullable = false,
)
assertEquals("kotlin.String", renderTypeForUnsafeNumberAnnotation(type))
}
@Test
fun `test class type with arguments`() {
val type = CirClassType.createInterned(
classId = CirEntityId.create("kotlin/Triple"), outerType = null, isMarkedNullable = false,
arguments = listOf(
CirRegularTypeProjection(
projectionKind = Variance.INVARIANT, type = CirClassType.createInterned(
classId = CirEntityId.create("kotlin/String"), outerType = null, arguments = emptyList(), isMarkedNullable = false,
)
),
CirRegularTypeProjection(
projectionKind = Variance.OUT_VARIANCE, type = CirClassType.createInterned(
classId = CirEntityId.create("kotlin/Number"), outerType = null, arguments = emptyList(), isMarkedNullable = false,
)
),
CirStarTypeProjection,
),
)
assertEquals("kotlin.Triple<kotlin.String, out kotlin.Number, *>", renderTypeForUnsafeNumberAnnotation(type))
}
@Test
fun `test type alias type with an argument`() {
val type = CirTypeAliasType.createInterned(
typeAliasId = CirEntityId.create("T"), isMarkedNullable = false, arguments = emptyList(),
underlyingType = CirClassType.createInterned(
classId = CirEntityId.create("kotlin/Triple"), outerType = null, isMarkedNullable = false,
arguments = listOf(
CirRegularTypeProjection(
projectionKind = Variance.INVARIANT, type = CirClassType.createInterned(
classId = CirEntityId.create("kotlin/String"),
outerType = null,
arguments = emptyList(),
isMarkedNullable = false,
)
),
CirRegularTypeProjection(
projectionKind = Variance.OUT_VARIANCE, type = CirClassType.createInterned(
classId = CirEntityId.create("kotlin/Number"),
outerType = null,
arguments = emptyList(),
isMarkedNullable = false,
)
),
CirStarTypeProjection,
),
),
)
assertEquals("kotlin.Triple<kotlin.String, out kotlin.Number, *>", renderTypeForUnsafeNumberAnnotation(type))
}
@Test
fun `test flexible type`() {
val type = CirFlexibleType(
lowerBound = CirClassType.createInterned(
classId = CirEntityId.create("kotlin/String"), outerType = null, arguments = emptyList(), isMarkedNullable = false,
),
upperBound = CirClassType.createInterned(
classId = CirEntityId.create("kotlin/String"), outerType = null, arguments = emptyList(), isMarkedNullable = true,
)
)
assertEquals("kotlin.String..kotlin.String?", renderTypeForUnsafeNumberAnnotation(type))
}
@Test
fun `test flexible type argument`() {
val type = CirClassType.createInterned(
classId = CirEntityId.create("kotlin.Array"), outerType = null, isMarkedNullable = false, arguments = listOf(
CirRegularTypeProjection(
projectionKind = Variance.OUT_VARIANCE,
type = CirFlexibleType(
lowerBound = CirClassType.createInterned(
classId = CirEntityId.create("kotlin/String"),
outerType = null,
arguments = emptyList(),
isMarkedNullable = false,
),
upperBound = CirClassType.createInterned(
classId = CirEntityId.create("kotlin/String"),
outerType = null,
arguments = emptyList(),
isMarkedNullable = true,
)
)
)
)
)
assertEquals("kotlin.Array<out kotlin.String..kotlin.String?>", renderTypeForUnsafeNumberAnnotation(type))
}
@Test
fun `test nested type argument`() {
val type = CirClassType.createInterned(
classId = CirEntityId.create("kotlin.Array"), outerType = null, isMarkedNullable = false, arguments = listOf(
CirRegularTypeProjection(
projectionKind = Variance.OUT_VARIANCE,
type = CirClassType.createInterned(
classId = CirEntityId.create("kotlin.Array"), outerType = null, isMarkedNullable = false, arguments = listOf(
CirRegularTypeProjection(
projectionKind = Variance.IN_VARIANCE,
type = CirClassType.createInterned(
classId = CirEntityId.create("kotlin/String"),
outerType = null,
arguments = emptyList(),
isMarkedNullable = false,
)
)
)
)
)
)
)
assertEquals("kotlin.Array<out kotlin.Array<in kotlin.String>>", renderTypeForUnsafeNumberAnnotation(type))
}
@Test
fun `test type parameter type in type argument`() {
val type = CirClassType.createInterned(
classId = CirEntityId.create("kotlin.Array"), outerType = null, isMarkedNullable = false, arguments = listOf(
CirRegularTypeProjection(
projectionKind = Variance.INVARIANT,
type = CirTypeParameterType.createInterned(index = 0, isMarkedNullable = true)
)
)
)
assertEquals("kotlin.Array<#0?>", renderTypeForUnsafeNumberAnnotation(type))
}
@Test
fun `test combined type`() {
val type = CirClassType.createInterned(
classId = CirEntityId.create("kotlin.Array"), outerType = null, isMarkedNullable = false, arguments = listOf(
CirRegularTypeProjection(
projectionKind = Variance.OUT_VARIANCE,
type = CirClassType.createInterned(
classId = CirEntityId.create("kotlin/Pair"), outerType = null, isMarkedNullable = true,
arguments = listOf(
CirStarTypeProjection,
CirRegularTypeProjection(
projectionKind = Variance.IN_VARIANCE, type = CirFlexibleType(
lowerBound = CirClassType.createInterned(
classId = CirEntityId.create("kotlin/String"),
outerType = null,
arguments = emptyList(),
isMarkedNullable = false,
),
upperBound = CirClassType.createInterned(
classId = CirEntityId.create("kotlin/String"),
outerType = null,
arguments = emptyList(),
isMarkedNullable = true,
)
)
),
),
)
)
)
)
assertEquals(
"kotlin.Array<out kotlin.Pair<*, in kotlin.String..kotlin.String?>?>",
renderTypeForUnsafeNumberAnnotation(type)
)
}
}