diff --git a/native/commonizer/src/org/jetbrains/kotlin/commonizer/facade.kt b/native/commonizer/src/org/jetbrains/kotlin/commonizer/facade.kt index 480bfad8862..d38c6dece9f 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/commonizer/facade.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/commonizer/facade.kt @@ -14,6 +14,8 @@ import org.jetbrains.kotlin.commonizer.mergedtree.CirKnownClassifiers import org.jetbrains.kotlin.commonizer.mergedtree.CirNode.Companion.indexOfCommon import org.jetbrains.kotlin.commonizer.mergedtree.CirRootNode import org.jetbrains.kotlin.commonizer.metadata.CirTreeSerializer +import org.jetbrains.kotlin.commonizer.transformer.CirAliasTypeSubstitutor +import org.jetbrains.kotlin.commonizer.transformer.CirUnderscoredTypeAliasSubstitutor import org.jetbrains.kotlin.commonizer.transformer.InlineTypeAliasCirNodeTransformer import org.jetbrains.kotlin.commonizer.transformer.TypeSubstitutionCirNodeTransformer import org.jetbrains.kotlin.commonizer.tree.CirTreeRoot @@ -62,7 +64,16 @@ internal fun commonizeTarget( val mergedTree = mergeCirTree(parameters.storageManager, classifiers, availableTrees) InlineTypeAliasCirNodeTransformer(parameters.storageManager, classifiers).invoke(mergedTree) - TypeSubstitutionCirNodeTransformer(parameters.storageManager, classifiers).invoke(mergedTree) + + TypeSubstitutionCirNodeTransformer( + parameters.storageManager, classifiers, + CirAliasTypeSubstitutor(classifiers.commonDependencies, classifiers.classifierIndices) + ).invoke(mergedTree) + + TypeSubstitutionCirNodeTransformer( + parameters.storageManager, classifiers, + CirUnderscoredTypeAliasSubstitutor(classifiers.classifierIndices) + ).invoke(mergedTree) mergedTree.accept(CommonizationVisitor(classifiers, mergedTree), Unit) diff --git a/native/commonizer/src/org/jetbrains/kotlin/commonizer/transformer/CirUnderscoredTypeAliasSubstitutor.kt b/native/commonizer/src/org/jetbrains/kotlin/commonizer/transformer/CirUnderscoredTypeAliasSubstitutor.kt new file mode 100644 index 00000000000..42bd0d82e4f --- /dev/null +++ b/native/commonizer/src/org/jetbrains/kotlin/commonizer/transformer/CirUnderscoredTypeAliasSubstitutor.kt @@ -0,0 +1,63 @@ +/* + * 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.transformer + +import org.jetbrains.kotlin.commonizer.TargetDependent +import org.jetbrains.kotlin.commonizer.cir.CirEntityId +import org.jetbrains.kotlin.commonizer.cir.CirName +import org.jetbrains.kotlin.commonizer.cir.CirType +import org.jetbrains.kotlin.commonizer.cir.CirTypeAliasType +import org.jetbrains.kotlin.commonizer.core.expandedType +import org.jetbrains.kotlin.commonizer.mergedtree.CirClassifierIndex +import org.jetbrains.kotlin.commonizer.mergedtree.CirTypeSubstitutor +import org.jetbrains.kotlin.commonizer.mergedtree.findTypeAlias + +/** + * Explicitly substitute [CirTypeAliasType]s whose classifier name is prefixed with a double underscore: "__" + * with a type using a classifier without the prefix if + * 1) Such a TypeAlias exists on the platform + * 2) Such a TypeAlias expands to the same type + * + * Example from platform.posix.mkdir: + * This function uses the following parameter: + * linux: `platform/posix/__mode_t -> kotlin/UInt` + * apple: `platform/posix/mode_t -> platform/posix/__darwin_mode_t -> platform/posix/__uint16_t -> kotlin/UShort` + * + * However, on linux a corresponding type alias + * `platform/posix/mode_t -> platform/posix/__mode_t -> kotlin/UInt` + * exists which is preferable + */ +internal class CirUnderscoredTypeAliasSubstitutor( + private val classifierIndices: TargetDependent +) : CirTypeSubstitutor { + + override fun substitute(targetIndex: Int, type: CirType): CirType { + if (type !is CirTypeAliasType) return type + + /* TypeAliases cannot be nested and therefore are expected to have only a single name segment */ + val name = type.classifierId.relativeNameSegments.singleOrNull() ?: return type + if (!name.name.startsWith("__")) return type + + /* Argument substitution not implemented. No real world cases known that would benefit */ + if (type.arguments.isNotEmpty()) return type + + val preferredClassifierId = CirEntityId.create( + type.classifierId.packageName, + CirName.create(name.name.removePrefix("__")) + ) + + val preferredTypeAlias = classifierIndices[targetIndex].findTypeAlias(preferredClassifierId) ?: return type + val expandedType = type.expandedType() + if (preferredTypeAlias.expandedType != expandedType) return type + + return CirTypeAliasType.createInterned( + typeAliasId = preferredClassifierId, + underlyingType = preferredTypeAlias.underlyingType, + arguments = emptyList(), + isMarkedNullable = expandedType.isMarkedNullable + ) + } +} diff --git a/native/commonizer/src/org/jetbrains/kotlin/commonizer/transformer/TypeSubstitutionCirNodeTransformer.kt b/native/commonizer/src/org/jetbrains/kotlin/commonizer/transformer/TypeSubstitutionCirNodeTransformer.kt index cba05d99921..f4ec3645359 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/commonizer/transformer/TypeSubstitutionCirNodeTransformer.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/commonizer/transformer/TypeSubstitutionCirNodeTransformer.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.commonizer.transformer import org.jetbrains.kotlin.commonizer.mergedtree.* import org.jetbrains.kotlin.commonizer.mergedtree.CirNodeRelationship.ParentNode -import org.jetbrains.kotlin.commonizer.tree.CirTreeRoot import org.jetbrains.kotlin.storage.StorageManager internal class TypeSubstitutionCirNodeTransformer( @@ -16,12 +15,6 @@ internal class TypeSubstitutionCirNodeTransformer( private val typeSubstitutor: CirTypeSubstitutor ) : CirNodeTransformer { - constructor(storageManager: StorageManager, classifiers: CirKnownClassifiers) : this( - storageManager = storageManager, - classifiers = classifiers, - typeSubstitutor = CirAliasTypeSubstitutor(classifiers.commonDependencies, classifiers.classifierIndices) - ) - override fun invoke(root: CirRootNode) { for (index in 0 until root.targetDeclarations.size) { root.modules.forEach { (_, module) -> this(module, index) } diff --git a/native/commonizer/tests/org/jetbrains/kotlin/commonizer/transformer/CirUnderscoredTypeAliasSubstitutorTest.kt b/native/commonizer/tests/org/jetbrains/kotlin/commonizer/transformer/CirUnderscoredTypeAliasSubstitutorTest.kt new file mode 100644 index 00000000000..928f0a38817 --- /dev/null +++ b/native/commonizer/tests/org/jetbrains/kotlin/commonizer/transformer/CirUnderscoredTypeAliasSubstitutorTest.kt @@ -0,0 +1,127 @@ +/* + * 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.transformer + +import org.jetbrains.kotlin.commonizer.AbstractInlineSourcesCommonizationTest +import org.jetbrains.kotlin.commonizer.assertCommonized + +class CirUnderscoredTypeAliasSubstitutorTest : AbstractInlineSourcesCommonizationTest() { + + fun `test inlined underscored typealias - single platform`() { + val result = commonize { + outputTarget("(a, b)") + simpleSingleSourceTarget( + "a", """ + typealias X = Int + typealias __X = X + fun x(x: __X) + """.trimIndent() + ) + + simpleSingleSourceTarget( + "b", """ + typealias X = Int + fun x(x: X) + """.trimIndent() + ) + } + + result.assertCommonized( + "(a, b)", """ + typealias X = Int + expect fun x(x: X) + """.trimIndent() + ) + } + + fun `test inlined underscored typealias - both platforms`() { + val result = commonize { + outputTarget("(a, b)") + simpleSingleSourceTarget( + "a", """ + typealias X = Int + typealias __X = X + fun x(x: __X) + """.trimIndent() + ) + + simpleSingleSourceTarget( + "b", """ + typealias X = Int + typealias __X = X + fun x(x: X) + """.trimIndent() + ) + } + + result.assertCommonized( + "(a, b)", """ + typealias X = Int + typealias __X = X + expect fun x(x: X) + """.trimIndent() + ) + } + + fun `test inlined underscored typealias - both platforms - not used in signature`() { + val result = commonize { + outputTarget("(a, b)") + simpleSingleSourceTarget( + "a", """ + typealias X = Int + typealias __X = X + fun x(x: X) + """.trimIndent() + ) + + simpleSingleSourceTarget( + "b", """ + typealias X = Int + typealias __X = X + fun x(x: X) + """.trimIndent() + ) + } + + result.assertCommonized( + "(a, b)", """ + typealias X = Int + typealias __X = X + expect fun x(x: X) + """.trimIndent() + ) + } + + + fun `test inlined underscored typealias - both platforms - underscore used in both signatures`() { + val result = commonize { + outputTarget("(a, b)") + simpleSingleSourceTarget( + "a", """ + typealias X = Int + typealias __X = X + fun x(x: __X) + """.trimIndent() + ) + + simpleSingleSourceTarget( + "b", """ + typealias X = Int + typealias __X = X + fun x(x: __X) + """.trimIndent() + ) + } + + result.assertCommonized( + "(a, b)", """ + typealias X = Int + typealias __X = X + expect fun x(x: __X) + """.trimIndent() + ) + } +} \ No newline at end of file