[MPP] Improve creation of @UnsafeNumber w.r.t. non-aliased types and PIC
^KT-51643
This commit is contained in:
committed by
teamcity
parent
e09f30f442
commit
621f14c5bb
@@ -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
|
||||
|
||||
+9
-17
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+46
@@ -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)
|
||||
}
|
||||
+9
-15
@@ -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),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+42
-29
@@ -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 {
|
||||
|
||||
+2
@@ -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()
|
||||
)
|
||||
|
||||
+75
-2
@@ -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()
|
||||
)
|
||||
}
|
||||
}
|
||||
+2
-37
@@ -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>()
|
||||
|
||||
+211
@@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user