[Commonizer] Improve performance of ClassOrTypeAliasTypeCommonizer

Performance is improved by reducing calls to 'backwardsTypeDistance'

^KT-48288
This commit is contained in:
sebastian.sellmair
2021-09-17 09:48:39 +02:00
committed by Space
parent 64d2ba4029
commit 16bf5f3df3
@@ -19,6 +19,7 @@ internal class ClassOrTypeAliasTypeCommonizer(
) : NullableSingleInvocationCommonizer<CirClassOrTypeAliasType> {
private val isMarkedNullableCommonizer = TypeNullabilityCommonizer(typeCommonizer.options)
private val typeDistanceMeasurement = TypeDistanceMeasurement(typeCommonizer.options)
override fun invoke(values: List<CirClassOrTypeAliasType>): 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<CirTypeAliasType>()?.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<CirClassOrTypeAliasType>
): List<TypeSubstitutionCandidate> {
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<CirClassOrTypeAliasType>
): List<TypeSubstitutionCandidate> {
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
}
}
}