[Commonizer] Implement CirTypeDistance.penalty

^KT-48288
This commit is contained in:
sebastian.sellmair
2021-09-16 12:50:37 +02:00
committed by Space
parent d0cd7c81ea
commit da1eb5d96e
3 changed files with 38 additions and 20 deletions
@@ -114,7 +114,7 @@ internal class ClassOrTypeAliasTypeCommonizer(
}
val resolvedClassifierFromDependencies = classifiers.commonDependencies.classifier(destinationClassifierId)
?: classifiers.targetDependencies[targetIndex].classifier(destinationClassifierId)
?: classifiers.targetDependencies[targetIndex].classifier(destinationClassifierId) // necessary?
if (resolvedClassifierFromDependencies != null && resolvedClassifierFromDependencies is CirProvided.TypeAlias) {
return backwardsSubstitute(targetIndex, sourceType, destinationClassifierId, resolvedClassifierFromDependencies)
@@ -201,20 +201,14 @@ internal class ClassOrTypeAliasTypeCommonizer(
val typeSubstitutionCandidates = resolveTypeSubstitutionCandidates(classifiers, commonId, types)
.filter { 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
}
if (typeSubstitutionCandidates.isEmpty()) return null
if (typeSubstitutionCandidates.size == 1) return typeSubstitutionCandidates.first().id
val forwardSubstitutionCandidates = typeSubstitutionCandidates.filter { it.typeDistance.isPositive }
val backwardsSubstitutionCandidates = typeSubstitutionCandidates.filter { it.typeDistance.isNegative }
return forwardSubstitutionCandidates.minByOrNull { it.typeDistance }?.id
?: backwardsSubstitutionCandidates.maxByOrNull { it.typeDistance }?.id
return typeSubstitutionCandidates.minByOrNull { it.typeDistance.penalty }?.id
}
}
@@ -231,14 +225,7 @@ private fun resolveTypeSubstitutionCandidates(
if (typeDistances.any { it.isNotReachable }) return@mapCandidateId null
TypeSubstitutionCandidate(
id = candidateId,
typeDistance = checkNotNull(typeDistances.worstOrNull())
typeDistance = checkNotNull(typeDistances.maxByOrNull { it.penalty })
)
}
}
private fun List<CirTypeDistance>.worstOrNull(): CirTypeDistance? {
if (this.isEmpty()) return null
// Negative Type Distances are considered 'worse'
filter { it.isNegative }.minOrNull()?.let { return it }
return maxOrNull()
}
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.commonizer.mergedtree
import org.jetbrains.kotlin.commonizer.CommonizerTarget
import org.jetbrains.kotlin.commonizer.cir.*
import org.jetbrains.kotlin.commonizer.mergedtree.CirTypeDistance.Companion.unreachable
import kotlin.math.absoluteValue
@JvmInline
value class CirTypeDistance(private val value: Int) : Comparable<CirTypeDistance> {
@@ -23,7 +22,25 @@ value class CirTypeDistance(private val value: Int) : Comparable<CirTypeDistance
val isZero: Boolean get() = value == 0
val absoluteValue get() = CirTypeDistance(value.absoluteValue)
/**
* Judges the type distance on 'how bad is it'.
* This judgement will always prefer positive distances over negative distances.
*
* The higher this number, the 'worse' the distance.
*
* Score for unreachable: MAX_VALUE
* Score for zero: MIN_VALUE
* Range for negative type distances: [1, MAX_VALUE[
* Range for positive type distances: ]MIN_VALUE, -1]
*/
val penalty: Int
get() = when {
isNotReachable -> Int.MAX_VALUE
isNegative -> -value
isZero -> Int.MIN_VALUE
isPositive -> Int.MIN_VALUE + value
else -> throw IllegalStateException("Unable to calculate penalty for $this")
}
operator fun plus(value: Int) = if (isReachable) CirTypeDistance(this.value + value) else this
@@ -308,9 +308,23 @@ class CirTypeDistanceTest : KtInlineSourceCommonizerTestCase() {
assertUnreachable(CirTypeDistance.unreachable.dec())
assertUnreachable(CirTypeDistance.unreachable - CirTypeDistance(1))
assertUnreachable(CirTypeDistance(1) - CirTypeDistance.unreachable)
assertUnreachable(CirTypeDistance.unreachable.absoluteValue)
assertEquals(CirTypeDistance(Int.MAX_VALUE), CirTypeDistance.unreachable)
}
fun `test penalty`() {
assertEquals(1, CirTypeDistance(-1).penalty)
assertEquals(2, CirTypeDistance(-2).penalty)
assertEquals(Int.MIN_VALUE, CirTypeDistance(0).penalty)
assertEquals(Int.MAX_VALUE, CirTypeDistance.unreachable.penalty)
assertEquals(Int.MIN_VALUE + 1, CirTypeDistance(1).penalty)
assertEquals(Int.MIN_VALUE + 2, CirTypeDistance(2).penalty)
assertTrue(CirTypeDistance(-1).penalty > CirTypeDistance(1).penalty)
assertTrue(CirTypeDistance(-1).penalty > CirTypeDistance(10).penalty)
assertTrue(CirTypeDistance(2).penalty > CirTypeDistance(1).penalty)
assertTrue(CirTypeDistance(-2).penalty > CirTypeDistance(-1).penalty)
assertTrue(CirTypeDistance(1).penalty > CirTypeDistance(0).penalty)
assertTrue(CirTypeDistance(-1).penalty > CirTypeDistance(0).penalty)
}
}
private fun assertUnreachable(typeDistance: CirTypeDistance) {