From 16bf5f3df3356693e0cd9c4d8da943851741e288 Mon Sep 17 00:00:00 2001 From: "sebastian.sellmair" Date: Fri, 17 Sep 2021 09:48:39 +0200 Subject: [PATCH] [Commonizer] Improve performance of ClassOrTypeAliasTypeCommonizer Performance is improved by reducing calls to 'backwardsTypeDistance' ^KT-48288 --- .../core/ClassOrTypeAliasTypeCommonizer.kt | 76 ++++++++++++------- 1 file changed, 47 insertions(+), 29 deletions(-) diff --git a/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/ClassOrTypeAliasTypeCommonizer.kt b/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/ClassOrTypeAliasTypeCommonizer.kt index a3b6a7c1363..315921d9b63 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/ClassOrTypeAliasTypeCommonizer.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/ClassOrTypeAliasTypeCommonizer.kt @@ -19,6 +19,7 @@ internal class ClassOrTypeAliasTypeCommonizer( ) : NullableSingleInvocationCommonizer { private val isMarkedNullableCommonizer = TypeNullabilityCommonizer(typeCommonizer.options) + private val typeDistanceMeasurement = TypeDistanceMeasurement(typeCommonizer.options) override fun invoke(values: List): CirClassOrTypeAliasType? { if (values.isEmpty()) return null @@ -146,11 +147,6 @@ internal class ClassOrTypeAliasTypeCommonizer( if (sourceType.arguments.isNotEmpty()) return null if (destinationTypeAlias.typeParameters.isNotEmpty()) return null - /* Check if any type in the intermediate ta chain has arguments */ - generateSequence(destinationTypeAlias.underlyingType) { type -> type.safeAs()?.underlyingType } - .takeWhile { type -> type.classifierId != sourceType.classifierId } - .forEach { type -> if (type.arguments.isNotEmpty()) return null } // limitation! - return CirTypeAliasType.createInterned( destinationTypeAliasId, underlyingType = destinationTypeAlias.underlyingType, @@ -171,16 +167,8 @@ internal class ClassOrTypeAliasTypeCommonizer( */ if (sourceType.arguments.isNotEmpty()) return null if (destinationTypeAlias.typeParameters.isNotEmpty()) return null - val providedClassifiers = CirProvidedClassifiers.of(classifiers.commonDependencies, classifiers.targetDependencies[targetIndex]) - generateSequence(destinationTypeAlias.underlyingType) next@{ type -> - val typeAliasType = type as? CirProvided.TypeAliasType ?: return@next null - val typeAlias = providedClassifiers.classifier(typeAliasType.classifierId) as? CirProvided.TypeAlias ?: return@next null - typeAlias.underlyingType - }.takeWhile { type -> type.classifierId != sourceType.classifierId } - .forEach { type -> if (type.arguments.isNotEmpty()) return null } - return CirTypeAliasType.createInterned( destinationTypeAliasId, underlyingType = destinationTypeAlias.underlyingType.toCirClassOrTypeAliasTypeOrNull(providedClassifiers) ?: return null, @@ -202,17 +190,28 @@ internal class ClassOrTypeAliasTypeCommonizer( classifiers.associatedIdsResolver.resolveAssociatedIds(it.classifierId) } ?: return null - val typeSubstitutionCandidates = resolveTypeSubstitutionCandidates(classifiers, associatedIds, types) - .filter { typeSubstitutionCandidate -> + val typeSubstitutionCandidates = resolveTypeSubstitutionCandidates(associatedIds, types) + .onEach { typeSubstitutionCandidate -> assert(typeSubstitutionCandidate.typeDistance.isZero.not()) { "Expected no zero typeDistance" } - if (typeSubstitutionCandidate.typeDistance.isNotReachable) return@filter false - if (typeSubstitutionCandidate.typeDistance.isNegative && !backwardsSubstitutionAllowed) return@filter false - if (typeSubstitutionCandidate.typeDistance.isPositive && !forwardSubstitutionAllowed) return@filter false - true + assert(typeSubstitutionCandidate.typeDistance.isReachable) { "Expected substitution candidate to be reachable" } } return typeSubstitutionCandidates.minByOrNull { it.typeDistance.penalty }?.id } + + private fun resolveTypeSubstitutionCandidates( + associatedIds: AssociatedClassifierIds, types: List + ): List { + return associatedIds.ids.mapNotNull mapCandidateId@{ candidateId -> + val typeDistances = types.mapIndexed { targetIndex, type -> + typeDistanceMeasurement(classifiers, targetIndex, type, candidateId) + .takeIf { it.isReachable } ?: return@mapCandidateId null + } + TypeSubstitutionCandidate( + id = candidateId, typeDistance = checkNotNull(typeDistances.maxByOrNull { it.penalty }) + ) + } + } } private class TypeSubstitutionCandidate( @@ -220,15 +219,34 @@ private class TypeSubstitutionCandidate( val typeDistance: CirTypeDistance ) -private fun resolveTypeSubstitutionCandidates( - classifiers: CirKnownClassifiers, associatedIds: AssociatedClassifierIds, types: List -): List { - return associatedIds.ids.mapNotNull mapCandidateId@{ candidateId -> - val typeDistances = types.mapIndexed { targetIndex, type -> typeDistance(classifiers, targetIndex, type, candidateId) } - if (typeDistances.any { it.isNotReachable }) return@mapCandidateId null - TypeSubstitutionCandidate( - id = candidateId, - typeDistance = checkNotNull(typeDistances.maxByOrNull { it.penalty }) - ) +private interface TypeDistanceMeasurement { + operator fun invoke( + classifiers: CirKnownClassifiers, targetIndex: Int, from: CirClassOrTypeAliasType, to: CirEntityId + ): CirTypeDistance + + private object None : TypeDistanceMeasurement { + override fun invoke( + classifiers: CirKnownClassifiers, targetIndex: Int, from: CirClassOrTypeAliasType, to: CirEntityId + ): CirTypeDistance = CirTypeDistance.unreachable + } + + private object ForwardOnly : TypeDistanceMeasurement { + override fun invoke( + classifiers: CirKnownClassifiers, targetIndex: Int, from: CirClassOrTypeAliasType, to: CirEntityId + ): CirTypeDistance = forwardTypeDistance(from, to) + } + + private object Full : TypeDistanceMeasurement { + override fun invoke( + classifiers: CirKnownClassifiers, targetIndex: Int, from: CirClassOrTypeAliasType, to: CirEntityId + ): CirTypeDistance = typeDistance(classifiers, targetIndex, from, to) + } + + companion object { + operator fun invoke(options: TypeCommonizer.Options): TypeDistanceMeasurement = when { + options.enableBackwardsTypeAliasSubstitution && options.enableForwardTypeAliasSubstitution -> Full + options.enableForwardTypeAliasSubstitution -> ForwardOnly + else -> None + } } }