[Commonizer] Use AssociativeCommonizer signature to implement ClassOrTypeAliasTypeCommonizer

This drastically improves performance for now, since the previous
Adapter implementation was at least O(n^2). While the Adapter
implementation could have been reduced to O(n), the Signature of
StatelessCommonizer was misleading.

StatelessCommonizer will be introduced back later when other
Commonizer implementations are ready to be converted to a new
Signature.
This commit is contained in:
sebastian.sellmair
2021-07-01 17:01:05 +02:00
committed by Space
parent 20f55ef0b7
commit b29fd17d26
4 changed files with 61 additions and 65 deletions

View File

@@ -0,0 +1,35 @@
/*
* 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
internal interface AssociativeCommonizer<T> {
fun commonize(first: T, second: T): T?
}
internal open class AssociativeCommonizerAdapter<T : Any>(
private val commonizer: AssociativeCommonizer<T>
) : AbstractStandardCommonizer<T, T>() {
private var _result: T? = null
override fun commonizationResult(): T {
return _result ?: failInEmptyState()
}
override fun initialize(first: T) = Unit
override fun doCommonizeWith(next: T): Boolean {
val currentResult = _result
if (currentResult == null) {
_result = next
return true
}
_result = commonizer.commonize(currentResult, next)
return _result != null
}
}

View File

@@ -10,52 +10,49 @@ import org.jetbrains.kotlin.commonizer.cir.CirClassType
import org.jetbrains.kotlin.commonizer.cir.CirTypeAliasType
import org.jetbrains.kotlin.commonizer.mergedtree.CirKnownClassifiers
internal class ClassOrTypeAliasTypeStatelessCommonizer(
internal class ClassOrTypeAliasTypeAssociativeCommonizer(
private val classifiers: CirKnownClassifiers
) : StatelessCommonizer<CirClassOrTypeAliasType, CirClassOrTypeAliasType> {
) : AssociativeCommonizer<CirClassOrTypeAliasType> {
override fun commonize(values: List<CirClassOrTypeAliasType>): CirClassOrTypeAliasType? {
if (values.isEmpty()) return null
values.singleOrNull()?.let { return it }
val classTypes = values.filterIsInstance<CirClassType>()
val typeAliasTypes = values.filterIsInstance<CirTypeAliasType>()
val expandedTypeAliasTypes = typeAliasTypes.map { it.expandedType() }
if (values.all { it is CirClassType }) {
return ClassTypeCommonizer(classifiers).commonize(classTypes)
override fun commonize(first: CirClassOrTypeAliasType, second: CirClassOrTypeAliasType): CirClassOrTypeAliasType? {
if (first is CirClassType && second is CirClassType) {
return ClassTypeCommonizer(classifiers).commonize(listOf(first, second))
}
if (values.all { it is CirTypeAliasType }) {
if (first is CirTypeAliasType && second is CirTypeAliasType) {
/*
In case regular type-alias-type commonization fails, we try to expand all type-aliases and
try our luck with commonizing those class types
*/
return TypeAliasTypeCommonizer(classifiers).commonize(typeAliasTypes)
?: ClassTypeCommonizer(classifiers).commonize(expandedTypeAliasTypes)
return TypeAliasTypeCommonizer(classifiers).commonize(listOf(first, second))
?: ClassTypeCommonizer(classifiers).commonize(listOf(first.expandedType(), second.expandedType()))
}
val classType = when {
first is CirClassType -> first
second is CirClassType -> second
else -> return null
}
val typeAliasType = when {
first is CirTypeAliasType -> first
second is CirTypeAliasType -> second
else -> return null
}
/*
There are type-alias types & class types enqueued for commonization.
We reduce all classes to a common representation and all type aliases to a common representation.
TypeAliasCommonizer will be able to figure out if the typealias will be represented as expect class in common.
If so, re-use this class type, otherwise: try to expand the typeAlias
*/
val commonizedClass = ClassTypeCommonizer(classifiers).commonize(classTypes) ?: return null
val commonizedTypeAlias = TypeAliasTypeCommonizer(classifiers).commonize(typeAliasTypes)
val typeAliasClassType = TypeAliasTypeCommonizer(classifiers).commonize(listOf(typeAliasType))?.expandedType()
?: typeAliasType.expandedType()
if (commonizedTypeAlias != null) {
return ClassTypeCommonizer(classifiers).commonize(listOf(commonizedClass, commonizedTypeAlias.expandedType()))
}
/*
If type-alias type commonization failed:
Last attempt: Try to commonize all type-alias expansions with the commonized class
*/
return ClassTypeCommonizer(classifiers).commonize(expandedTypeAliasTypes + commonizedClass)
return ClassTypeCommonizer(classifiers).commonize(listOf(classType, typeAliasClassType))
}
}
internal class ClassOrTypeAliasTypeCommonizer(classifiers: CirKnownClassifiers) :
StatelessCommonizerAdapter<CirClassOrTypeAliasType, CirClassOrTypeAliasType>(ClassOrTypeAliasTypeStatelessCommonizer(classifiers))
AssociativeCommonizerAdapter<CirClassOrTypeAliasType>(ClassOrTypeAliasTypeAssociativeCommonizer(classifiers))
internal tailrec fun CirClassOrTypeAliasType.expandedType(): CirClassType = when (this) {
is CirClassType -> this

View File

@@ -11,11 +11,6 @@ interface Commonizer<T, R> {
}
fun <T, R> Commonizer<T, R>.commonize(values: List<T>): R? {
/* Fast path: If commonizer supports StatelessCommonizer interface */
if (this is StatelessCommonizerAdapter) {
return commonize(values)
}
values.forEach { value -> if (!commonizeWith(value)) return null }
return result
}

View File

@@ -1,31 +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
interface StatelessCommonizer<T, R> {
fun commonize(values: List<T>): R?
}
open class StatelessCommonizerAdapter<T, R : Any>(
private val commonizer: StatelessCommonizer<T, R>
) : AbstractStandardCommonizer<T, R>(), StatelessCommonizer<T, R> by commonizer {
private val values = mutableListOf<T>()
override fun commonizationResult(): R {
try {
return checkNotNull(commonize(values.toList()))
} finally {
values.clear()
}
}
override fun initialize(first: T) = Unit
override fun doCommonizeWith(next: T): Boolean {
values.add(next)
return commonize(values.toList()) != null
}
}