[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)
|
val resolvedClassifierFromDependencies = classifiers.commonDependencies.classifier(destinationClassifierId)
|
||||||
?: classifiers.targetDependencies[targetIndex].classifier(destinationClassifierId)
|
?: classifiers.targetDependencies[targetIndex].classifier(destinationClassifierId) // necessary?
|
||||||
|
|
||||||
if (resolvedClassifierFromDependencies != null && resolvedClassifierFromDependencies is CirProvided.TypeAlias) {
|
if (resolvedClassifierFromDependencies != null && resolvedClassifierFromDependencies is CirProvided.TypeAlias) {
|
||||||
return backwardsSubstitute(targetIndex, sourceType, destinationClassifierId, resolvedClassifierFromDependencies)
|
return backwardsSubstitute(targetIndex, sourceType, destinationClassifierId, resolvedClassifierFromDependencies)
|
||||||
@@ -201,20 +201,14 @@ internal class ClassOrTypeAliasTypeCommonizer(
|
|||||||
|
|
||||||
val typeSubstitutionCandidates = resolveTypeSubstitutionCandidates(classifiers, commonId, types)
|
val typeSubstitutionCandidates = resolveTypeSubstitutionCandidates(classifiers, commonId, types)
|
||||||
.filter { typeSubstitutionCandidate ->
|
.filter { typeSubstitutionCandidate ->
|
||||||
|
assert(typeSubstitutionCandidate.typeDistance.isZero.not()) { "Expected no zero typeDistance" }
|
||||||
if (typeSubstitutionCandidate.typeDistance.isNotReachable) return@filter false
|
if (typeSubstitutionCandidate.typeDistance.isNotReachable) return@filter false
|
||||||
if (typeSubstitutionCandidate.typeDistance.isNegative && !backwardsSubstitutionAllowed) return@filter false
|
if (typeSubstitutionCandidate.typeDistance.isNegative && !backwardsSubstitutionAllowed) return@filter false
|
||||||
if (typeSubstitutionCandidate.typeDistance.isPositive && !forwardSubstitutionAllowed) return@filter false
|
if (typeSubstitutionCandidate.typeDistance.isPositive && !forwardSubstitutionAllowed) return@filter false
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeSubstitutionCandidates.isEmpty()) return null
|
return typeSubstitutionCandidates.minByOrNull { it.typeDistance.penalty }?.id
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,14 +225,7 @@ private fun resolveTypeSubstitutionCandidates(
|
|||||||
if (typeDistances.any { it.isNotReachable }) return@mapCandidateId null
|
if (typeDistances.any { it.isNotReachable }) return@mapCandidateId null
|
||||||
TypeSubstitutionCandidate(
|
TypeSubstitutionCandidate(
|
||||||
id = candidateId,
|
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.CommonizerTarget
|
||||||
import org.jetbrains.kotlin.commonizer.cir.*
|
import org.jetbrains.kotlin.commonizer.cir.*
|
||||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirTypeDistance.Companion.unreachable
|
import org.jetbrains.kotlin.commonizer.mergedtree.CirTypeDistance.Companion.unreachable
|
||||||
import kotlin.math.absoluteValue
|
|
||||||
|
|
||||||
@JvmInline
|
@JvmInline
|
||||||
value class CirTypeDistance(private val value: Int) : Comparable<CirTypeDistance> {
|
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 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
|
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.dec())
|
||||||
assertUnreachable(CirTypeDistance.unreachable - CirTypeDistance(1))
|
assertUnreachable(CirTypeDistance.unreachable - CirTypeDistance(1))
|
||||||
assertUnreachable(CirTypeDistance(1) - CirTypeDistance.unreachable)
|
assertUnreachable(CirTypeDistance(1) - CirTypeDistance.unreachable)
|
||||||
assertUnreachable(CirTypeDistance.unreachable.absoluteValue)
|
|
||||||
assertEquals(CirTypeDistance(Int.MAX_VALUE), CirTypeDistance.unreachable)
|
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) {
|
private fun assertUnreachable(typeDistance: CirTypeDistance) {
|
||||||
|
|||||||
Reference in New Issue
Block a user