[Commonizer] Improve performance of ClassOrTypeAliasTypeCommonizer
Performance is improved by reducing calls to 'backwardsTypeDistance' ^KT-48288
This commit is contained in:
committed by
Space
parent
64d2ba4029
commit
16bf5f3df3
+47
-29
@@ -19,6 +19,7 @@ internal class ClassOrTypeAliasTypeCommonizer(
|
|||||||
) : NullableSingleInvocationCommonizer<CirClassOrTypeAliasType> {
|
) : NullableSingleInvocationCommonizer<CirClassOrTypeAliasType> {
|
||||||
|
|
||||||
private val isMarkedNullableCommonizer = TypeNullabilityCommonizer(typeCommonizer.options)
|
private val isMarkedNullableCommonizer = TypeNullabilityCommonizer(typeCommonizer.options)
|
||||||
|
private val typeDistanceMeasurement = TypeDistanceMeasurement(typeCommonizer.options)
|
||||||
|
|
||||||
override fun invoke(values: List<CirClassOrTypeAliasType>): CirClassOrTypeAliasType? {
|
override fun invoke(values: List<CirClassOrTypeAliasType>): CirClassOrTypeAliasType? {
|
||||||
if (values.isEmpty()) return null
|
if (values.isEmpty()) return null
|
||||||
@@ -146,11 +147,6 @@ internal class ClassOrTypeAliasTypeCommonizer(
|
|||||||
if (sourceType.arguments.isNotEmpty()) return null
|
if (sourceType.arguments.isNotEmpty()) return null
|
||||||
if (destinationTypeAlias.typeParameters.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(
|
return CirTypeAliasType.createInterned(
|
||||||
destinationTypeAliasId,
|
destinationTypeAliasId,
|
||||||
underlyingType = destinationTypeAlias.underlyingType,
|
underlyingType = destinationTypeAlias.underlyingType,
|
||||||
@@ -171,16 +167,8 @@ internal class ClassOrTypeAliasTypeCommonizer(
|
|||||||
*/
|
*/
|
||||||
if (sourceType.arguments.isNotEmpty()) return null
|
if (sourceType.arguments.isNotEmpty()) return null
|
||||||
if (destinationTypeAlias.typeParameters.isNotEmpty()) return null
|
if (destinationTypeAlias.typeParameters.isNotEmpty()) return null
|
||||||
|
|
||||||
val providedClassifiers = CirProvidedClassifiers.of(classifiers.commonDependencies, classifiers.targetDependencies[targetIndex])
|
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(
|
return CirTypeAliasType.createInterned(
|
||||||
destinationTypeAliasId,
|
destinationTypeAliasId,
|
||||||
underlyingType = destinationTypeAlias.underlyingType.toCirClassOrTypeAliasTypeOrNull(providedClassifiers) ?: return null,
|
underlyingType = destinationTypeAlias.underlyingType.toCirClassOrTypeAliasTypeOrNull(providedClassifiers) ?: return null,
|
||||||
@@ -202,17 +190,28 @@ internal class ClassOrTypeAliasTypeCommonizer(
|
|||||||
classifiers.associatedIdsResolver.resolveAssociatedIds(it.classifierId)
|
classifiers.associatedIdsResolver.resolveAssociatedIds(it.classifierId)
|
||||||
} ?: return null
|
} ?: return null
|
||||||
|
|
||||||
val typeSubstitutionCandidates = resolveTypeSubstitutionCandidates(classifiers, associatedIds, types)
|
val typeSubstitutionCandidates = resolveTypeSubstitutionCandidates(associatedIds, types)
|
||||||
.filter { typeSubstitutionCandidate ->
|
.onEach { typeSubstitutionCandidate ->
|
||||||
assert(typeSubstitutionCandidate.typeDistance.isZero.not()) { "Expected no zero typeDistance" }
|
assert(typeSubstitutionCandidate.typeDistance.isZero.not()) { "Expected no zero typeDistance" }
|
||||||
if (typeSubstitutionCandidate.typeDistance.isNotReachable) return@filter false
|
assert(typeSubstitutionCandidate.typeDistance.isReachable) { "Expected substitution candidate to be reachable" }
|
||||||
if (typeSubstitutionCandidate.typeDistance.isNegative && !backwardsSubstitutionAllowed) return@filter false
|
|
||||||
if (typeSubstitutionCandidate.typeDistance.isPositive && !forwardSubstitutionAllowed) return@filter false
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return typeSubstitutionCandidates.minByOrNull { it.typeDistance.penalty }?.id
|
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(
|
private class TypeSubstitutionCandidate(
|
||||||
@@ -220,15 +219,34 @@ private class TypeSubstitutionCandidate(
|
|||||||
val typeDistance: CirTypeDistance
|
val typeDistance: CirTypeDistance
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun resolveTypeSubstitutionCandidates(
|
private interface TypeDistanceMeasurement {
|
||||||
classifiers: CirKnownClassifiers, associatedIds: AssociatedClassifierIds, types: List<CirClassOrTypeAliasType>
|
operator fun invoke(
|
||||||
): List<TypeSubstitutionCandidate> {
|
classifiers: CirKnownClassifiers, targetIndex: Int, from: CirClassOrTypeAliasType, to: CirEntityId
|
||||||
return associatedIds.ids.mapNotNull mapCandidateId@{ candidateId ->
|
): CirTypeDistance
|
||||||
val typeDistances = types.mapIndexed { targetIndex, type -> typeDistance(classifiers, targetIndex, type, candidateId) }
|
|
||||||
if (typeDistances.any { it.isNotReachable }) return@mapCandidateId null
|
private object None : TypeDistanceMeasurement {
|
||||||
TypeSubstitutionCandidate(
|
override fun invoke(
|
||||||
id = candidateId,
|
classifiers: CirKnownClassifiers, targetIndex: Int, from: CirClassOrTypeAliasType, to: CirEntityId
|
||||||
typeDistance = checkNotNull(typeDistances.maxByOrNull { it.penalty })
|
): 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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user