[Commonizer] Implement CirAliasTypeSubstitutor
This will substitute non-commonizable classifiers with known type-aliases (which might be commonizable). A simple example depending on this substitution comes from posix: Most function and properties use the `FILE` typealias which is available across all platforms. Some linux platforms use `__IO_FILE` in their signature, which is just linux specific. This type substitution will figure out, that this type can be substituted with `FILE`. ^KT-47433 Verification Pending
This commit is contained in:
committed by
Space
parent
906346b7d9
commit
7c450f9884
@@ -127,6 +127,22 @@ abstract class CirClassType : CirClassOrTypeAliasType(), CirHasVisibility {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun CirClassType.copyInterned(
|
||||||
|
classifierId: CirEntityId = this.classifierId,
|
||||||
|
outerType: CirClassType? = this.outerType,
|
||||||
|
visibility: Visibility = this.visibility,
|
||||||
|
arguments: List<CirTypeProjection> = this.arguments,
|
||||||
|
isMarkedNullable: Boolean = this.isMarkedNullable
|
||||||
|
): CirClassType {
|
||||||
|
return createInterned(
|
||||||
|
classId = classifierId,
|
||||||
|
outerType = outerType,
|
||||||
|
visibility = visibility,
|
||||||
|
arguments = arguments,
|
||||||
|
isMarkedNullable = isMarkedNullable
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private val interner = Interner<CirClassTypeInternedImpl>()
|
private val interner = Interner<CirClassTypeInternedImpl>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -170,6 +186,20 @@ abstract class CirTypeAliasType : CirClassOrTypeAliasType() {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun CirTypeAliasType.copyInterned(
|
||||||
|
classifierId: CirEntityId = this.classifierId,
|
||||||
|
underlyingType: CirClassOrTypeAliasType = this.underlyingType,
|
||||||
|
arguments: List<CirTypeProjection> = this.arguments,
|
||||||
|
isMarkedNullable: Boolean = this.isMarkedNullable
|
||||||
|
): CirTypeAliasType {
|
||||||
|
return createInterned(
|
||||||
|
typeAliasId = classifierId,
|
||||||
|
underlyingType = underlyingType,
|
||||||
|
arguments = arguments,
|
||||||
|
isMarkedNullable = isMarkedNullable
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private val interner = Interner<CirTypeAliasTypeInternedImpl>()
|
private val interner = Interner<CirTypeAliasTypeInternedImpl>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+100
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* 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.mergedtree
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.commonizer.cir.*
|
||||||
|
import org.jetbrains.kotlin.commonizer.cir.CirClassType.Companion.copyInterned
|
||||||
|
import org.jetbrains.kotlin.commonizer.cir.CirTypeAliasType.Companion.copyInterned
|
||||||
|
|
||||||
|
internal class CirAliasTypeSubstitutor(
|
||||||
|
private val commonDependencies: CirProvidedClassifiers,
|
||||||
|
private val classifierIndices: List<CirClassifierIndex>
|
||||||
|
) : CirTypeSubstitutor {
|
||||||
|
|
||||||
|
override fun substitute(targetIndex: Int, type: CirType): CirType {
|
||||||
|
return when (type) {
|
||||||
|
is CirFlexibleType -> type
|
||||||
|
is CirTypeParameterType -> type
|
||||||
|
is CirClassOrTypeAliasType -> substituteClassOrTypeAliasType(targetIndex, type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun substituteTypeProjection(targetIndex: Int, projection: CirTypeProjection): CirTypeProjection {
|
||||||
|
return when (projection) {
|
||||||
|
is CirRegularTypeProjection -> {
|
||||||
|
val newType = substitute(targetIndex, projection.type)
|
||||||
|
if (newType != projection.type) projection.copy(type = newType) else projection
|
||||||
|
}
|
||||||
|
is CirStarTypeProjection -> projection
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun substituteClassOrTypeAliasType(targetIndex: Int, type: CirClassOrTypeAliasType): CirClassOrTypeAliasType {
|
||||||
|
|
||||||
|
/*
|
||||||
|
Classifier id is available in all platforms or is provided by common dependencies.
|
||||||
|
The classifier itself does not require substitution, but type arguments potentially do!
|
||||||
|
*/
|
||||||
|
if (isCommon(type.classifierId)) {
|
||||||
|
val newArguments = type.arguments.map { argument -> substituteTypeProjection(targetIndex, argument) }
|
||||||
|
return if (newArguments != type.arguments) when (type) {
|
||||||
|
is CirTypeAliasType -> type.copyInterned(arguments = newArguments)
|
||||||
|
is CirClassType -> type.copyInterned(arguments = newArguments)
|
||||||
|
} else type
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Yet, we do not have any evidence that it is worth trying to substitute types with arguments when the type itself is
|
||||||
|
* not common at all. This substitutor could try to substitute the type & it's arguments.
|
||||||
|
*
|
||||||
|
* Without any evidence of libraries that would benefit from this higher effort, we will just skip this case.
|
||||||
|
*/
|
||||||
|
if (type.arguments.isNotEmpty()) {
|
||||||
|
return type
|
||||||
|
}
|
||||||
|
|
||||||
|
return when (type) {
|
||||||
|
is CirClassType -> substituteClassType(targetIndex, type)
|
||||||
|
is CirTypeAliasType -> substituteClassType(targetIndex, type.unabbreviate())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to find a suitable type alias pointing to the given class [type] which is available in 'common'
|
||||||
|
* This function does *not* support types with arguments!
|
||||||
|
*/
|
||||||
|
private fun substituteClassType(targetIndex: Int, type: CirClassType): CirClassOrTypeAliasType {
|
||||||
|
if (type.arguments.isNotEmpty()) return type
|
||||||
|
if (type.outerType != null) return type
|
||||||
|
val classifierIndex = classifierIndices[targetIndex]
|
||||||
|
|
||||||
|
var typeAliases = classifierIndex.findTypeAliasesWithUnderlyingType(type.classifierId)
|
||||||
|
|
||||||
|
while (typeAliases.isNotEmpty()) {
|
||||||
|
val commonTypeAlias = typeAliases.firstOrNull { (id, typeAlias) -> typeAlias.typeParameters.isEmpty() && isCommon(id) }
|
||||||
|
|
||||||
|
if (commonTypeAlias != null) {
|
||||||
|
return CirTypeAliasType.createInterned(
|
||||||
|
typeAliasId = commonTypeAlias.id,
|
||||||
|
underlyingType = commonTypeAlias.typeAlias.underlyingType,
|
||||||
|
arguments = emptyList(),
|
||||||
|
isMarkedNullable = type.isMarkedNullable
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
typeAliases = typeAliases.flatMap { (id, _) ->
|
||||||
|
classifierIndex.findTypeAliasesWithUnderlyingType(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return type
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isCommon(id: CirEntityId): Boolean =
|
||||||
|
commonDependencies.hasClassifier(id) || classifierIndices.all { index -> id in index.allClassifierIds }
|
||||||
|
}
|
||||||
|
|
||||||
+70
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.mergedtree
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.commonizer.cir.CirEntityId
|
||||||
|
import org.jetbrains.kotlin.commonizer.tree.*
|
||||||
|
import org.jetbrains.kotlin.commonizer.utils.compact
|
||||||
|
import org.jetbrains.kotlin.commonizer.utils.compactMapValues
|
||||||
|
|
||||||
|
internal fun CirClassifierIndex(tree: CirTreeRoot): CirClassifierIndex {
|
||||||
|
return CirUnderlyingTypeIndexBuilder().apply { invoke(tree) }.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
internal interface CirClassifierIndex {
|
||||||
|
val allClassifierIds: Set<CirEntityId>
|
||||||
|
fun findTypeAliasesWithUnderlyingType(underlyingClassifier: CirEntityId): List<CirTreeTypeAlias>
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CirClassifierIndexImpl(
|
||||||
|
override val allClassifierIds: Set<CirEntityId>,
|
||||||
|
private val typeAliasesByUnderlyingType: Map<CirEntityId, List<CirTreeTypeAlias>>
|
||||||
|
) : CirClassifierIndex {
|
||||||
|
|
||||||
|
override fun findTypeAliasesWithUnderlyingType(underlyingClassifier: CirEntityId): List<CirTreeTypeAlias> {
|
||||||
|
return typeAliasesByUnderlyingType[underlyingClassifier].orEmpty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CirUnderlyingTypeIndexBuilder {
|
||||||
|
private val index = mutableMapOf<CirEntityId, MutableList<CirTreeTypeAlias>>()
|
||||||
|
private val classifierIds = mutableSetOf<CirEntityId>()
|
||||||
|
|
||||||
|
operator fun invoke(tree: CirTreeRoot) {
|
||||||
|
tree.modules.forEach { module -> this(module) }
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun invoke(module: CirTreeModule) {
|
||||||
|
module.packages.forEach { pkg -> this(pkg) }
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun invoke(pkg: CirTreePackage) {
|
||||||
|
pkg.typeAliases.forEach { typeAlias -> this(typeAlias) }
|
||||||
|
pkg.classes.forEach { clazz -> this(clazz) }
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun invoke(typeAlias: CirTreeTypeAlias) {
|
||||||
|
classifierIds.add(typeAlias.id)
|
||||||
|
index.getOrPut(typeAlias.typeAlias.underlyingType.classifierId) { mutableListOf() }.add(typeAlias)
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun invoke(clazz: CirTreeClass) {
|
||||||
|
classifierIds.add(clazz.id)
|
||||||
|
clazz.classes.forEach { innerClazz -> this(innerClazz) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun build(): CirClassifierIndex {
|
||||||
|
return CirClassifierIndexImpl(
|
||||||
|
allClassifierIds = classifierIds.toSet(),
|
||||||
|
typeAliasesByUnderlyingType = index.compactMapValues { (_, list) -> list.compact() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
+45
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 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.mergedtree
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.commonizer.cir.CirFunction
|
||||||
|
import org.jetbrains.kotlin.commonizer.cir.CirProperty
|
||||||
|
import org.jetbrains.kotlin.commonizer.cir.CirType
|
||||||
|
import org.jetbrains.kotlin.commonizer.cir.CirValueParameter.Companion.copyInterned
|
||||||
|
|
||||||
|
interface CirTypeSubstitutor {
|
||||||
|
fun substitute(targetIndex: Int, type: CirType): CirType
|
||||||
|
}
|
||||||
|
|
||||||
|
fun CirTypeSubstitutor.substitute(index: Int, property: CirProperty): CirProperty {
|
||||||
|
val newReturnType = substitute(index, property.returnType)
|
||||||
|
return if (newReturnType != property.returnType) property.copy(returnType = newReturnType) else property
|
||||||
|
}
|
||||||
|
|
||||||
|
fun CirTypeSubstitutor.substitute(index: Int, function: CirFunction): CirFunction {
|
||||||
|
val newExtensionReceiverType = function.extensionReceiver?.type?.let { substitute(index, it) }
|
||||||
|
|
||||||
|
val newExtensionReceiver = if (newExtensionReceiverType != function.extensionReceiver?.type)
|
||||||
|
function.extensionReceiver?.copy(type = checkNotNull(newExtensionReceiverType))
|
||||||
|
else function.extensionReceiver
|
||||||
|
|
||||||
|
val newValueParameters = function.valueParameters.map { valueParameter ->
|
||||||
|
val newReturnType = substitute(index, valueParameter.returnType)
|
||||||
|
if (newReturnType != valueParameter.returnType) valueParameter.copyInterned(returnType = newReturnType) else valueParameter
|
||||||
|
}
|
||||||
|
|
||||||
|
val newReturnType = substitute(index, function.returnType)
|
||||||
|
|
||||||
|
return if (
|
||||||
|
newExtensionReceiver != function.extensionReceiver ||
|
||||||
|
newValueParameters != function.valueParameters ||
|
||||||
|
newReturnType != function.returnType
|
||||||
|
) function.copy(
|
||||||
|
extensionReceiver = newExtensionReceiver,
|
||||||
|
valueParameters = newValueParameters,
|
||||||
|
returnType = newReturnType
|
||||||
|
) else function
|
||||||
|
}
|
||||||
@@ -11,7 +11,10 @@ import org.jetbrains.kotlin.commonizer.mergedtree.*
|
|||||||
import org.jetbrains.kotlin.storage.StorageManager
|
import org.jetbrains.kotlin.storage.StorageManager
|
||||||
|
|
||||||
internal data class TargetBuildingContext(
|
internal data class TargetBuildingContext(
|
||||||
val storageManager: StorageManager, val classifiers: CirKnownClassifiers, val memberContext: CirMemberContext = CirMemberContext.empty,
|
val storageManager: StorageManager,
|
||||||
|
val classifiers: CirKnownClassifiers,
|
||||||
|
val memberContext: CirMemberContext = CirMemberContext.empty,
|
||||||
|
val typeSubstitutor: CirTypeSubstitutor,
|
||||||
val targets: Int, val targetIndex: Int
|
val targets: Int, val targetIndex: Int
|
||||||
) {
|
) {
|
||||||
fun withMemberContextOf(clazz: CirClass) = copy(memberContext = memberContext.withContextOf(clazz))
|
fun withMemberContextOf(clazz: CirClass) = copy(memberContext = memberContext.withContextOf(clazz))
|
||||||
@@ -24,7 +27,17 @@ internal fun mergeCirTree(
|
|||||||
roots.targets.withIndex().forEach { (targetIndex, target) ->
|
roots.targets.withIndex().forEach { (targetIndex, target) ->
|
||||||
node.targetDeclarations[targetIndex] = CirRoot.create(target)
|
node.targetDeclarations[targetIndex] = CirRoot.create(target)
|
||||||
node.buildModules(
|
node.buildModules(
|
||||||
TargetBuildingContext(storageManager, classifiers, CirMemberContext.empty, roots.size, targetIndex), roots[target].modules
|
TargetBuildingContext(
|
||||||
|
storageManager = storageManager,
|
||||||
|
classifiers = classifiers,
|
||||||
|
memberContext = CirMemberContext.empty,
|
||||||
|
typeSubstitutor = CirAliasTypeSubstitutor(
|
||||||
|
commonDependencies = classifiers.commonDependencies,
|
||||||
|
classifierIndices = roots.map(::CirClassifierIndex)
|
||||||
|
),
|
||||||
|
targets = roots.size,
|
||||||
|
targetIndex = targetIndex
|
||||||
|
), roots[target].modules
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return node
|
return node
|
||||||
@@ -70,19 +83,21 @@ internal fun CirNodeWithMembers<*, *>.buildClass(
|
|||||||
internal fun CirNodeWithMembers<*, *>.buildFunction(
|
internal fun CirNodeWithMembers<*, *>.buildFunction(
|
||||||
context: TargetBuildingContext, function: CirFunction, parent: CirNode<*, *>? = null
|
context: TargetBuildingContext, function: CirFunction, parent: CirNode<*, *>? = null
|
||||||
) {
|
) {
|
||||||
val functionNode = functions.getOrPut(FunctionApproximationKey.create(context.memberContext, function)) {
|
val newFunction = context.typeSubstitutor.substitute(context.targetIndex, function)
|
||||||
|
val functionNode = functions.getOrPut(FunctionApproximationKey.create(context.memberContext, newFunction)) {
|
||||||
buildFunctionNode(context.storageManager, context.targets, context.classifiers, CirNodeRelationship.ParentNode(parent))
|
buildFunctionNode(context.storageManager, context.targets, context.classifiers, CirNodeRelationship.ParentNode(parent))
|
||||||
}
|
}
|
||||||
functionNode.targetDeclarations[context.targetIndex] = function
|
functionNode.targetDeclarations[context.targetIndex] = newFunction
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun CirNodeWithMembers<*, *>.buildProperty(
|
internal fun CirNodeWithMembers<*, *>.buildProperty(
|
||||||
context: TargetBuildingContext, property: CirProperty, parent: CirNode<*, *>? = null
|
context: TargetBuildingContext, property: CirProperty, parent: CirNode<*, *>? = null
|
||||||
) {
|
) {
|
||||||
val propertyNode = properties.getOrPut(PropertyApproximationKey.create(context.memberContext, property)) {
|
val newProperty = context.typeSubstitutor.substitute(context.targetIndex, property)
|
||||||
|
val propertyNode = properties.getOrPut(PropertyApproximationKey.create(context.memberContext, newProperty)) {
|
||||||
buildPropertyNode(context.storageManager, context.targets, context.classifiers, CirNodeRelationship.ParentNode(parent))
|
buildPropertyNode(context.storageManager, context.targets, context.classifiers, CirNodeRelationship.ParentNode(parent))
|
||||||
}
|
}
|
||||||
propertyNode.targetDeclarations[context.targetIndex] = property
|
propertyNode.targetDeclarations[context.targetIndex] = newProperty
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun CirClassNode.buildConstructor(
|
internal fun CirClassNode.buildConstructor(
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ class CommonizedGroup<T : Any>(
|
|||||||
return elements[index] as T?
|
return elements[index] as T?
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun set(index: Int, value: T) {
|
operator fun set(index: Int, value: T?) {
|
||||||
val oldValue = this[index]
|
val oldValue = this[index]
|
||||||
check(oldValue == null) {
|
check(oldValue == null || value == null) {
|
||||||
"$oldValue can not be overwritten with $value at index $index"
|
"$oldValue can not be overwritten with $value at index $index"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
-63
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.commonizer.hierarchical
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.commonizer.AbstractInlineSourcesCommonizationTest
|
import org.jetbrains.kotlin.commonizer.AbstractInlineSourcesCommonizationTest
|
||||||
import org.jetbrains.kotlin.commonizer.assertCommonized
|
import org.jetbrains.kotlin.commonizer.assertCommonized
|
||||||
import org.junit.Test
|
|
||||||
|
|
||||||
class HierarchicalClassAndTypeAliasCommonizationTest : AbstractInlineSourcesCommonizationTest() {
|
class HierarchicalClassAndTypeAliasCommonizationTest : AbstractInlineSourcesCommonizationTest() {
|
||||||
|
|
||||||
@@ -573,66 +572,4 @@ class HierarchicalClassAndTypeAliasCommonizationTest : AbstractInlineSourcesComm
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("unused")
|
|
||||||
fun `ignored KT-47433 - test boxed function using TA and expanded type`() {
|
|
||||||
val result = commonize {
|
|
||||||
outputTarget("(a, b)")
|
|
||||||
|
|
||||||
simpleSingleSourceTarget(
|
|
||||||
"a", """
|
|
||||||
class Box<T>
|
|
||||||
class A
|
|
||||||
typealias X = A
|
|
||||||
fun x(x: Box<X>)
|
|
||||||
""".trimIndent()
|
|
||||||
)
|
|
||||||
|
|
||||||
simpleSingleSourceTarget(
|
|
||||||
"b", """
|
|
||||||
class Box<T>
|
|
||||||
class B
|
|
||||||
typealias X = B
|
|
||||||
fun x(x: Box<B>)
|
|
||||||
""".trimIndent()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
result.assertCommonized(
|
|
||||||
"(a, b)", """
|
|
||||||
expect class Box<T> expect constructor()
|
|
||||||
expect class X expect constructor()
|
|
||||||
expect fun x(x: Box<X>)
|
|
||||||
""".trimIndent()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("unused")
|
|
||||||
fun `ignored KT-47433 - test parameters with non-commonized TA expanding to a commonized type`() {
|
|
||||||
val result = commonize {
|
|
||||||
outputTarget("(a, b)")
|
|
||||||
|
|
||||||
simpleSingleSourceTarget(
|
|
||||||
"a", """
|
|
||||||
class X
|
|
||||||
fun useX(x: X) = Unit
|
|
||||||
""".trimIndent()
|
|
||||||
)
|
|
||||||
|
|
||||||
simpleSingleSourceTarget(
|
|
||||||
"b", """
|
|
||||||
class X
|
|
||||||
typealias B = X
|
|
||||||
fun useX(x: B) = Unit
|
|
||||||
""".trimIndent()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
result.assertCommonized(
|
|
||||||
"(a, b)", """
|
|
||||||
expect class X expect constructor()
|
|
||||||
expect fun useX(x: X)
|
|
||||||
""".trimIndent()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -184,7 +184,7 @@ class HierarchicalPropertyCommonizationTest : AbstractInlineSourcesCommonization
|
|||||||
expect class AB expect constructor()
|
expect class AB expect constructor()
|
||||||
expect typealias TA_AB = AB
|
expect typealias TA_AB = AB
|
||||||
// https://youtrack.jetbrains.com/issue/KT-47100
|
// https://youtrack.jetbrains.com/issue/KT-47100
|
||||||
expect val x: AB
|
expect val x: TA_AB
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+106
@@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
class HierarchicalTypeSubstitutionCommonizationTest : AbstractInlineSourcesCommonizationTest() {
|
||||||
|
|
||||||
|
fun `test boxed function using TA and expanded type`() {
|
||||||
|
val result = commonize {
|
||||||
|
outputTarget("(a, b)")
|
||||||
|
|
||||||
|
simpleSingleSourceTarget(
|
||||||
|
"a", """
|
||||||
|
class Box<T>
|
||||||
|
class A
|
||||||
|
typealias X = A
|
||||||
|
fun x(x: Box<X>)
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
simpleSingleSourceTarget(
|
||||||
|
"b", """
|
||||||
|
class Box<T>
|
||||||
|
class B
|
||||||
|
typealias X = B
|
||||||
|
fun x(x: Box<B>)
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
result.assertCommonized(
|
||||||
|
"(a, b)", """
|
||||||
|
expect class Box<T> expect constructor()
|
||||||
|
expect class X expect constructor()
|
||||||
|
expect fun x(x: Box<X>)
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun `test boxed function using TA and expanded type - with box from dependencies`() {
|
||||||
|
val result = commonize {
|
||||||
|
outputTarget("(a, b)")
|
||||||
|
|
||||||
|
registerDependency("a", "b", "(a, b)") {
|
||||||
|
source("""class Box<T>""")
|
||||||
|
}
|
||||||
|
|
||||||
|
simpleSingleSourceTarget(
|
||||||
|
"a", """
|
||||||
|
class A
|
||||||
|
typealias X = A
|
||||||
|
fun x(x: Box<X>)
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
simpleSingleSourceTarget(
|
||||||
|
"b", """
|
||||||
|
class B
|
||||||
|
typealias X = B
|
||||||
|
fun x(x: Box<B>)
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
result.assertCommonized(
|
||||||
|
"(a, b)", """
|
||||||
|
expect class X expect constructor()
|
||||||
|
expect fun x(x: Box<X>)
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun `test parameters with non-commonized TA expanding to a commonized type`() {
|
||||||
|
val result = commonize {
|
||||||
|
outputTarget("(a, b)")
|
||||||
|
|
||||||
|
simpleSingleSourceTarget(
|
||||||
|
"a", """
|
||||||
|
class X
|
||||||
|
fun useX(x: X) = Unit
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
simpleSingleSourceTarget(
|
||||||
|
"b", """
|
||||||
|
class X
|
||||||
|
typealias B = X
|
||||||
|
fun useX(x: B) = Unit
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
result.assertCommonized(
|
||||||
|
"(a, b)", """
|
||||||
|
expect class X expect constructor()
|
||||||
|
expect fun useX(x: X)
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user