[Commonizer] Remove old implementations for type commonization

Removed AliasedTypeSubstitutor: Covered by ClassOrTypeAliasTypeCommonizer
Removed ClassTypeCommonizer: Covered by ClassOrTypeAliasTypeCommonizer
Removed type alias substitution transformers: Covered by CirCommonClassifierId

^KT-48288
This commit is contained in:
sebastian.sellmair
2021-09-10 11:52:03 +02:00
committed by Space
parent bfa433fa06
commit 5c7ac614ce
5 changed files with 0 additions and 443 deletions
@@ -1,66 +0,0 @@
/*
* 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.commonizer.utils.singleDistinctValueOrNull
class ClassTypeCommonizer internal constructor(
private val classifiers: CirKnownClassifiers,
private val typeCommonizer: TypeCommonizer,
private val isMarkedNullableCommonizer: TypeNullabilityCommonizer
) : NullableSingleInvocationCommonizer<CirClassType> {
override fun invoke(values: List<CirClassType>): CirClassType? {
if (values.isEmpty()) return null
val classId = values.singleDistinctValueOrNull { it.classifierId } ?: return null
val isMarkedNullable = isMarkedNullableCommonizer.commonize(values.map { it.isMarkedNullable }) ?: return null
if (values.any { !isClassifierAvailableInCommon(classifiers, it.classifierId) }) {
return null
}
val outerType = if (values.all { it.outerType == null }) null
else if (values.any { it.outerType == null }) return null
else invoke(values.map { checkNotNull(it.outerType) }) ?: return null
// Commonizer is stateful: Needs to be created per invocation!
val arguments = TypeArgumentListCommonizer(typeCommonizer).commonize(values.map { it.arguments }) ?: return null
return CirClassType.createInterned(
classId = classId,
outerType = outerType,
// 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 = values.first().visibility,
arguments = arguments,
isMarkedNullable = isMarkedNullable
)
}
}
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
}
@@ -1,138 +0,0 @@
/*
* 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 typeCommonizer: TypeCommonizer,
private val classifiers: CirKnownClassifiers,
) : AbstractStandardCommonizer<CirTypeAliasType, CirClassOrTypeAliasType>() {
private lateinit var typeAliasId: CirEntityId
private val arguments = TypeArgumentListCommonizer(typeCommonizer)
private val underlyingTypeArguments = TypeArgumentListCommonizer(typeCommonizer)
private val isMarkedNullable = TypeNullabilityCommonizer(typeCommonizer.options).asCommonizer()
private var commonizedTypeBuilder: CommonizedTypeAliasTypeBuilder? = null // null means not selected yet
override fun commonizationResult() =
(commonizedTypeBuilder ?: failInEmptyState()).build(
typeAliasId = typeAliasId,
arguments = arguments.result,
underlyingTypeArguments = underlyingTypeArguments.result,
isMarkedNullable = isMarkedNullable.result
)
override fun initialize(first: CirTypeAliasType) {
typeAliasId = first.classifierId
}
override fun doCommonizeWith(next: CirTypeAliasType): Boolean {
if (typeAliasId != next.classifierId) return false
if (!isMarkedNullable.commonizeWith(next.expandedType().isMarkedNullable)) 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, typeCommonizer, next.underlyingType) ?: return false
CommonizedTypeAliasTypeBuilder.forKnownUnderlyingType(underlyingType)
}
else -> error("Unexpected common classifier type: ${commonClassifier::class.java}, $commonClassifier")
}
}
return arguments.commonizeWith(next.arguments) &&
underlyingTypeArguments.commonizeWith(next.underlyingType.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<CirTypeProjection>,
underlyingTypeArguments: List<CirTypeProjection>,
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<CirTypeProjection>,
underlyingTypeArguments: List<CirTypeProjection>,
isMarkedNullable: Boolean
) = CirClassType.createInterned(
classId = typeAliasId,
outerType = null, // there can't be outer type
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<CirTypeProjection>,
underlyingTypeArguments: List<CirTypeProjection>,
isMarkedNullable: Boolean
): CirTypeAliasType {
val underlyingTypeWithProperNullability = underlyingType
.makeNullableIfNecessary(isMarkedNullable)
.withArguments(underlyingTypeArguments)
return CirTypeAliasType.createInterned(
typeAliasId = typeAliasId,
underlyingType = underlyingTypeWithProperNullability,
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
}
}
@@ -1,109 +0,0 @@
/*
* 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.*
import org.jetbrains.kotlin.commonizer.cir.CirClassType.Companion.copyInterned
import org.jetbrains.kotlin.commonizer.cir.CirTypeAliasType.Companion.copyInterned
import org.jetbrains.kotlin.commonizer.mergedtree.CirClassifierIndex
import org.jetbrains.kotlin.commonizer.mergedtree.CirProvidedClassifiers
import org.jetbrains.kotlin.commonizer.mergedtree.CirTypeSubstitutor
import org.jetbrains.kotlin.commonizer.tree.CirTreeTypeAlias
internal class AliasedTypeSubstitutor(
private val commonDependencies: CirProvidedClassifiers,
private val classifierIndices: TargetDependent<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
if (isCommon(type.classifierId)) return type
val classifierIndex = classifierIndices[targetIndex]
val typeAliases = classifierIndex.findTypeAliasesWithUnderlyingType(type.classifierId)
val commonTypeAlias = findSuitableCommonTypeAlias(classifierIndex, typeAliases) ?: return type
return CirTypeAliasType.createInterned(
typeAliasId = commonTypeAlias.id,
underlyingType = commonTypeAlias.typeAlias.underlyingType,
arguments = emptyList(),
isMarkedNullable = type.isMarkedNullable
)
}
private tailrec fun findSuitableCommonTypeAlias(
index: CirClassifierIndex,
typeAliases: List<CirTreeTypeAlias>
): CirTreeTypeAlias? {
if (typeAliases.isEmpty()) return null
val commonTypeAlias = typeAliases.firstOrNull { (id, typeAlias) -> typeAlias.typeParameters.isEmpty() && isCommon(id) }
if (commonTypeAlias != null) {
return commonTypeAlias
}
return findSuitableCommonTypeAlias(
index, typeAliases.flatMap { (id, _) -> index.findTypeAliasesWithUnderlyingType(id) }
)
}
private fun isCommon(id: CirEntityId): Boolean =
commonDependencies.hasClassifier(id) || classifierIndices.all { index -> id in index.allClassifierIds }
}
@@ -1,71 +0,0 @@
/*
* 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.mergedtree.*
import org.jetbrains.kotlin.commonizer.mergedtree.CirNodeRelationship.ParentNode
import org.jetbrains.kotlin.commonizer.utils.fastForEach
import org.jetbrains.kotlin.storage.StorageManager
internal class TypeSubstitutionCirNodeTransformer(
private val storageManager: StorageManager,
private val classifiers: CirKnownClassifiers,
private val typeSubstitutor: CirTypeSubstitutor,
) : CirNodeTransformer {
private val commonClassifierIdResolver = classifiers.commonClassifierIdResolver
override fun invoke(root: CirRootNode) {
for (index in 0 until root.targetDeclarations.size) {
root.modules.forEach { (_, module) -> this(module, index) }
}
}
private operator fun invoke(module: CirModuleNode, index: Int) {
module.packages.forEach { (_, pkg) -> this(pkg, index) }
}
private operator fun invoke(pkg: CirPackageNode, index: Int) {
pkg.functions.values.toTypedArray().fastForEach { function -> this(pkg, function, index, CirMemberContext.empty) }
pkg.properties.values.toTypedArray().fastForEach { property -> this(pkg, property, index, CirMemberContext.empty) }
pkg.classes.values.toTypedArray().fastForEach { clazz -> this(clazz, index, CirMemberContext.empty) }
}
private operator fun invoke(clazz: CirClassNode, index: Int, context: CirMemberContext) {
val contextWithClass = context.withContextOf(clazz.targetDeclarations[index] ?: return)
clazz.functions.values.toTypedArray().fastForEach { function -> this(clazz, function, index, contextWithClass) }
clazz.properties.values.toTypedArray().fastForEach { property -> this(clazz, property, index, contextWithClass) }
clazz.classes.values.toTypedArray().fastForEach { innerClass -> this(innerClass, index, contextWithClass) }
}
private operator fun invoke(parent: CirNodeWithMembers<*, *>, function: CirFunctionNode, index: Int, context: CirMemberContext) {
/* Only perform type substitution to nodes that are not 'complete' */
if (function.targetDeclarations.none { it == null }) return
val originalFunction = function.targetDeclarations[index] ?: return
val newFunction = typeSubstitutor.substitute(index, originalFunction)
if (originalFunction == newFunction) return
val approximationKey = FunctionApproximationKey.create(context, commonClassifierIdResolver, newFunction)
val newNode = parent.functions.getOrPut(approximationKey) {
buildFunctionNode(storageManager, parent.targetDeclarations.size, classifiers, ParentNode(parent))
}
newNode.targetDeclarations.setAllowingOverride(index, newFunction)
}
private operator fun invoke(parent: CirNodeWithMembers<*, *>, property: CirPropertyNode, index: Int, context: CirMemberContext) {
val originalProperty = property.targetDeclarations[index] ?: return
val newProperty = typeSubstitutor.substitute(index, originalProperty)
if (originalProperty == newProperty) return
val approximationKey = PropertyApproximationKey.create(context, commonClassifierIdResolver, newProperty)
val newNode = parent.properties.getOrPut(approximationKey) {
buildPropertyNode(storageManager, parent.targetDeclarations.size, classifiers, ParentNode(parent))
}
newNode.targetDeclarations.setAllowingOverride(index, newProperty)
}
}
@@ -1,59 +0,0 @@
/*
* 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.*
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 UnderscoredTypeAliasTypeSubstitutor(
private val classifierIndices: TargetDependent<CirClassifierIndex>
) : 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
)
}
}