From 68e7476765bf66f5929fc2afbc1f334df1ef83cf Mon Sep 17 00:00:00 2001 From: "sebastian.sellmair" Date: Fri, 13 Aug 2021 11:52:30 +0200 Subject: [PATCH] [Commonizer] ClassSuperTypeCommonizer: Don't find consumed TypeNodes This commit will also add some simple documentation to this class and its implementation. ^KT-47430 --- .../core/ClassSuperTypeCommonizer.kt | 66 +++++++++++++++++-- .../commonized/common/package_root.kt | 2 +- 2 files changed, 61 insertions(+), 7 deletions(-) diff --git a/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/ClassSuperTypeCommonizer.kt b/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/ClassSuperTypeCommonizer.kt index f434cdb64ae..37b0a4bb0f4 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/ClassSuperTypeCommonizer.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/ClassSuperTypeCommonizer.kt @@ -16,11 +16,33 @@ import org.jetbrains.kotlin.commonizer.mergedtree.findClass import org.jetbrains.kotlin.commonizer.util.transitiveClosure import org.jetbrains.kotlin.descriptors.ClassKind -typealias Supertypes = List +private typealias Supertypes = List +/** + * Using the [TypeCommonizer] on all supertypes to find the list of common supertypes across + * all platforms. This commonizer will also resolve all transitive supertypes to find potential common supertypes. + * + * ``` + * // dependencies + * interface A + * interface B: A + * + * // target A + * class X: A + * + * // target B + * class X: B + * + * ``` + * + * will commonize to + * ``` + * class X: A // <- common supertype + * ``` + */ internal class ClassSuperTypeCommonizer( private val classifiers: CirKnownClassifiers -) : SingleInvocationCommonizer> { +) : SingleInvocationCommonizer { private val typeCommonizer = TypeCommonizer(classifiers) @@ -36,6 +58,28 @@ internal class ClassSuperTypeCommonizer( } } + /** + * For every supertype listed in [values] a full [SupertypesTree] will be resolved. + * This tree represents the supertype-hierarchy: + * + * ``` + * interface A + * interface B: A + * interface C: B, A + * ``` + * + * will become a tree like + * ``` + * C + * |\ + * | \ + * B A + * | + * A + * + * ``` + * + */ private fun resolveSupertypesTree(values: List): List { return values.mapIndexed { index: Int, supertypes: Supertypes -> val classifierIndex = classifiers.classifierIndices[index] @@ -45,12 +89,22 @@ internal class ClassSuperTypeCommonizer( } } + /** + * Builds [SupertypesGroup] (a group representing one type for every platform) that will be enqueued for type commonization. + * To find out which types shall be grouped this implementation will go through every single node in all trees (BFS!) + * If a certain type can be found on all other platforms, then a group is build. + * This types and all transitively "covered" supertypes will be marked as 'consumed' and therefore will be 'effectively removed' + * from the tree. + * + * This grouping implementation will also be very careful about *not* grouping two groups that could effectively + * represent a 'ClassKind' (to avoid commonizing with two abstract class supertypes) + */ private fun buildSupertypesGroups(trees: List): List { val groups = mutableListOf() var allowClassTypes = true trees.flatMap { tree -> tree.allNodes }.forEach { node -> - if (node.assignedGroup != null) return@forEach + if (node.isConsumed) return@forEach val candidateGroup = buildTypeGroup(trees, node.type.classifierId) ?: return@forEach if (containsAnyClassKind(candidateGroup)) { if (!allowClassTypes) return@forEach @@ -87,7 +141,7 @@ internal class ClassSuperTypeCommonizer( group.nodes.forEach { rootNode -> rootNode.allNodes.forEach { visitingNode -> if (visitingNode.type.classifierId in coveredClassifierIds) { - visitingNode.assignedGroup = group + visitingNode.isConsumed = true } } } @@ -95,7 +149,7 @@ internal class ClassSuperTypeCommonizer( private fun buildTypeGroup(trees: List, classifierId: CirEntityId): SupertypesGroup? { val nodes = trees.map { otherTree: SupertypesTree -> - otherTree.allNodes.find { otherNode -> otherNode.type.classifierId == classifierId } ?: return null + otherTree.allNodes.find { otherNode -> otherNode.type.classifierId == classifierId && !otherNode.isConsumed } ?: return null } return SupertypesGroup(classifierId, nodes) } @@ -133,7 +187,7 @@ private class TypeNode( val index: CirClassifierIndex, val type: CirClassType, val supertypes: List, - var assignedGroup: SupertypesGroup? = null + var isConsumed: Boolean = false ) { val allNodes: List by lazy { val allSupertypes = transitiveClosure(this, TypeNode::supertypes) diff --git a/native/commonizer/testData/classifierCommonization/supertypes/commonized/common/package_root.kt b/native/commonizer/testData/classifierCommonization/supertypes/commonized/common/package_root.kt index f9886bfc36d..8628310459f 100644 --- a/native/commonizer/testData/classifierCommonization/supertypes/commonized/common/package_root.kt +++ b/native/commonizer/testData/classifierCommonization/supertypes/commonized/common/package_root.kt @@ -8,7 +8,7 @@ expect abstract class A2() : A1 { abstract fun function2(): Int } -expect class A3() : A2, A1 { +expect class A3() : A2 { override val property1: Int override val property2: Int val property3: Int