[Commonizer] Implement CirTypeDistance.penalty
^KT-48288
This commit is contained in:
committed by
Space
parent
d0cd7c81ea
commit
da1eb5d96e
+4
-17
@@ -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()
|
||||
}
|
||||
+19
-2
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user