diff --git a/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/ClassTypeCommonizer.kt b/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/ClassTypeCommonizer.kt new file mode 100644 index 00000000000..2ca609bf4c9 --- /dev/null +++ b/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/ClassTypeCommonizer.kt @@ -0,0 +1,71 @@ +/* + * 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 +import org.jetbrains.kotlin.commonizer.mergedtree.CirKnownClassifiers +import org.jetbrains.kotlin.commonizer.utils.isUnderKotlinNativeSyntheticPackages +import org.jetbrains.kotlin.descriptors.Visibility + +internal class ClassTypeCommonizer(private val classifiers: CirKnownClassifiers) : + AbstractStandardCommonizer() { + private lateinit var classId: CirEntityId + private val outerType = OuterClassTypeCommonizer(classifiers) + private lateinit var anyVisibility: Visibility + private val arguments = TypeArgumentListCommonizer(classifiers) + private var isMarkedNullable = false + + override fun commonizationResult() = CirClassType.createInterned( + classId = classId, + outerType = outerType.result, + // N.B. The 'visibility' field in class types is needed ONLY for TA commonization. The class type constructed here is + // intended to be used in "common" target. It could not participate in TA commonization. So, it does not matter which + // exactly visibility will be recorded for commonized class type. Passing the visibility of the first class type + // to reach better interning rate. + visibility = anyVisibility, + arguments = arguments.result, + isMarkedNullable = isMarkedNullable + ) + + override fun initialize(first: CirClassType) { + classId = first.classifierId + anyVisibility = first.visibility + isMarkedNullable = first.isMarkedNullable + } + + override fun doCommonizeWith(next: CirClassType) = + isMarkedNullable == next.isMarkedNullable + && classId == next.classifierId + && outerType.commonizeWith(next.outerType) + && isClassifierAvailableInCommon(classifiers, classId) + && arguments.commonizeWith(next.arguments) +} + +private fun isClassifierAvailableInCommon(classifiers: CirKnownClassifiers, classId: CirEntityId): Boolean { + if (classifiers.commonDependencies.hasClassifier(classId)) { + // The class is from common fragment of dependency library (ex: stdlib). Already commonized. + return true + } else if (classId.packageName.isUnderKotlinNativeSyntheticPackages) { + // C/Obj-C forward declarations are: + // - Either resolved to real classes/interfaces from other interop libraries (which are generated by C-interop tool and + // are known to have modality/visibility/other attributes to successfully pass commonization). + // - Or resolved to the same synthetic classes/interfaces. + // ... and therefore are considered as successfully commonized. + return true + } + + // Looking for a a node that provides a non-null (successfully commonized) classifier declaration + return (classifiers.commonizedNodes.classNode(classId)?.commonDeclaration?.invoke() + ?: classifiers.commonizedNodes.typeAliasNode(classId)?.commonDeclaration?.invoke()) != null +} + +private class OuterClassTypeCommonizer(classifiers: CirKnownClassifiers) : + AbstractNullableCommonizer( + wrappedCommonizerFactory = { ClassTypeCommonizer(classifiers) }, + extractor = { it }, + builder = { it } + ) diff --git a/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/TypeAliasTypeCommonizer.kt b/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/TypeAliasTypeCommonizer.kt new file mode 100644 index 00000000000..660f56be4e8 --- /dev/null +++ b/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/TypeAliasTypeCommonizer.kt @@ -0,0 +1,121 @@ +/* + * 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.* +import org.jetbrains.kotlin.commonizer.core.CommonizedTypeAliasAnswer.Companion.FAILURE_MISSING_IN_SOME_TARGET +import org.jetbrains.kotlin.commonizer.core.CommonizedTypeAliasAnswer.Companion.SUCCESS_FROM_DEPENDENCY_LIBRARY +import org.jetbrains.kotlin.commonizer.mergedtree.CirKnownClassifiers + +internal class TypeAliasTypeCommonizer(private val classifiers: CirKnownClassifiers) : + AbstractStandardCommonizer() { + + private lateinit var typeAliasId: CirEntityId + private val arguments = TypeArgumentListCommonizer(classifiers) + private var isMarkedNullable = false + private var commonizedTypeBuilder: CommonizedTypeAliasTypeBuilder? = null // null means not selected yet + + override fun commonizationResult() = + (commonizedTypeBuilder ?: failInEmptyState()).build( + typeAliasId = typeAliasId, + arguments = arguments.result, + isMarkedNullable = isMarkedNullable + ) + + override fun initialize(first: CirTypeAliasType) { + typeAliasId = first.classifierId + isMarkedNullable = first.expandedType().isMarkedNullable + } + + override fun doCommonizeWith(next: CirTypeAliasType): Boolean { + if (isMarkedNullable != next.expandedType().isMarkedNullable || typeAliasId != next.classifierId) + return false + + if (commonizedTypeBuilder == null) { + val answer = commonizeTypeAlias(typeAliasId, classifiers) + if (!answer.isCommon) + return false + + commonizedTypeBuilder = when (val commonClassifier = answer.commonClassifier) { + is CirClass -> CommonizedTypeAliasTypeBuilder.forClass(commonClassifier) + is CirTypeAlias -> CommonizedTypeAliasTypeBuilder.forTypeAlias(commonClassifier) + null -> { + val underlyingType = computeSuitableUnderlyingType(classifiers, next.underlyingType) ?: return false + CommonizedTypeAliasTypeBuilder.forKnownUnderlyingType(underlyingType) + } + else -> error("Unexpected common classifier type: ${commonClassifier::class.java}, $commonClassifier") + } + } + + return arguments.commonizeWith(next.arguments) + } + + // builds a new type for "common" library fragment for the given combination of type alias types in "platform" fragments + internal interface CommonizedTypeAliasTypeBuilder { + fun build(typeAliasId: CirEntityId, arguments: List, isMarkedNullable: Boolean): CirClassOrTypeAliasType + + companion object { + // type alias has been commonized to expect class, need to build type for expect class + fun forClass(commonClass: CirClass) = object : CommonizedTypeAliasTypeBuilder { + override fun build(typeAliasId: CirEntityId, arguments: List, isMarkedNullable: Boolean) = + CirClassType.createInterned( + classId = typeAliasId, + outerType = null, // there can't be outer type // TODO NOW!!! + visibility = commonClass.visibility, + arguments = arguments, + isMarkedNullable = isMarkedNullable + ) + } + + // type alias has been commonized to another type alias with the different underlying type, need to build type for + // new type alias + fun forTypeAlias(modifiedTypeAlias: CirTypeAlias) = forKnownUnderlyingType(modifiedTypeAlias.underlyingType) + + // type alias don't needs to be commonized because it is from the standard library + fun forKnownUnderlyingType(underlyingType: CirClassOrTypeAliasType) = object : CommonizedTypeAliasTypeBuilder { + override fun build( + typeAliasId: CirEntityId, + arguments: List, + isMarkedNullable: Boolean + ): CirTypeAliasType { + val underlyingTypeWithProperNullability = underlyingType.makeNullableIfNecessary(isMarkedNullable) + return CirTypeAliasType.createInterned( + typeAliasId = typeAliasId, + underlyingType = underlyingTypeWithProperNullability, // TODO replace arguments??? + arguments = arguments, + isMarkedNullable = isMarkedNullable + ) + } + } + } + } +} + +private fun commonizeTypeAlias(typeAliasId: CirEntityId, classifiers: CirKnownClassifiers): CommonizedTypeAliasAnswer { + if (classifiers.commonDependencies.hasClassifier(typeAliasId)) { + // The type alias is from common fragment of dependency library (ex: stdlib). Already commonized. + return SUCCESS_FROM_DEPENDENCY_LIBRARY + } + + val typeAliasNode = classifiers.commonizedNodes.typeAliasNode(typeAliasId) + val classNode = classifiers.commonizedNodes.classNode(typeAliasId) + + if (typeAliasNode == null && classNode == null) { + return FAILURE_MISSING_IN_SOME_TARGET + } + + return CommonizedTypeAliasAnswer.create(typeAliasNode?.commonDeclaration?.invoke() ?: classNode?.commonDeclaration?.invoke()) +} + +private class CommonizedTypeAliasAnswer(val isCommon: Boolean, val commonClassifier: CirClassifier?) { + companion object { + val SUCCESS_FROM_DEPENDENCY_LIBRARY = CommonizedTypeAliasAnswer(true, null) + val FAILURE_MISSING_IN_SOME_TARGET = CommonizedTypeAliasAnswer(false, null) + + fun create(commonClassifier: CirClassifier?) = + if (commonClassifier != null) CommonizedTypeAliasAnswer(true, commonClassifier) else FAILURE_MISSING_IN_SOME_TARGET + } +} diff --git a/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/TypeCommonizer.kt b/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/TypeCommonizer.kt index 695ad52a327..5161590d4dc 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/TypeCommonizer.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/TypeCommonizer.kt @@ -6,12 +6,7 @@ package org.jetbrains.kotlin.commonizer.core import org.jetbrains.kotlin.commonizer.cir.* -import org.jetbrains.kotlin.commonizer.core.CommonizedTypeAliasAnswer.Companion.FAILURE_MISSING_IN_SOME_TARGET -import org.jetbrains.kotlin.commonizer.core.CommonizedTypeAliasAnswer.Companion.SUCCESS_FROM_DEPENDENCY_LIBRARY -import org.jetbrains.kotlin.commonizer.core.CommonizedTypeAliasAnswer.Companion.create import org.jetbrains.kotlin.commonizer.mergedtree.CirKnownClassifiers -import org.jetbrains.kotlin.commonizer.utils.isUnderKotlinNativeSyntheticPackages -import org.jetbrains.kotlin.descriptors.Visibility class TypeCommonizer(private val classifiers: CirKnownClassifiers) : AbstractStandardCommonizer() { private lateinit var typeCommonizer: Commonizer<*, CirType> @@ -36,132 +31,6 @@ class TypeCommonizer(private val classifiers: CirKnownClassifiers) : AbstractSta } } -internal class ClassTypeCommonizer(private val classifiers: CirKnownClassifiers) : - AbstractStandardCommonizer() { - private lateinit var classId: CirEntityId - private val outerType = OuterClassTypeCommonizer(classifiers) - private lateinit var anyVisibility: Visibility - private val arguments = TypeArgumentListCommonizer(classifiers) - private var isMarkedNullable = false - - override fun commonizationResult() = CirClassType.createInterned( - classId = classId, - outerType = outerType.result, - // N.B. The 'visibility' field in class types is needed ONLY for TA commonization. The class type constructed here is - // intended to be used in "common" target. It could not participate in TA commonization. So, it does not matter which - // exactly visibility will be recorded for commonized class type. Passing the visibility of the first class type - // to reach better interning rate. - visibility = anyVisibility, - arguments = arguments.result, - isMarkedNullable = isMarkedNullable - ) - - override fun initialize(first: CirClassType) { - classId = first.classifierId - anyVisibility = first.visibility - isMarkedNullable = first.isMarkedNullable - } - - override fun doCommonizeWith(next: CirClassType) = - isMarkedNullable == next.isMarkedNullable - && classId == next.classifierId - && outerType.commonizeWith(next.outerType) - && commonizeClass(classId, classifiers) - && arguments.commonizeWith(next.arguments) -} - -// TODO NOW -internal class OuterClassTypeCommonizer(classifiers: CirKnownClassifiers) : - AbstractNullableCommonizer( - wrappedCommonizerFactory = { ClassTypeCommonizer(classifiers) }, - extractor = { it }, - builder = { it } - ) - -internal class TypeAliasTypeCommonizer(private val classifiers: CirKnownClassifiers) : - AbstractStandardCommonizer() { - - private lateinit var typeAliasId: CirEntityId - private val arguments = TypeArgumentListCommonizer(classifiers) - private var isMarkedNullable = false - private var commonizedTypeBuilder: CommonizedTypeAliasTypeBuilder? = null // null means not selected yet - - override fun commonizationResult() = - (commonizedTypeBuilder ?: failInEmptyState()).build( - typeAliasId = typeAliasId, - arguments = arguments.result, - isMarkedNullable = isMarkedNullable - ) - - override fun initialize(first: CirTypeAliasType) { - typeAliasId = first.classifierId - isMarkedNullable = first.expandedType().isMarkedNullable - } - - override fun doCommonizeWith(next: CirTypeAliasType): Boolean { - if (isMarkedNullable != next.expandedType().isMarkedNullable || typeAliasId != next.classifierId) - return false - - if (commonizedTypeBuilder == null) { - val answer = commonizeTypeAlias(typeAliasId, classifiers) - if (!answer.commonized) - return false - - commonizedTypeBuilder = when (val commonClassifier = answer.commonClassifier) { - is CirClass -> CommonizedTypeAliasTypeBuilder.forClass(commonClassifier) - is CirTypeAlias -> CommonizedTypeAliasTypeBuilder.forTypeAlias(commonClassifier) - null -> { - val underlyingType = computeSuitableUnderlyingType(classifiers, next.underlyingType) ?: return false - CommonizedTypeAliasTypeBuilder.forKnownUnderlyingType(underlyingType) - } - else -> error("Unexpected common classifier type: ${commonClassifier::class.java}, $commonClassifier") - } - } - - return arguments.commonizeWith(next.arguments) - } - - // builds a new type for "common" library fragment for the given combination of type alias types in "platform" fragments - internal interface CommonizedTypeAliasTypeBuilder { - fun build(typeAliasId: CirEntityId, arguments: List, isMarkedNullable: Boolean): CirClassOrTypeAliasType - - companion object { - // type alias has been commonized to expect class, need to build type for expect class - fun forClass(commonClass: CirClass) = object : CommonizedTypeAliasTypeBuilder { - override fun build(typeAliasId: CirEntityId, arguments: List, isMarkedNullable: Boolean) = - CirClassType.createInterned( - classId = typeAliasId, - outerType = null, // there can't be outer type // TODO NOW!!! - visibility = commonClass.visibility, - arguments = arguments, - isMarkedNullable = isMarkedNullable - ) - } - - // type alias has been commonized to another type alias with the different underlying type, need to build type for - // new type alias - fun forTypeAlias(modifiedTypeAlias: CirTypeAlias) = forKnownUnderlyingType(modifiedTypeAlias.underlyingType) - - // type alias don't needs to be commonized because it is from the standard library - fun forKnownUnderlyingType(underlyingType: CirClassOrTypeAliasType) = object : CommonizedTypeAliasTypeBuilder { - override fun build( - typeAliasId: CirEntityId, - arguments: List, - isMarkedNullable: Boolean - ): CirTypeAliasType { - val underlyingTypeWithProperNullability = underlyingType.makeNullableIfNecessary(isMarkedNullable) - return CirTypeAliasType.createInterned( - typeAliasId = typeAliasId, - underlyingType = underlyingTypeWithProperNullability, // TODO replace arguments??? - arguments = arguments, - isMarkedNullable = isMarkedNullable - ) - } - } - } - } -} - private class TypeParameterTypeCommonizer : AbstractStandardCommonizer() { private lateinit var temp: CirTypeParameterType @@ -192,47 +61,3 @@ private class FlexibleTypeCommonizer(classifiers: CirKnownClassifiers) : Abstrac override fun doCommonizeWith(next: CirFlexibleType) = lowerBound.commonizeWith(next.lowerBound) && upperBound.commonizeWith(next.upperBound) } - -private fun commonizeClass(classId: CirEntityId, classifiers: CirKnownClassifiers): Boolean { - if (classifiers.commonDependencies.hasClassifier(classId)) { - // The class is from common fragment of dependency library (ex: stdlib). Already commonized. - return true - } else if (classId.packageName.isUnderKotlinNativeSyntheticPackages) { - // C/Obj-C forward declarations are: - // - Either resolved to real classes/interfaces from other interop libraries (which are generated by C-interop tool and - // are known to have modality/visibility/other attributes to successfully pass commonization). - // - Or resolved to the same synthetic classes/interfaces. - // ... and therefore are considered as successfully commonized. - return true - } - - // Looking for a a node that provides a non-null (successfully commonized) classifier declaration - return (classifiers.commonizedNodes.classNode(classId)?.commonDeclaration?.invoke() - ?: classifiers.commonizedNodes.typeAliasNode(classId)?.commonDeclaration?.invoke()) != null -} - -private fun commonizeTypeAlias(typeAliasId: CirEntityId, classifiers: CirKnownClassifiers): CommonizedTypeAliasAnswer { - if (classifiers.commonDependencies.hasClassifier(typeAliasId)) { - // The type alias is from common fragment of dependency library (ex: stdlib). Already commonized. - return SUCCESS_FROM_DEPENDENCY_LIBRARY - } - - val typeAliasNode = classifiers.commonizedNodes.typeAliasNode(typeAliasId) - val classNode = classifiers.commonizedNodes.classNode(typeAliasId) - - if (typeAliasNode == null && classNode == null) { - return FAILURE_MISSING_IN_SOME_TARGET - } - - return create(typeAliasNode?.commonDeclaration?.invoke() ?: classNode?.commonDeclaration?.invoke()) -} - -internal class CommonizedTypeAliasAnswer(val commonized: Boolean, val commonClassifier: CirClassifier?) { - companion object { - val SUCCESS_FROM_DEPENDENCY_LIBRARY = CommonizedTypeAliasAnswer(true, null) - val FAILURE_MISSING_IN_SOME_TARGET = CommonizedTypeAliasAnswer(false, null) - - fun create(commonClassifier: CirClassifier?) = - if (commonClassifier != null) CommonizedTypeAliasAnswer(true, commonClassifier) else FAILURE_MISSING_IN_SOME_TARGET - } -}