[Commonizer] Implement optimistic number commonization for typealias
When typealias point to a number of different bit width on certain platforms, this implementation will choose the number type with higher bit width as commonization result for typealias types and typealias underlying types. This will effectively port the "analyse code for a single selected platform" UX approach into HMPP (for numbers only) ^KT-48455 Verification Pending
This commit is contained in:
committed by
Space
parent
fbfbb0c72c
commit
814a147a53
@@ -95,7 +95,10 @@ class CirEntityId private constructor(val packageName: CirPackageName, val relat
|
||||
else -> false
|
||||
}
|
||||
|
||||
override fun hashCode(): Int = hashCode(packageName).appendHashCode(relativeNameSegments)
|
||||
private var _hashCode: Int = 0
|
||||
|
||||
override fun hashCode(): Int = if (_hashCode != 0) _hashCode else
|
||||
hashCode(packageName).appendHashCode(relativeNameSegments).also { hashCode -> _hashCode = hashCode }
|
||||
|
||||
override fun toString(): String = buildString {
|
||||
packageName.segments.joinTo(this, "/")
|
||||
|
||||
+6
-3
@@ -11,12 +11,14 @@ import org.jetbrains.kotlin.commonizer.cir.CirTypeAliasType
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirKnownClassifiers
|
||||
|
||||
internal class ClassOrTypeAliasTypeCommonizer(
|
||||
private val classifiers: CirKnownClassifiers
|
||||
private val classifiers: CirKnownClassifiers,
|
||||
private val options: TypeCommonizer.Options
|
||||
) : AssociativeCommonizer<CirClassOrTypeAliasType> {
|
||||
|
||||
override fun commonize(first: CirClassOrTypeAliasType, second: CirClassOrTypeAliasType): CirClassOrTypeAliasType? {
|
||||
if (first is CirClassType && second is CirClassType) {
|
||||
return ClassTypeCommonizer(classifiers).commonize(listOf(first, second))
|
||||
?: if (options.allowOptimisticNumberTypeCommonization) OptimisticNumbersTypeCommonizer.commonize(first, second) else null
|
||||
}
|
||||
|
||||
if (first is CirTypeAliasType && second is CirTypeAliasType) {
|
||||
@@ -25,7 +27,8 @@ internal class ClassOrTypeAliasTypeCommonizer(
|
||||
try our luck with commonizing those class types
|
||||
*/
|
||||
return TypeAliasTypeCommonizer(classifiers).commonize(listOf(first, second))
|
||||
?: ClassTypeCommonizer(classifiers).commonize(listOf(first.expandedType(), second.expandedType()))
|
||||
?: ClassOrTypeAliasTypeCommonizer(classifiers, options.withAllowOptimisticNumberTypeCommonization())
|
||||
.commonize(first.expandedType(), second.expandedType())
|
||||
}
|
||||
|
||||
val classType = when {
|
||||
@@ -47,7 +50,7 @@ internal class ClassOrTypeAliasTypeCommonizer(
|
||||
val typeAliasClassType = TypeAliasTypeCommonizer(classifiers).commonize(listOf(typeAliasType))?.expandedType()
|
||||
?: typeAliasType.expandedType()
|
||||
|
||||
return ClassTypeCommonizer(classifiers).commonize(listOf(classType, typeAliasClassType))
|
||||
return commonize(classType, typeAliasClassType)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.CirClassType
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirEntityId
|
||||
|
||||
private typealias BitWidth = Int
|
||||
|
||||
private class SubstitutableNumbers(private val numbers: Map<CirEntityId, BitWidth>) {
|
||||
fun choose(first: CirClassType, second: CirClassType): CirClassType? {
|
||||
val firstBitWidth = numbers[first.classifierId] ?: return null
|
||||
val secondBitWidth = numbers[second.classifierId] ?: return null
|
||||
return if (secondBitWidth > firstBitWidth) second else first
|
||||
}
|
||||
}
|
||||
|
||||
private val signedIntegers = SubstitutableNumbers(
|
||||
mapOf(
|
||||
CirEntityId.create("kotlin/Byte") to 8,
|
||||
CirEntityId.create("kotlin/Short") to 16,
|
||||
CirEntityId.create("kotlin/Int") to 32,
|
||||
CirEntityId.create("kotlin/Long") to 64
|
||||
)
|
||||
)
|
||||
|
||||
private val unsignedIntegers = SubstitutableNumbers(
|
||||
mapOf(
|
||||
CirEntityId.create("kotlin/UByte") to 8,
|
||||
CirEntityId.create("kotlin/UShort") to 16,
|
||||
CirEntityId.create("kotlin/UInt") to 32,
|
||||
CirEntityId.create("kotlin/ULong") to 64
|
||||
)
|
||||
)
|
||||
|
||||
private val floatingPoints = SubstitutableNumbers(
|
||||
mapOf(
|
||||
CirEntityId.create("kotlin/Float") to 32,
|
||||
CirEntityId.create("kotlin/Double") to 64,
|
||||
)
|
||||
)
|
||||
|
||||
private val signedVarIntegers = SubstitutableNumbers(
|
||||
mapOf(
|
||||
CirEntityId.create("kotlinx/cinterop/ByteVarOf") to 8,
|
||||
CirEntityId.create("kotlinx/cinterop/ShortVarOf") to 16,
|
||||
CirEntityId.create("kotlinx/cinterop/IntVarOf") to 32,
|
||||
CirEntityId.create("kotlinx/cinterop/LongVarOf") to 64,
|
||||
)
|
||||
)
|
||||
|
||||
private val unsignedVarIntegers = SubstitutableNumbers(
|
||||
mapOf(
|
||||
CirEntityId.create("kotlinx/cinterop/UByteVarOf") to 8,
|
||||
CirEntityId.create("kotlinx/cinterop/UShortVarOf") to 16,
|
||||
CirEntityId.create("kotlinx/cinterop/UIntVarOf") to 32,
|
||||
CirEntityId.create("kotlinx/cinterop/ULongVarOf") to 64,
|
||||
)
|
||||
)
|
||||
|
||||
private val floatingPointVars = SubstitutableNumbers(
|
||||
mapOf(
|
||||
CirEntityId.create("kotlinx/cinterop/FloatVarOf") to 32,
|
||||
CirEntityId.create("kotlinx/cinterop/DoubleVarOf") to 64,
|
||||
)
|
||||
)
|
||||
|
||||
object OptimisticNumbersTypeCommonizer : AssociativeCommonizer<CirClassType> {
|
||||
override fun commonize(first: CirClassType, second: CirClassType): CirClassType? {
|
||||
return signedIntegers.choose(first, second)
|
||||
?: unsignedIntegers.choose(first, second)
|
||||
?: floatingPoints.choose(first, second)
|
||||
?: signedVarIntegers.choose(first, second)
|
||||
?: unsignedVarIntegers.choose(first, second)
|
||||
?: floatingPointVars.choose(first, second)
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,8 @@
|
||||
|
||||
package org.jetbrains.kotlin.commonizer.core
|
||||
|
||||
import org.jetbrains.kotlin.commonizer.cir.*
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirClassOrTypeAliasType
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirTypeAlias
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirKnownClassifiers
|
||||
|
||||
class TypeAliasCommonizer(
|
||||
@@ -18,7 +19,7 @@ class TypeAliasCommonizer(
|
||||
val typeParameters = TypeParameterListCommonizer(classifiers)
|
||||
.commonize(listOf(first.typeParameters, second.typeParameters)) ?: return null
|
||||
|
||||
val underlyingType = TypeCommonizer(classifiers)
|
||||
val underlyingType = TypeCommonizer(classifiers, TypeCommonizer.Options.default.withAllowOptimisticNumberTypeCommonization())
|
||||
.commonize(first.underlyingType, second.underlyingType) as? CirClassOrTypeAliasType ?: return null
|
||||
|
||||
val visibility = VisibilityCommonizer.lowering().commonize(listOf(first, second)) ?: return null
|
||||
@@ -32,4 +33,4 @@ class TypeAliasCommonizer(
|
||||
expandedType = underlyingType.expandedType()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,14 @@ package org.jetbrains.kotlin.commonizer.core
|
||||
import org.jetbrains.kotlin.commonizer.cir.*
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirKnownClassifiers
|
||||
|
||||
class TypeCommonizer(private val classifiers: CirKnownClassifiers) : AssociativeCommonizer<CirType> {
|
||||
|
||||
class TypeCommonizer(
|
||||
private val classifiers: CirKnownClassifiers,
|
||||
private val options: Options = Options.default
|
||||
) : AssociativeCommonizer<CirType> {
|
||||
override fun commonize(first: CirType, second: CirType): CirType? {
|
||||
if (first is CirClassOrTypeAliasType && second is CirClassOrTypeAliasType) {
|
||||
return ClassOrTypeAliasTypeCommonizer(classifiers).commonize(first, second)
|
||||
return ClassOrTypeAliasTypeCommonizer(classifiers, options).commonize(first, second)
|
||||
}
|
||||
|
||||
if (first is CirTypeParameterType && second is CirTypeParameterType) {
|
||||
@@ -19,11 +23,25 @@ class TypeCommonizer(private val classifiers: CirKnownClassifiers) : Associative
|
||||
}
|
||||
|
||||
if (first is CirFlexibleType && second is CirFlexibleType) {
|
||||
return FlexibleTypeAssociativeCommonizer(classifiers).commonize(first, second)
|
||||
return FlexibleTypeAssociativeCommonizer(classifiers, options).commonize(first, second)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
data class Options(
|
||||
val allowOptimisticNumberTypeCommonization: Boolean = false
|
||||
) {
|
||||
|
||||
fun withAllowOptimisticNumberTypeCommonization(): Options {
|
||||
return if (allowOptimisticNumberTypeCommonization) this
|
||||
else copy(allowOptimisticNumberTypeCommonization = true)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val default = Options()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private object TypeParameterTypeCommonizer : AssociativeCommonizer<CirTypeParameterType> {
|
||||
@@ -35,11 +53,14 @@ private object TypeParameterTypeCommonizer : AssociativeCommonizer<CirTypeParame
|
||||
}
|
||||
}
|
||||
|
||||
private class FlexibleTypeAssociativeCommonizer(private val classifiers: CirKnownClassifiers) : AssociativeCommonizer<CirFlexibleType> {
|
||||
private class FlexibleTypeAssociativeCommonizer(
|
||||
private val classifiers: CirKnownClassifiers,
|
||||
private val options: TypeCommonizer.Options
|
||||
) : AssociativeCommonizer<CirFlexibleType> {
|
||||
override fun commonize(first: CirFlexibleType, second: CirFlexibleType): CirFlexibleType? {
|
||||
|
||||
val lowerBound = TypeCommonizer(classifiers).commonize(first.lowerBound, second.lowerBound) ?: return null
|
||||
val upperBound = TypeCommonizer(classifiers).commonize(first.upperBound, second.upperBound) ?: return null
|
||||
val lowerBound = TypeCommonizer(classifiers, options).commonize(first.lowerBound, second.lowerBound) ?: return null
|
||||
val upperBound = TypeCommonizer(classifiers, options).commonize(first.upperBound, second.upperBound) ?: return null
|
||||
|
||||
return CirFlexibleType(
|
||||
lowerBound = lowerBound as CirSimpleType,
|
||||
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.AbstractInlineSourcesCommonizationTest
|
||||
import org.jetbrains.kotlin.commonizer.assertCommonized
|
||||
import org.jetbrains.kotlin.commonizer.utils.InlineSourceBuilder
|
||||
|
||||
class AliasedNumberTypeCommonizationTest : AbstractInlineSourcesCommonizationTest() {
|
||||
|
||||
fun `test Int and Long - typealias`() {
|
||||
val result = commonize {
|
||||
outputTarget("(a, b)")
|
||||
simpleSingleSourceTarget("a", "typealias X = Int")
|
||||
simpleSingleSourceTarget("b", "typealias X = Long")
|
||||
}
|
||||
|
||||
result.assertCommonized("(a, b)", "typealias X = Long")
|
||||
}
|
||||
|
||||
fun `test UInt and ULong - typealias`() {
|
||||
val result = commonize {
|
||||
outputTarget("(a, b)")
|
||||
registerDependency("a", "b", "(a, b)") { unsignedIntegers() }
|
||||
simpleSingleSourceTarget("a", "typealias X = UInt")
|
||||
simpleSingleSourceTarget("b", "typealias X = ULong")
|
||||
}
|
||||
|
||||
result.assertCommonized("(a, b)", "typealias X = ULong")
|
||||
}
|
||||
|
||||
|
||||
fun `test int and long - chain - typealias`() {
|
||||
val result = commonize {
|
||||
outputTarget("(a, b)")
|
||||
|
||||
simpleSingleSourceTarget(
|
||||
"a", """
|
||||
typealias A = Int
|
||||
typealias B = A
|
||||
typealias C = B
|
||||
typealias X = C
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
simpleSingleSourceTarget(
|
||||
"b", """
|
||||
typealias A = Long
|
||||
typealias B = A
|
||||
typealias X = B
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
result.assertCommonized(
|
||||
"(a, b)", """
|
||||
typealias A = Long
|
||||
typealias B = A
|
||||
typealias X = Long
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
fun `test function with pure number types parameter`() {
|
||||
val result = commonize {
|
||||
outputTarget("(a, b)")
|
||||
simpleSingleSourceTarget("a", "fun x(p: Int)")
|
||||
simpleSingleSourceTarget("b", "fun x(p: Long)")
|
||||
}
|
||||
|
||||
/*
|
||||
Only functions that use a TA in their signature are supposed to be
|
||||
commonized using our number's commonization hack.
|
||||
|
||||
This is a hard requirement. It would also be reasonable if we would add
|
||||
support for this case, since there would be reasonable code that people
|
||||
could write with this!
|
||||
*/
|
||||
result.assertCommonized("(a, b)", "")
|
||||
}
|
||||
|
||||
fun `test function with aliased number value parameter`() {
|
||||
val result = commonize {
|
||||
outputTarget("(a, b)")
|
||||
simpleSingleSourceTarget(
|
||||
"a", """
|
||||
typealias A = Int
|
||||
typealias X = A
|
||||
fun x(p: X)
|
||||
""".trimIndent()
|
||||
)
|
||||
simpleSingleSourceTarget(
|
||||
"b", """
|
||||
typealias B = Long
|
||||
typealias X = B
|
||||
fun x(p: X)
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
result.assertCommonized(
|
||||
"(a, b)", """
|
||||
typealias X = Long
|
||||
expect fun x(p: X)
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
fun `test property with pure number return type`() {
|
||||
val result = commonize {
|
||||
outputTarget("(a, b)")
|
||||
registerDependency("a", "b", "(a, b)") { unsignedIntegers() }
|
||||
simpleSingleSourceTarget("a", "val x: UInt")
|
||||
simpleSingleSourceTarget("b", "val x: ULong")
|
||||
}
|
||||
|
||||
/*
|
||||
Only commonize return types that were specified using a type-alias.
|
||||
As with function value parameters, this is not a hard requirement.
|
||||
It would also be reasonable to support this case.
|
||||
*/
|
||||
result.assertCommonized("(a, b)", "")
|
||||
}
|
||||
|
||||
fun `test property with aliased number return type`() {
|
||||
val result = commonize {
|
||||
outputTarget("(a, b)")
|
||||
registerDependency("a", "b", "(a, b)") { unsignedIntegers() }
|
||||
simpleSingleSourceTarget(
|
||||
"a", """
|
||||
typealias X = UShort
|
||||
val x: X = TODO()
|
||||
""".trimIndent()
|
||||
)
|
||||
simpleSingleSourceTarget(
|
||||
"b", """
|
||||
typealias X = ULong
|
||||
val x: X = TODO()
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
result.assertCommonized(
|
||||
"(a, b)", """
|
||||
typealias X = ULong
|
||||
expect val x: X
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun InlineSourceBuilder.ModuleBuilder.unsignedIntegers() {
|
||||
source(
|
||||
"""
|
||||
package kotlin
|
||||
class UByte
|
||||
class UShort
|
||||
class UInt
|
||||
class ULong
|
||||
""".trimIndent(), "unsigned.kt"
|
||||
)
|
||||
}
|
||||
+14
-5
@@ -33,13 +33,22 @@ class HierarchicalClassAndTypeAliasCommonizationTest : AbstractInlineSourcesComm
|
||||
fun `test commonization of typeAlias and class hierarchically`() {
|
||||
val result = commonize {
|
||||
outputTarget("(a, b)", "(c, d)", "(a, b, c, d)")
|
||||
simpleSingleSourceTarget("a", "typealias X = Int")
|
||||
simpleSingleSourceTarget("b", "typealias X = Long")
|
||||
registerDependency("a", "b", "c", "d", "(a, b)", "(c, d)", "(a, b, c, d)") {
|
||||
source(
|
||||
"""
|
||||
interface A
|
||||
interface B: A
|
||||
interface C: A
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
simpleSingleSourceTarget("a", "typealias X = B")
|
||||
simpleSingleSourceTarget("b", "typealias X = C")
|
||||
simpleSingleSourceTarget("c", "class X")
|
||||
simpleSingleSourceTarget("d", "typealias X = Short")
|
||||
}
|
||||
|
||||
result.assertCommonized("(a, b)", "expect class X: Number")
|
||||
result.assertCommonized("(a, b)", "expect class X: A")
|
||||
result.assertCommonized("(c, d)", "expect class X")
|
||||
result.assertCommonized("((a, b), (c, d))", "expect class X")
|
||||
}
|
||||
@@ -558,7 +567,7 @@ class HierarchicalClassAndTypeAliasCommonizationTest : AbstractInlineSourcesComm
|
||||
|
||||
result.assertCommonized(
|
||||
"(c, d)", """
|
||||
expect class Proxy: Number
|
||||
typealias Proxy = Int
|
||||
typealias X = Proxy
|
||||
expect val x: X
|
||||
""".trimIndent()
|
||||
@@ -566,7 +575,7 @@ class HierarchicalClassAndTypeAliasCommonizationTest : AbstractInlineSourcesComm
|
||||
|
||||
result.assertCommonized(
|
||||
"(a, b, c, d)", """
|
||||
expect class Proxy: Number
|
||||
typealias Proxy = Long
|
||||
typealias X = Proxy
|
||||
expect val x: X
|
||||
""".trimIndent()
|
||||
|
||||
Reference in New Issue
Block a user