From 9d2553bd185d5aa71bbfd4b74bd5a151309516be Mon Sep 17 00:00:00 2001 From: "sebastian.sellmair" Date: Mon, 13 Sep 2021 11:48:46 +0200 Subject: [PATCH] [Commonizer] Adapt TypeCommonizerTest ^KT-48288 --- .../core/ClassOrTypeAliasTypeCommonizer.kt | 2 +- .../CirCommonClassifierIdResolver.kt | 26 +- .../mergedtree/CirKnownClassifiers.kt | 3 +- .../CirCommonClassifierIdResolverTest.kt | 4 +- .../commonizer/core/TypeCommonizerTest.kt | 1026 +++++++++-------- .../commonizer/utils/InlineSourceBuilder.kt | 9 + 6 files changed, 610 insertions(+), 460 deletions(-) diff --git a/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/ClassOrTypeAliasTypeCommonizer.kt b/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/ClassOrTypeAliasTypeCommonizer.kt index c7f7b704820..05870525f69 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/ClassOrTypeAliasTypeCommonizer.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/ClassOrTypeAliasTypeCommonizer.kt @@ -28,7 +28,7 @@ internal class ClassOrTypeAliasTypeCommonizer( val arguments = TypeArgumentListCommonizer(typeCommonizer).commonize(values.map { it.arguments }) ?: return null val classifierId = selectClassifierId(values) ?: typeCommonizer.options.enableOptimisticNumberTypeCommonization.ifTrue { - return OptimisticNumbersTypeCommonizer.commonize(values.map { it.expandedType() }) + return OptimisticNumbersTypeCommonizer.commonize(expansions) } ?: return null val outerTypes = values.safeCastValues()?.map { it.outerType } diff --git a/native/commonizer/src/org/jetbrains/kotlin/commonizer/mergedtree/CirCommonClassifierIdResolver.kt b/native/commonizer/src/org/jetbrains/kotlin/commonizer/mergedtree/CirCommonClassifierIdResolver.kt index a2a32559838..40a5b5cb578 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/commonizer/mergedtree/CirCommonClassifierIdResolver.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/commonizer/mergedtree/CirCommonClassifierIdResolver.kt @@ -15,9 +15,10 @@ import org.jetbrains.kotlin.commonizer.cir.CirTypeAlias internal fun CirCommonClassifierIdResolver( classifierIndices: TargetDependent, - dependencies: CirProvidedClassifiers = CirProvidedClassifiers.EMPTY + targetDependencies: TargetDependent, + commonDependencies: CirProvidedClassifiers = CirProvidedClassifiers.EMPTY ): CirCommonClassifierIdResolver { - return CirCommonClassifierIdResolverImpl(classifierIndices, dependencies) + return CirCommonClassifierIdResolverImpl(classifierIndices, targetDependencies, commonDependencies) } interface CirCommonClassifierIdResolver { @@ -26,7 +27,8 @@ interface CirCommonClassifierIdResolver { private class CirCommonClassifierIdResolverImpl( private val classifierIndices: TargetDependent, - private val dependencies: CirProvidedClassifiers + private val targetDependencies: TargetDependent, + private val commonDependencies: CirProvidedClassifiers ) : CirCommonClassifierIdResolver { private val cachedResults = THashMap() @@ -54,8 +56,10 @@ private class CirCommonClassifierIdResolverImpl( val nextClassifierId = queue.removeFirst() /* Either CirClassifier or CirProvided.Classifier or null */ - val foundClassifiers = classifierIndices.associateWith { index -> - index.findClassifier(nextClassifierId) ?: dependencies.classifier(nextClassifierId) + val foundClassifiers = classifierIndices.targets.associateWith { index -> + classifierIndices[index].findClassifier(nextClassifierId) + ?: targetDependencies[index].classifier(nextClassifierId) + ?: commonDependencies.classifier(nextClassifierId) } /* Classifier is available for all targets */ @@ -63,17 +67,23 @@ private class CirCommonClassifierIdResolverImpl( results.add(nextClassifierId) } - foundClassifiers.forEach { (index, classifier) -> + foundClassifiers.forEach { (target, classifier) -> if (classifier == null) return@forEach // Propagate to the left (towards typealias) - index.findTypeAliasesWithUnderlyingType(nextClassifierId).forEach { alias -> + classifierIndices[target].findTypeAliasesWithUnderlyingType(nextClassifierId).forEach { alias -> if (visited.add(alias.id)) { queue.add(alias.id) } } - dependencies.findTypeAliasesWithUnderlyingType(nextClassifierId).forEach { aliasId -> + targetDependencies[target].findTypeAliasesWithUnderlyingType(nextClassifierId).forEach { aliasId -> + if (visited.add(aliasId)) { + queue.add(aliasId) + } + } + + commonDependencies.findTypeAliasesWithUnderlyingType(nextClassifierId).forEach { aliasId -> if (visited.add(aliasId)) { queue.add(aliasId) } diff --git a/native/commonizer/src/org/jetbrains/kotlin/commonizer/mergedtree/CirKnownClassifiers.kt b/native/commonizer/src/org/jetbrains/kotlin/commonizer/mergedtree/CirKnownClassifiers.kt index 30f8148b523..a4f695bd80e 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/commonizer/mergedtree/CirKnownClassifiers.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/commonizer/mergedtree/CirKnownClassifiers.kt @@ -14,7 +14,8 @@ class CirKnownClassifiers( val targetDependencies: TargetDependent, val commonizedNodes: CirCommonizedClassifierNodes, val commonDependencies: CirProvidedClassifiers, - val commonClassifierIdResolver: CirCommonClassifierIdResolver = CirCommonClassifierIdResolver(classifierIndices, commonDependencies), + val commonClassifierIdResolver: CirCommonClassifierIdResolver = + CirCommonClassifierIdResolver(classifierIndices, targetDependencies, commonDependencies), ) /** A set of all CIR nodes built for commonized classes and type aliases. */ diff --git a/native/commonizer/tests/org/jetbrains/kotlin/commonizer/CirCommonClassifierIdResolverTest.kt b/native/commonizer/tests/org/jetbrains/kotlin/commonizer/CirCommonClassifierIdResolverTest.kt index c95696c8fc1..378f4a58e5a 100644 --- a/native/commonizer/tests/org/jetbrains/kotlin/commonizer/CirCommonClassifierIdResolverTest.kt +++ b/native/commonizer/tests/org/jetbrains/kotlin/commonizer/CirCommonClassifierIdResolverTest.kt @@ -277,7 +277,9 @@ private fun createCommonClassifierIdResolver( return CirCommonClassifierIdResolver( TargetDependent(root.withIndex().associate { (index, root) -> LeafCommonizerTarget(index.toString()) to root }) .mapValue(::CirClassifierIndex), - dependencies = dependencies + targetDependencies = root.withIndex() + .associate { (index, _) -> LeafCommonizerTarget(index.toString()) to CirProvidedClassifiers.EMPTY }.toTargetDependent(), + commonDependencies = dependencies ) } diff --git a/native/commonizer/tests/org/jetbrains/kotlin/commonizer/core/TypeCommonizerTest.kt b/native/commonizer/tests/org/jetbrains/kotlin/commonizer/core/TypeCommonizerTest.kt index c1d17cabae7..e5e74bb9eb6 100644 --- a/native/commonizer/tests/org/jetbrains/kotlin/commonizer/core/TypeCommonizerTest.kt +++ b/native/commonizer/tests/org/jetbrains/kotlin/commonizer/core/TypeCommonizerTest.kt @@ -5,498 +5,626 @@ package org.jetbrains.kotlin.commonizer.core +import org.jetbrains.kotlin.commonizer.AbstractInlineSourcesCommonizationTest +import org.jetbrains.kotlin.commonizer.LeafCommonizerTarget import org.jetbrains.kotlin.commonizer.TargetDependent -import org.jetbrains.kotlin.commonizer.cir.* -import org.jetbrains.kotlin.commonizer.mergedtree.* -import org.jetbrains.kotlin.commonizer.utils.isUnderStandardKotlinPackages -import org.jetbrains.kotlin.commonizer.utils.mockClassType -import org.jetbrains.kotlin.commonizer.utils.mockTAType -import org.jetbrains.kotlin.descriptors.ClassKind -import org.jetbrains.kotlin.descriptors.Modality -import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.commonizer.cir.CirType +import org.jetbrains.kotlin.commonizer.mapValue +import org.jetbrains.kotlin.commonizer.mergedtree.CirClassifierIndex +import org.jetbrains.kotlin.commonizer.mergedtree.CirCommonizedClassifierNodes +import org.jetbrains.kotlin.commonizer.mergedtree.CirKnownClassifiers +import org.jetbrains.kotlin.commonizer.mergedtree.CirProvidedClassifiers +import org.jetbrains.kotlin.commonizer.tree.mergeCirTree +import org.jetbrains.kotlin.commonizer.utils.* import org.jetbrains.kotlin.storage.LockBasedStorageManager -import org.junit.Before -import org.junit.Test -class TypeCommonizerTest : AbstractCommonizerTest() { +class TypeCommonizerTest : AbstractInlineSourcesCommonizationTest() { - private lateinit var classifiers: CirKnownClassifiers + fun createCommonizer( + commonTargetSources: InlineSourceBuilder.ModuleBuilder.() -> Unit = { + source( + """ + package org.sample + class Foo + class Bar + """.trimIndent(), "commonTargetSource.kt" + ) + source( + """ + package org.fictitiousPackageName + class Foo + """.trimIndent() + ) + }, + commonDependencySources: InlineSourceBuilder.ModuleBuilder.() -> Unit = { + source( + """ + package kotlin.collections + class List + class Set + """.trimIndent(), "collections.kt" + ) - @Before - fun initialize() { - // reset cache - classifiers = CirKnownClassifiers( - classifierIndices = TargetDependent.empty(), - targetDependencies = TargetDependent.empty(), + source( + """ + package kotlinx.cinterop + class CPointer + """.trimIndent(), "cinterop.kt" + ) + + source( + """ + package kotlin.fictitiousPackageName + class List + class CPointer + """.trimIndent(), "fictitiousPackageName.kt" + ) + }, + targetASpecificSources: (InlineSourceBuilder.ModuleBuilder.() -> Unit)? = null, + targetBSpecificSources: (InlineSourceBuilder.ModuleBuilder.() -> Unit)? = null, + targetCSpecificSources: (InlineSourceBuilder.ModuleBuilder.() -> Unit)? = null, + targetADependencySources: (InlineSourceBuilder.ModuleBuilder.() -> Unit)? = null, + targetBDependencySources: (InlineSourceBuilder.ModuleBuilder.() -> Unit)? = null, + targetCDependencySources: (InlineSourceBuilder.ModuleBuilder.() -> Unit)? = null + ): TypeCommonizer { + + val targetARoot = createCirTreeRoot { + commonTargetSources() + if (targetASpecificSources != null) targetASpecificSources() + } + + val targetBRoot = createCirTreeRoot { + commonTargetSources() + if (targetBSpecificSources != null) targetBSpecificSources() + } + + val targetCRoot = createCirTreeRoot { + commonTargetSources() + if (targetCSpecificSources != null) targetCSpecificSources() + } + + val commonDependencies = createCirProvidedClassifiers { commonDependencySources() } + + val targetADependencies = targetADependencySources?.let { createCirProvidedClassifiers { it() } } ?: CirProvidedClassifiers.EMPTY + val targetBDependencies = targetBDependencySources?.let { createCirProvidedClassifiers { it() } } ?: CirProvidedClassifiers.EMPTY + val targetCDependencies = targetCDependencySources?.let { createCirProvidedClassifiers { it() } } ?: CirProvidedClassifiers.EMPTY + + val targetDependencies = TargetDependent( + LeafCommonizerTarget("a") to targetADependencies, + LeafCommonizerTarget("b") to targetBDependencies, + LeafCommonizerTarget("c") to targetCDependencies + ) + + val roots = TargetDependent( + LeafCommonizerTarget("a") to targetARoot, + LeafCommonizerTarget("b") to targetBRoot, + LeafCommonizerTarget("c") to targetCRoot + ) + + val classifiers = CirKnownClassifiers( + classifierIndices = roots.mapValue(::CirClassifierIndex), + targetDependencies = targetDependencies, commonizedNodes = CirCommonizedClassifierNodes.default(), - commonDependencies = object : CirProvidedClassifiers { - override fun hasClassifier(classifierId: CirEntityId) = classifierId.packageName.isUnderStandardKotlinPackages - override fun classifier(classifierId: CirEntityId) = error("This method should not be called") - override fun findTypeAliasesWithUnderlyingType(underlyingClassifier: CirEntityId): List = emptyList() - } + commonDependencies = commonDependencies + ).also { classifiers -> + mergeCirTree(LockBasedStorageManager.NO_LOCKS, classifiers, roots) + } + + return TypeCommonizer(classifiers) + } + + + fun `test class types in Kotlin package with same name`() { + assertEquals( + mockClassType("kotlin/collections/List"), createCommonizer().invoke( + listOf( + mockClassType("kotlin/collections/List"), + mockClassType("kotlin/collections/List"), + mockClassType("kotlin/collections/List") + ) + ) ) } - @Test - fun classTypesInKotlinPackageWithSameName() = doTestSuccess( - expected = mockClassType("kotlin/collections/List"), - mockClassType("kotlin/collections/List"), - mockClassType("kotlin/collections/List"), - mockClassType("kotlin/collections/List") - ) + fun `test class types in Kotlin package with different names - 1`() { + assertEquals( + null, createCommonizer().invoke( + listOf( + mockClassType("kotlin/collections/List"), + mockClassType("kotlin/collections/List"), + mockClassType("kotlin/fictitiousPackageName/List") + ) + ) + ) + } - @Test(expected = IllegalCommonizerStateException::class) - fun classTypesInKotlinPackageWithDifferentNames1() = doTestFailure( - mockClassType("kotlin/collections/List"), - mockClassType("kotlin/collections/List"), - mockClassType("kotlin/fictitiousPackageName/List") - ) + fun `test class types in Kotlin package with different names - 2`() { + assertEquals( + null, createCommonizer().invoke( + listOf( + mockClassType("kotlin/collections/List"), + mockClassType("kotlin/collections/List"), + mockClassType("kotlin/collections/Set") + ) + ) + ) + } - @Test(expected = IllegalCommonizerStateException::class) - fun classTypesInKotlinPackageWithDifferentNames2() = doTestFailure( - mockClassType("kotlin/collections/List"), - mockClassType("kotlin/collections/List"), - mockClassType("kotlin/collections/Set") - ) + fun `test class types in Kotlin package with different names - 3`() { + assertEquals( + null, createCommonizer().invoke( + listOf( + mockClassType("kotlin/collections/List"), + mockClassType("kotlin/collections/List"), + mockClassType("org/sample/Foo") + ) + ) + ) + } - @Test(expected = IllegalCommonizerStateException::class) - fun classTypesInKotlinPackageWithDifferentNames3() = doTestFailure( - mockClassType("kotlin/collections/List"), - mockClassType("kotlin/collections/List"), - mockClassType("org/sample/Foo") - ) + fun `test class types in Kotlinx package with same name`() { + assertEquals( + mockClassType("kotlinx/cinterop/CPointer"), createCommonizer().invoke( + listOf( + mockClassType("kotlinx/cinterop/CPointer"), + mockClassType("kotlinx/cinterop/CPointer"), + mockClassType("kotlinx/cinterop/CPointer") + ) + ) + ) + } - @Test - fun classTypesInKotlinxPackageWithSameName() = doTestSuccess( - expected = mockClassType("kotlinx/cinterop/CPointer"), - mockClassType("kotlinx/cinterop/CPointer"), - mockClassType("kotlinx/cinterop/CPointer"), - mockClassType("kotlinx/cinterop/CPointer") - ) + fun `test class types in Kotlinx package with different names - 1`() { + assertEquals( + null, createCommonizer().invoke( + listOf( + mockClassType("kotlinx/cinterop/CPointer"), + mockClassType("kotlinx/cinterop/CPointer"), + mockClassType("kotlin/fictitiousPackageName/CPointer") + ) + ) + ) + } - @Test(expected = IllegalCommonizerStateException::class) - fun classTypesInKotlinxPackageWithDifferentNames1() = doTestFailure( - mockClassType("kotlinx/cinterop/CPointer"), - mockClassType("kotlinx/cinterop/CPointer"), - mockClassType("kotlinx/fictitiousPackageName/CPointer") - ) + fun `test class types in user package with same name`() { + assertEquals( + mockClassType("org/sample/Foo"), createCommonizer().invoke( + listOf( + mockClassType("org/sample/Foo"), + mockClassType("org/sample/Foo"), + mockClassType("org/sample/Foo") + ) + ) + ) + } - @Test(expected = IllegalCommonizerStateException::class) - fun classTypesInKotlinxPackageWithDifferentNames2() = doTestFailure( - mockClassType("kotlinx/cinterop/CPointer"), - mockClassType("kotlinx/cinterop/CPointer"), - mockClassType("kotlinx/cinterop/ObjCObject") - ) + fun `test class types in user package with different names - 1`() { + assertEquals( + null, createCommonizer().invoke( + listOf( + mockClassType("org/sample/Foo"), + mockClassType("org/fictitiousPackageName/Foo") + ) + ) + ) + } - @Test(expected = IllegalCommonizerStateException::class) - fun classTypesInKotlinxPackageWithDifferentNames3() = doTestFailure( - mockClassType("kotlinx/cinterop/CPointer"), - mockClassType("kotlinx/cinterop/CPointer"), - mockClassType("org/sample/Foo") - ) + fun `test class types in user package with different names - 2`() { + assertEquals( + null, createCommonizer().invoke( + listOf( + mockClassType("org/sample/Foo"), + mockClassType("org/sample/Bar") + ) + ) + ) + } - @Test - fun classTypesInUserPackageWithSameName() = doTestSuccess( - expected = mockClassType("org/sample/Foo"), - mockClassType("org/sample/Foo"), - mockClassType("org/sample/Foo"), - mockClassType("org/sample/Foo") - ) + fun `test class types in user package with different names - 3`() { + assertEquals( + null, createCommonizer().invoke( + listOf( + mockClassType("org/sample/Foo"), + mockClassType("kotlin/String") + ) + ) + ) + } - @Test(expected = IllegalCommonizerStateException::class) - fun classTypesInUserPackageWithDifferentNames1() = doTestFailure( - mockClassType("org/sample/Foo"), - mockClassType("org/fictitiousPackageName/Foo"), - shouldFailOnFirstVariant = false - ) + fun `test class types in Kotlin package with same nullability - 1`() { + assertEquals( + mockClassType("kotlin/collections/List", nullable = false), createCommonizer().invoke( + listOf( + mockClassType("kotlin/collections/List", nullable = false), + mockClassType("kotlin/collections/List", nullable = false), + mockClassType("kotlin/collections/List", nullable = false) + ) + ) + ) + } - @Test(expected = IllegalCommonizerStateException::class) - fun classTypesInUserPackageWithDifferentNames2() = doTestFailure( - mockClassType("org/sample/Foo"), - mockClassType("org/sample/Bar"), - shouldFailOnFirstVariant = false - ) + fun `test class types in Kotlin package with same nullability - 2`() { + assertEquals( + mockClassType("kotlin/collections/List", nullable = true), createCommonizer().invoke( + listOf( + mockClassType("kotlin/collections/List", nullable = true), + mockClassType("kotlin/collections/List", nullable = true), + mockClassType("kotlin/collections/List", nullable = true) + ) + ) + ) + } - @Test(expected = IllegalCommonizerStateException::class) - fun classTypesInUserPackageWithDifferentNames3() = doTestFailure( - mockClassType("org/sample/Foo"), - mockClassType("kotlin/String"), - shouldFailOnFirstVariant = false - ) + fun `test class types in Kotlin package with different nullability - 1`() { + assertEquals( + null, createCommonizer().invoke( + listOf( + mockClassType("kotlin/collections/List", nullable = false), + mockClassType("kotlin/collections/List", nullable = false), + mockClassType("kotlin/collections/List", nullable = true) + ) + ) + ) + } - @Test - fun classTypesInKotlinPackageWithSameNullability1() = doTestSuccess( - expected = mockClassType("kotlin/collections/List", nullable = false), - mockClassType("kotlin/collections/List", nullable = false), - mockClassType("kotlin/collections/List", nullable = false), - mockClassType("kotlin/collections/List", nullable = false) - ) + fun `test class types in Kotlin package with different nullability - 2`() { + assertEquals( + null, createCommonizer().invoke( + listOf( + mockClassType("kotlin/collections/List", nullable = true), + mockClassType("kotlin/collections/List", nullable = true), + mockClassType("kotlin/collections/List", nullable = false) + ) + ) + ) + } - @Test - fun classTypesInKotlinPackageWithSameNullability2() = doTestSuccess( - expected = mockClassType("kotlin/collections/List", nullable = true), - mockClassType("kotlin/collections/List", nullable = true), - mockClassType("kotlin/collections/List", nullable = true), - mockClassType("kotlin/collections/List", nullable = true) - ) + fun `test class types in user package with same nullability - 1`() { + assertEquals( + mockClassType("org/sample/Foo", nullable = false), createCommonizer().invoke( + listOf( + mockClassType("org/sample/Foo", nullable = false), + mockClassType("org/sample/Foo", nullable = false), + mockClassType("org/sample/Foo", nullable = false) + ) + ) + ) + } - @Test(expected = IllegalCommonizerStateException::class) - fun classTypesInKotlinPackageWithDifferentNullability1() = doTestFailure( - mockClassType("kotlin/collections/List", nullable = false), - mockClassType("kotlin/collections/List", nullable = false), - mockClassType("kotlin/collections/List", nullable = true) - ) + fun `test class types in user package with same nullability - 2`() { + assertEquals( + mockClassType("org/sample/Foo", nullable = true), createCommonizer().invoke( + listOf( + mockClassType("org/sample/Foo", nullable = true), + mockClassType("org/sample/Foo", nullable = true), + mockClassType("org/sample/Foo", nullable = true) + ) + ) + ) + } - @Test(expected = IllegalCommonizerStateException::class) - fun classTypesInKotlinPackageWithDifferentNullability2() = doTestFailure( - mockClassType("kotlin/collections/List", nullable = true), - mockClassType("kotlin/collections/List", nullable = true), - mockClassType("kotlin/collections/List", nullable = false) - ) + fun `test class types in user package with different nullability - 1`() { + assertEquals( + null, createCommonizer().invoke( + listOf( + mockClassType("org/sample/Foo", nullable = false), + mockClassType("org/sample/Foo", nullable = false), + mockClassType("org/sample/Foo", nullable = true) + ) + ) + ) + } - @Test - fun classTypesInUserPackageWithSameNullability1() = doTestSuccess( - expected = mockClassType("org/sample/Foo", nullable = false), - mockClassType("org/sample/Foo", nullable = false), - mockClassType("org/sample/Foo", nullable = false), - mockClassType("org/sample/Foo", nullable = false) - ) + fun `test class types in user package with different nullability - 2`() { + assertEquals( + null, createCommonizer().invoke( + listOf( + mockClassType("org/sample/Foo", nullable = true), + mockClassType("org/sample/Foo", nullable = true), + mockClassType("org/sample/Foo", nullable = false) + ) + ) + ) + } - @Test - fun classTypesInUserPackageWithSameNullability2() = doTestSuccess( - expected = mockClassType("org/sample/Foo", nullable = true), - mockClassType("org/sample/Foo", nullable = true), - mockClassType("org/sample/Foo", nullable = true), - mockClassType("org/sample/Foo", nullable = true) - ) - - @Test(expected = IllegalCommonizerStateException::class) - fun classTypesInUserPackageWithDifferentNullability1() = doTestFailure( - mockClassType("org/sample/Foo", nullable = false), - mockClassType("org/sample/Foo", nullable = false), - mockClassType("org/sample/Foo", nullable = true) - ) - - @Test(expected = IllegalCommonizerStateException::class) - fun classTypesInUserPackageWithDifferentNullability2() = doTestFailure( - mockClassType("org/sample/Foo", nullable = true), - mockClassType("org/sample/Foo", nullable = true), - mockClassType("org/sample/Foo", nullable = false) - ) - - @Test - // why success: matching FQNs from the standard Kotlin packages - fun taTypesInKotlinPackageWithSameNameAndClass() = doTestSuccess( - expected = mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope") }, - mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope") }, - mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope") }, - mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope") } - ) - - @Test - fun taTypesInKotlinPackageWithDifferentNames() = doTestSuccess( - expected = mockClassType("kotlin/sequences/SequenceScope"), - mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope") }, - mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope") }, - mockTAType("kotlin/sequences/FictitiousTypeAlias") { mockClassType("kotlin/sequences/SequenceScope") } - ) - - @Test - // why success: matching FQNs from the standard Kotlin packages - fun taTypesInKotlinPackageWithDifferentClasses() = doTestSuccess( - expected = mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope") }, - mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope") }, - mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope") }, - mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/FictitiousClass") } - ) - - @Test - // why success: matching FQNs from the standard Kotlin packages - fun taTypesInKotlinxPackageWithSameNameAndClass() = doTestSuccess( - expected = mockTAType("kotlinx/cinterop/CArrayPointer") { mockClassType("kotlinx/cinterop/CPointer") }, - mockTAType("kotlinx/cinterop/CArrayPointer") { mockClassType("kotlinx/cinterop/CPointer") }, - mockTAType("kotlinx/cinterop/CArrayPointer") { mockClassType("kotlinx/cinterop/CPointer") }, - mockTAType("kotlinx/cinterop/CArrayPointer") { mockClassType("kotlinx/cinterop/CPointer") } - ) - - @Test() - fun taTypesInKotlinxPackageWithDifferentNames() = doTestSuccess( - expected = mockClassType("kotlinx/cinterop/CPointer"), - mockTAType("kotlinx/cinterop/CArrayPointer") { mockClassType("kotlinx/cinterop/CPointer") }, - mockTAType("kotlinx/cinterop/CArrayPointer") { mockClassType("kotlinx/cinterop/CPointer") }, - mockTAType("kotlinx/cinterop/FictitiousTypeAlias") { mockClassType("kotlinx/cinterop/CPointer") } - ) - - @Test - // why success: matching FQNs from the standard Kotlin packages - fun taTypesInKotlinxPackageWithDifferentClasses() = doTestSuccess( - expected = mockTAType("kotlinx/cinterop/CArrayPointer") { mockClassType("kotlinx/cinterop/CPointer") }, - mockTAType("kotlinx/cinterop/CArrayPointer") { mockClassType("kotlinx/cinterop/CPointer") }, - mockTAType("kotlinx/cinterop/CArrayPointer") { mockClassType("kotlinx/cinterop/CPointer") }, - mockTAType("kotlinx/cinterop/CArrayPointer") { mockClassType("kotlinx/cinterop/FictitiousClass") } - ) - - @Test - // why success: matching FQNs from the standard Kotlin packages - fun multilevelTATypesInKotlinPackageWithSameNameAndRightHandSideClass() = doTestSuccess( - expected = mockTAType("kotlin/FictitiousTypeAlias") { - mockClassType("kotlin/FictitiousClass") - }, - - mockTAType("kotlin/FictitiousTypeAlias") { - mockClassType("kotlin/FictitiousClass") - }, - - mockTAType("kotlin/FictitiousTypeAlias") { - mockTAType("kotlin/FictitiousTypeAliasL2") { - mockClassType("kotlin/FictitiousClass") + fun `test ta types in Kotlin package with same name and class`() { + val commonizer = createCommonizer( + commonDependencySources = { + source( + """ + package kotlin.sequences + class SequenceScope + typealias SequenceBuilder = SequenceScope + """.trimIndent(), "sequences.kt" + ) } - }, + ) - mockTAType("kotlin/FictitiousTypeAlias") { - mockTAType("kotlin/FictitiousTypeAliasL2") { - mockTAType("kotlin/FictitiousTypeAliasL3") { + assertEquals(mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope") }, commonizer( + listOf( + mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope") }, + mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope") }, + mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope") } + ))) + } + + fun `test ta types in Kotlin package with different names`() { + val commonizer = createCommonizer( + commonDependencySources = { + source( + """ + package kotlin.sequences + class SequenceScope + typealias SequenceBuilder = SequenceScope + """.trimIndent() + ) + }, + + targetCDependencySources = { + source( + """ + package kotlin.sequences + class SequenceScope + typealias FictitiousTypeAlias = SequenceScope + """.trimIndent(), "fictitious.kt" + ) + } + ) + assertEquals( + mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope") }, commonizer( + listOf( + mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope") }, + mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope") }, + mockTAType("kotlin/sequences/FictitiousTypeAlias") { mockClassType("kotlin/sequences/SequenceScope") } + ))) + } + + fun `test ta types in Kotlin package with different classes`() { + val commonizer = createCommonizer( + targetADependencySources = { + source( + """ + package kotlin.sequences + class SequenceScope + typealias SequenceBuilder = SequenceScope + """.trimIndent() + ) + }, + targetBDependencySources = { + source( + """ + package kotlin.sequences + class SequenceScope + typealias SequenceBuilder = SequenceScope + """.trimIndent() + ) + }, + targetCDependencySources = { + source( + """ + package kotlin.sequences + class FictitiousClass + typealias SequenceBuilder = FictitiousClass + """.trimIndent() + ) + } + ) + assertEquals(null, commonizer( + listOf( + mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope") }, + mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope") }, + mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/FictitiousClass") } + ))) + } + + fun `test multilevel ta types in Kotlin package with same name and right hand side class`() { + val commonizer = createCommonizer( + targetASpecificSources = { + source( + """ + package kotlin + class FictitiousClass + typealias FictitiousTypeAlias = FictitiousClass + """.trimIndent() + ) + }, + targetBSpecificSources = { + source( + """ + package kotlin + class FictitiousClass + typealias FictitiousTypeAliasL2 = FictitiousClass + typealias FictitiousTypeAlias = FictitiousTypeAliasL2 + """.trimIndent() + ) + }, + targetCSpecificSources = { + source( + """ + package kotlin + class FictitiousClass + typealias FictitiousTypeAliasL2 = FictitiousClass + typealias FictitiousTypeAliasL3 = FictitiousTypeAliasL2 + typealias FictitiousTypeAlias = FictitiousTypeAliasL3 + """.trimIndent() + ) + } + ) + assertEquals(mockTAType("kotlin/FictitiousTypeAlias") { + mockClassType("kotlin/FictitiousClass") + }, commonizer(listOf( + + mockTAType("kotlin/FictitiousTypeAlias") { + mockClassType("kotlin/FictitiousClass") + }, + + mockTAType("kotlin/FictitiousTypeAlias") { + mockTAType("kotlin/FictitiousTypeAliasL2") { mockClassType("kotlin/FictitiousClass") } - } - } - ) + }, - @Test - // why success: lifting up - fun taTypesInUserPackageWithSameNameAndClass() = doTestSuccess( - expected = mockTAType("org/sample/FooAlias") { mockClassType("org/sample/Foo") }, - mockTAType("org/sample/FooAlias") { mockClassType("org/sample/Foo") }, - mockTAType("org/sample/FooAlias") { mockClassType("org/sample/Foo") }, - mockTAType("org/sample/FooAlias") { mockClassType("org/sample/Foo") } - ) - - @Test - fun taTypesInUserPackageWithDifferentNames() = doTestSuccess( - expected = mockClassType("org/sample/Foo"), - mockTAType("org/sample/FooAlias") { mockClassType("org/sample/Foo") }, - mockTAType("org/sample/BarAlias") { mockClassType("org/sample/Foo") }, - ) - - @Test - // why success: short-circuiting & lifting up - fun multilevelTATypesInUserPackageWithSameNameAndRightHandSideClass1() = doTestSuccess( - expected = mockTAType("org/sample/FooAlias") { - mockClassType("org/sample/Foo") - }, - - mockTAType("org/sample/FooAlias") { - mockClassType("org/sample/Foo") - }, - - mockTAType("org/sample/FooAlias") { - mockTAType("org/sample/FooAliasL2") { - mockClassType("org/sample/Foo") - } - } - ) - - @Test - // why success: short-circuiting & lifting up - fun multilevelTATypesInUserPackageWithSameNameAndRightHandSideClass2() = doTestSuccess( - expected = mockTAType("org/sample/FooAlias") { - mockClassType("org/sample/Foo") - }, - - mockTAType("org/sample/FooAlias") { - mockTAType("org/sample/FooAliasL2") { - mockClassType("org/sample/Foo") - } - }, - - mockTAType("org/sample/FooAlias") { - mockClassType("org/sample/Foo") - } - ) - - @Test - // why success: lifting up (inner and outer TAs) - fun multilevelTATypesInUserPackageWithSameNameAndRightHandSideClass3() = doTestSuccess( - expected = mockTAType("org/sample/FooAlias") { - mockTAType("org/sample/FooAliasL2") { - mockClassType("org/sample/Foo") - } - }, - - mockTAType("org/sample/FooAlias") { - mockTAType("org/sample/FooAliasL2") { - mockClassType("org/sample/Foo") - } - }, - - mockTAType("org/sample/FooAlias") { - mockTAType("org/sample/FooAliasL2") { - mockClassType("org/sample/Foo") - } - } - ) - - @Test - // why success: types with the same nullability are treated as equal - fun taTypesInKotlinPackageWithSameNullability1() = doTestSuccess( - expected = mockTAType("kotlin/sequences/SequenceBuilder", nullable = false) { mockClassType("kotlin/sequences/SequenceScope") }, - mockTAType("kotlin/sequences/SequenceBuilder", nullable = false) { mockClassType("kotlin/sequences/SequenceScope") }, - mockTAType("kotlin/sequences/SequenceBuilder", nullable = false) { mockClassType("kotlin/sequences/SequenceScope") }, - mockTAType("kotlin/sequences/SequenceBuilder", nullable = false) { mockClassType("kotlin/sequences/SequenceScope") } - ) - - @Test - // why success: types with the same nullability are treated as equal - fun taTypesInKotlinPackageWithSameNullability2() = doTestSuccess( - expected = mockTAType("kotlin/sequences/SequenceBuilder", nullable = true) { mockClassType("kotlin/sequences/SequenceScope") }, - mockTAType("kotlin/sequences/SequenceBuilder", nullable = true) { mockClassType("kotlin/sequences/SequenceScope") }, - mockTAType("kotlin/sequences/SequenceBuilder", nullable = true) { mockClassType("kotlin/sequences/SequenceScope") }, - mockTAType("kotlin/sequences/SequenceBuilder", nullable = true) { mockClassType("kotlin/sequences/SequenceScope") } - ) - - @Test(expected = IllegalCommonizerStateException::class) - fun taTypesInKotlinPackageWithDifferentNullability1() = doTestFailure( - mockTAType("kotlin/sequences/SequenceBuilder", nullable = false) { mockClassType("kotlin/sequences/SequenceScope") }, - mockTAType("kotlin/sequences/SequenceBuilder", nullable = false) { mockClassType("kotlin/sequences/SequenceScope") }, - mockTAType("kotlin/sequences/SequenceBuilder", nullable = true) { mockClassType("kotlin/sequences/SequenceScope") } - ) - - @Test(expected = IllegalCommonizerStateException::class) - fun taTypesInKotlinPackageWithDifferentNullability2() = doTestFailure( - mockTAType("kotlin/sequences/SequenceBuilder", nullable = true) { mockClassType("kotlin/sequences/SequenceScope") }, - mockTAType("kotlin/sequences/SequenceBuilder", nullable = true) { mockClassType("kotlin/sequences/SequenceScope") }, - mockTAType("kotlin/sequences/SequenceBuilder", nullable = false) { mockClassType("kotlin/sequences/SequenceScope") } - ) - - @Test(expected = IllegalCommonizerStateException::class) - // why failure: Different nullability in type-expansion can't be commonized by now - fun taTypesInKotlinPackageWithDifferentNullability3() = doTestFailure( - mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope", nullable = false) }, - mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope", nullable = false) }, - mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope", nullable = true) } - ) - - @Test(expected = IllegalCommonizerStateException::class) - // why failure: Different nullability in type-expansion can't be commonized by now - fun taTypesInKotlinPackageWithDifferentNullability4() = doTestFailure( - mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope", nullable = true) }, - mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope", nullable = true) }, - mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope", nullable = false) } - ) - - @Test - // why success: types with the same nullability are treated as equal - fun taTypesInUserPackageWithSameNullability1() = doTestSuccess( - expected = mockTAType("org/sample/FooAlias", nullable = false) { mockClassType("org/sample/Foo") }, - mockTAType("org/sample/FooAlias", nullable = false) { mockClassType("org/sample/Foo") }, - mockTAType("org/sample/FooAlias", nullable = false) { mockClassType("org/sample/Foo") }, - mockTAType("org/sample/FooAlias", nullable = false) { mockClassType("org/sample/Foo") } - ) - - @Test - // why success: types with the same nullability are treated as equal - fun taTypesInUserPackageWithSameNullability2() = doTestSuccess( - expected = mockTAType("org/sample/FooAlias", nullable = true) { mockClassType("org/sample/Foo") }, - mockTAType("org/sample/FooAlias", nullable = true) { mockClassType("org/sample/Foo") }, - mockTAType("org/sample/FooAlias", nullable = true) { mockClassType("org/sample/Foo") }, - mockTAType("org/sample/FooAlias", nullable = true) { mockClassType("org/sample/Foo") } - ) - - @Test(expected = IllegalCommonizerStateException::class) - fun taTypesInUserPackageWithDifferentNullability1() = doTestFailure( - mockTAType("org/sample/FooAlias", nullable = false) { mockClassType("org/sample/Foo") }, - mockTAType("org/sample/FooAlias", nullable = false) { mockClassType("org/sample/Foo") }, - mockTAType("org/sample/FooAlias", nullable = true) { mockClassType("org/sample/Foo") } - ) - - @Test(expected = IllegalCommonizerStateException::class) - fun taTypesInUserPackageWithDifferentNullability2() = doTestFailure( - mockTAType("org/sample/FooAlias", nullable = true) { mockClassType("org/sample/Foo") }, - mockTAType("org/sample/FooAlias", nullable = true) { mockClassType("org/sample/Foo") }, - mockTAType("org/sample/FooAlias", nullable = false) { mockClassType("org/sample/Foo") }, - ) - - private fun prepareCache(variants: Array) { - check(variants.isNotEmpty()) - - fun recurse(type: CirClassOrTypeAliasType, index: Int) { - when (type) { - is CirClassType -> { - val node = classifiers.classNode(type.classifierId) { - buildClassNode( - storageManager = LockBasedStorageManager.NO_LOCKS, - size = variants.size, - classifiers = classifiers, - nodeRelationship = null, - classId = type.classifierId - ) + mockTAType("kotlin/FictitiousTypeAlias") { + mockTAType("kotlin/FictitiousTypeAliasL2") { + mockTAType("kotlin/FictitiousTypeAliasL3") { + mockClassType("kotlin/FictitiousClass") } - node.targetDeclarations[index] = CirClass.create( - annotations = emptyList(), - name = type.classifierId.relativeNameSegments.last(), - typeParameters = emptyList(), - supertypes = emptyList(), - visibility = Visibilities.Public, - modality = Modality.FINAL, - kind = ClassKind.CLASS, - companion = null, - isCompanion = false, - isData = false, - isValue = false, - isInner = false, - isExternal = false - ) - } - is CirTypeAliasType -> { - val node = classifiers.typeAliasNode(type.classifierId) { - buildTypeAliasNode( - storageManager = LockBasedStorageManager.NO_LOCKS, - size = variants.size, - classifiers = classifiers, - typeAliasId = type.classifierId - ) - } - node.targetDeclarations[index] = CirTypeAlias.create( - annotations = emptyList(), - name = type.classifierId.relativeNameSegments.last(), - typeParameters = emptyList(), - visibility = Visibilities.Public, - underlyingType = type.underlyingType, - expandedType = computeExpandedType(type.underlyingType) - ) - - recurse(type.underlyingType, index) // expand underlying types recursively } } - } - - variants.forEachIndexed { index, type -> - recurse(type, index) - } + ))) } - fun doTestSuccess(expected: CirClassOrTypeAliasType, vararg variants: CirClassOrTypeAliasType) { - prepareCache(variants) - super.doTestSuccess(expected, *variants) + fun `test multilevel ta types in user package with same name and right hand side class - 1`() { + val commonizer = createCommonizer( + targetASpecificSources = { + source( + """ + package org.sample + class F + typealias FAlias = F + """.trimIndent() + ) + }, + targetBSpecificSources = { + source( + """ + package org.sample + class F + typealias FAlias = F + """.trimIndent() + ) + }, + targetCSpecificSources = { + source( + """ + package org.sample + class F + typealias FAliasL2 = F + typealias FAlias = FAliasL2 + """.trimIndent() + ) + } + ) + assertEquals( + mockTAType("org/sample/FAlias") { + mockClassType("org/sample/F") + }, commonizer( + listOf( + mockTAType("org/sample/FAlias") { + mockClassType("org/sample/F") + }, + mockTAType("org/sample/FAlias") { + mockClassType("org/sample/F") + }, + mockTAType("org/sample/FAlias") { + mockTAType("org/sample/FAliasL2") { + mockClassType("org/sample/F") + } + }) + ) + ) } - fun doTestFailure(vararg variants: CirClassOrTypeAliasType, shouldFailOnFirstVariant: Boolean = false) { - prepareCache(variants) - super.doTestFailure(*variants, shouldFailOnFirstVariant = shouldFailOnFirstVariant) + fun `test multilevel ta types in user package with same name and right hand side class - 3`() { + val commonizer = createCommonizer( + commonTargetSources = { + source( + """ + package org.sample + class Foo + typealias FooAliasL2 = Foo + typealias FooAlias = FooAliasL2 + """.trimIndent() + ) + } + ) + assertEquals( + mockTAType("org/sample/FooAlias") { + mockTAType("org/sample/FooAliasL2") { + mockClassType("org/sample/Foo") + } + }, commonizer( + listOf( + mockTAType("org/sample/FooAlias") { + mockTAType("org/sample/FooAliasL2") { + mockClassType("org/sample/Foo") + } + }, + mockTAType("org/sample/FooAlias") { + mockTAType("org/sample/FooAliasL2") { + mockClassType("org/sample/Foo") + } + }, + + mockTAType("org/sample/FooAlias") { + mockTAType("org/sample/FooAliasL2") { + mockClassType("org/sample/Foo") + } + }) + ) + ) } - override fun createCommonizer() = TypeCommonizer(classifiers).asCommonizer() + fun `test ta types in Kotlin package with different nullability`() { + val commonizer = createCommonizer( + targetADependencySources = { + source( + """ + package kotlin.sequences + class SequenceScope + typealias SequenceBuilder = SequenceScope + """.trimIndent() + ) + }, + targetBDependencySources = { + source( + """ + package kotlin.sequences + class SequenceScope + typealias SequenceBuilder = SequenceScope + """.trimIndent() + ) + }, + targetCDependencySources = { + source( + """ + package kotlin.sequences + class SequenceScope + typealias SequenceBuilder = SequenceScope? + """.trimIndent() + ) + } + ) + assertEquals(null, commonizer(listOf( + mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope", nullable = false) }, + mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope", nullable = false) }, + mockTAType("kotlin/sequences/SequenceBuilder") { mockClassType("kotlin/sequences/SequenceScope", nullable = true) } + ))) + } + + fun `test ta types in user package with same nullability`() { + val commonizer = createCommonizer( + commonTargetSources = { + source( + """ + package org.sample + class Foo + typealias FooAlias = Foo? + """.trimIndent() + ) + } + ) + assertEquals(mockTAType("org/sample/FooAlias", nullable = true) { mockClassType("org/sample/Foo") }, commonizer(listOf( + mockTAType("org/sample/FooAlias", nullable = true) { mockClassType("org/sample/Foo") }, + mockTAType("org/sample/FooAlias", nullable = true) { mockClassType("org/sample/Foo") }, + mockTAType("org/sample/FooAlias", nullable = true) { mockClassType("org/sample/Foo") } + ))) + } - override fun areEqual(a: CirType?, b: CirType?) = (a === b) || (a != null && b != null && areEqual(classifiers, a, b)) companion object { fun areEqual(classifiers: CirKnownClassifiers, a: CirType, b: CirType): Boolean = - TypeCommonizer(classifiers).asCommonizer().run { commonizeWith(a) && commonizeWith(b) } - - private fun CirKnownClassifiers.classNode(classId: CirEntityId, computation: () -> CirClassNode) = - commonizedNodes.classNode(classId) ?: computation() - - private fun CirKnownClassifiers.typeAliasNode(typeAliasId: CirEntityId, computation: () -> CirTypeAliasNode) = - commonizedNodes.typeAliasNode(typeAliasId) ?: computation() + TypeCommonizer(classifiers).invoke(listOf(a, b)) != null } } + diff --git a/native/commonizer/tests/org/jetbrains/kotlin/commonizer/utils/InlineSourceBuilder.kt b/native/commonizer/tests/org/jetbrains/kotlin/commonizer/utils/InlineSourceBuilder.kt index a23cb950cfe..37fa93ff7bc 100644 --- a/native/commonizer/tests/org/jetbrains/kotlin/commonizer/utils/InlineSourceBuilder.kt +++ b/native/commonizer/tests/org/jetbrains/kotlin/commonizer/utils/InlineSourceBuilder.kt @@ -114,3 +114,12 @@ fun InlineSourceBuilder.createCirProvidedClassifiers(module: InlineSourceBuilder return CirProvidedClassifiersByModules.load(modulesProvider) } +@InlineSourceBuilder.ModuleBuilderDsl +fun InlineSourceBuilder.createCirProvidedClassifiers(builder: InlineSourceBuilder.ModuleBuilder.() -> Unit): CirProvidedClassifiers { + return createCirProvidedClassifiers(createModule { builder() }) +} + +@InlineSourceBuilder.ModuleBuilderDsl +fun InlineSourceBuilder.createCirProvidedClassifiersFromSourceCode(@Language("kotlin") sourceCode: String): CirProvidedClassifiers { + return createCirProvidedClassifiers(createModule { source(sourceCode) }) +} \ No newline at end of file