[Commonizer] ClassOrTypeAliasTypeCommonizer: Use typeDistance and type substitution
^KT-48288
This commit is contained in:
committed by
Space
parent
4a6366ed9b
commit
31445d1471
+133
-39
@@ -6,13 +6,13 @@
|
|||||||
package org.jetbrains.kotlin.commonizer.core
|
package org.jetbrains.kotlin.commonizer.core
|
||||||
|
|
||||||
import org.jetbrains.kotlin.commonizer.cir.*
|
import org.jetbrains.kotlin.commonizer.cir.*
|
||||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirKnownClassifiers
|
import org.jetbrains.kotlin.commonizer.mergedtree.*
|
||||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirProvided
|
|
||||||
import org.jetbrains.kotlin.commonizer.utils.isUnderKotlinNativeSyntheticPackages
|
import org.jetbrains.kotlin.commonizer.utils.isUnderKotlinNativeSyntheticPackages
|
||||||
import org.jetbrains.kotlin.commonizer.utils.safeCastValues
|
import org.jetbrains.kotlin.commonizer.utils.safeCastValues
|
||||||
import org.jetbrains.kotlin.commonizer.utils.singleDistinctValueOrNull
|
import org.jetbrains.kotlin.commonizer.utils.singleDistinctValueOrNull
|
||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.ifTrue
|
import org.jetbrains.kotlin.utils.addToStdlib.ifTrue
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
internal class ClassOrTypeAliasTypeCommonizer(
|
internal class ClassOrTypeAliasTypeCommonizer(
|
||||||
private val typeCommonizer: TypeCommonizer,
|
private val typeCommonizer: TypeCommonizer,
|
||||||
@@ -23,16 +23,18 @@ internal class ClassOrTypeAliasTypeCommonizer(
|
|||||||
|
|
||||||
override fun invoke(values: List<CirClassOrTypeAliasType>): CirClassOrTypeAliasType? {
|
override fun invoke(values: List<CirClassOrTypeAliasType>): CirClassOrTypeAliasType? {
|
||||||
if (values.isEmpty()) return null
|
if (values.isEmpty()) return null
|
||||||
|
|
||||||
val expansions = values.map { it.expandedType() }
|
val expansions = values.map { it.expandedType() }
|
||||||
val isMarkedNullable = isMarkedNullableCommonizer.commonize(expansions.map { it.isMarkedNullable }) ?: return null
|
val isMarkedNullable = isMarkedNullableCommonizer.commonize(expansions.map { it.isMarkedNullable }) ?: return null
|
||||||
val arguments = TypeArgumentListCommonizer(typeCommonizer).commonize(values.map { it.arguments }) ?: return null
|
|
||||||
val classifierId = selectClassifierId(values)
|
|
||||||
?: typeCommonizer.options.enableOptimisticNumberTypeCommonization.ifTrue {
|
|
||||||
return OptimisticNumbersTypeCommonizer.commonize(expansions)
|
|
||||||
} ?: return null
|
|
||||||
|
|
||||||
val outerTypes = values.safeCastValues<CirClassOrTypeAliasType, CirClassType>()?.map { it.outerType }
|
val types = substituteTypesIfNecessary(values) ?: typeCommonizer.options.enableOptimisticNumberTypeCommonization.ifTrue {
|
||||||
|
return OptimisticNumbersTypeCommonizer.commonize(expansions)
|
||||||
|
} ?: return null
|
||||||
|
|
||||||
|
val classifierId = types.singleDistinctValueOrNull { it.classifierId } ?: return null
|
||||||
|
|
||||||
|
val arguments = TypeArgumentListCommonizer(typeCommonizer).commonize(types.map { it.arguments }) ?: return null
|
||||||
|
|
||||||
|
val outerTypes = types.safeCastValues<CirClassOrTypeAliasType, CirClassType>()?.map { it.outerType }
|
||||||
val outerType = when {
|
val outerType = when {
|
||||||
outerTypes == null -> null
|
outerTypes == null -> null
|
||||||
outerTypes.all { it == null } -> null
|
outerTypes.all { it == null } -> null
|
||||||
@@ -94,10 +96,98 @@ internal class ClassOrTypeAliasTypeCommonizer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("KotlinConstantConditions") // Improved readability
|
private fun substituteTypesIfNecessary(types: List<CirClassOrTypeAliasType>): List<CirClassOrTypeAliasType>? {
|
||||||
private fun selectClassifierId(types: List<CirClassOrTypeAliasType>): CirEntityId? {
|
// Not necessary
|
||||||
types.singleDistinctValueOrNull { it.classifierId }?.let { return it }
|
if (types.singleDistinctValueOrNull { it.classifierId } != null) return types
|
||||||
|
val classifierId = selectSubstitutionClassifierId(types) ?: return null
|
||||||
|
return types.mapIndexed { targetIndex, type -> substituteIfNecessary(targetIndex, type, classifierId) ?: return null }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun substituteIfNecessary(
|
||||||
|
targetIndex: Int, sourceType: CirClassOrTypeAliasType, destinationClassifierId: CirEntityId
|
||||||
|
): CirClassOrTypeAliasType? {
|
||||||
|
if (sourceType.classifierId == destinationClassifierId) {
|
||||||
|
return sourceType
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sourceType is CirTypeAliasType) {
|
||||||
|
forwardSubstitute(sourceType, destinationClassifierId)?.let { return it }
|
||||||
|
}
|
||||||
|
|
||||||
|
val resolvedClassifierFromDependencies = classifiers.commonDependencies.classifier(destinationClassifierId)
|
||||||
|
?: classifiers.targetDependencies[targetIndex].classifier(destinationClassifierId)
|
||||||
|
|
||||||
|
if (resolvedClassifierFromDependencies != null && resolvedClassifierFromDependencies is CirProvided.TypeAlias) {
|
||||||
|
return backwardsSubstitute(targetIndex, sourceType, destinationClassifierId, resolvedClassifierFromDependencies)
|
||||||
|
}
|
||||||
|
|
||||||
|
val resolvedClassifier = classifiers.classifierIndices[targetIndex].findClassifier(destinationClassifierId)
|
||||||
|
if (resolvedClassifier != null && resolvedClassifier is CirTypeAlias) {
|
||||||
|
return backwardsSubstitute(sourceType, destinationClassifierId, resolvedClassifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun forwardSubstitute(
|
||||||
|
sourceType: CirTypeAliasType,
|
||||||
|
destinationClassifierId: CirEntityId,
|
||||||
|
): CirClassOrTypeAliasType? {
|
||||||
|
return generateSequence(sourceType.underlyingType) { type -> type.safeAs<CirTypeAliasType>()?.underlyingType }
|
||||||
|
.firstOrNull { underlyingType -> underlyingType.classifierId == destinationClassifierId }
|
||||||
|
?.withParentArguments(sourceType.arguments, sourceType.isMarkedNullable)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun backwardsSubstitute(
|
||||||
|
sourceType: CirClassOrTypeAliasType,
|
||||||
|
destinationTypeAliasId: CirEntityId,
|
||||||
|
destinationTypeAlias: CirTypeAlias
|
||||||
|
): CirTypeAliasType? {
|
||||||
|
// Limitation: No backwards substitution with arguments
|
||||||
|
if (sourceType.arguments.isNotEmpty()) return null
|
||||||
|
if (destinationTypeAlias.typeParameters.isNotEmpty()) return null
|
||||||
|
|
||||||
|
// Check if any 'backward' type 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,
|
||||||
|
arguments = emptyList(),
|
||||||
|
isMarkedNullable = sourceType.isMarkedNullable
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun backwardsSubstitute(
|
||||||
|
targetIndex: Int,
|
||||||
|
sourceType: CirClassOrTypeAliasType,
|
||||||
|
destinationTypeAliasId: CirEntityId,
|
||||||
|
destinationTypeAlias: CirProvided.TypeAlias
|
||||||
|
): CirClassOrTypeAliasType? {
|
||||||
|
// Limitation: No backwards substitution with arguments
|
||||||
|
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 = providedClassifiers.toCirClassOrTypeAliasTypeOrNull(destinationTypeAlias.underlyingType) ?: return null,
|
||||||
|
arguments = emptyList(),
|
||||||
|
isMarkedNullable = sourceType.isMarkedNullable
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun selectSubstitutionClassifierId(types: List<CirClassOrTypeAliasType>): CirEntityId? {
|
||||||
val forwardSubstitutionAllowed = typeCommonizer.options.enableForwardTypeAliasSubstitution
|
val forwardSubstitutionAllowed = typeCommonizer.options.enableForwardTypeAliasSubstitution
|
||||||
val backwardsSubstitutionAllowed = typeCommonizer.options.enableBackwardsTypeAliasSubstitution
|
val backwardsSubstitutionAllowed = typeCommonizer.options.enableBackwardsTypeAliasSubstitution
|
||||||
|
|
||||||
@@ -110,36 +200,40 @@ internal class ClassOrTypeAliasTypeCommonizer(
|
|||||||
classifiers.commonClassifierIdResolver.findCommonId(it.classifierId)
|
classifiers.commonClassifierIdResolver.findCommonId(it.classifierId)
|
||||||
} ?: return null
|
} ?: return null
|
||||||
|
|
||||||
val candidates = when {
|
val typeSubstitutionCandidates = resolveTypeSubstitutionCandidates(classifiers, commonId, types)
|
||||||
forwardSubstitutionAllowed && backwardsSubstitutionAllowed -> commonId.aliases
|
.filter { typeSubstitutionCandidate ->
|
||||||
|
if (typeSubstitutionCandidate.typeDistance.isNotReachable) return@filter false
|
||||||
/* Only forward substitutions allowed -> Only substitute with any underlying type */
|
if (typeSubstitutionCandidate.typeDistance.isNegative && !backwardsSubstitutionAllowed) return@filter false
|
||||||
forwardSubstitutionAllowed -> commonId.aliases.filter { candidate ->
|
if (typeSubstitutionCandidate.typeDistance.isPositive && !forwardSubstitutionAllowed) return@filter false
|
||||||
types.all { type -> candidate == type.classifierId || type.isAnyUnderlyingClassifier(candidate) }
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Only backward substitutions allowed -> Only substitute with any typealias pointing to this types */
|
if (typeSubstitutionCandidates.isEmpty()) return null
|
||||||
backwardsSubstitutionAllowed -> commonId.aliases.filter { candidate ->
|
if (typeSubstitutionCandidates.size == 1) return typeSubstitutionCandidates.first().id
|
||||||
types.none { type -> type.isAnyUnderlyingClassifier(candidate) }
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> error("Failed to select classifierId: Unexpected when branch")
|
val forwardSubstitutionCandidates = typeSubstitutionCandidates.filter { it.typeDistance.isPositive }
|
||||||
}
|
val backwardsSubstitutionCandidates = typeSubstitutionCandidates.filter { it.typeDistance.isNegative }
|
||||||
|
|
||||||
if (candidates.isEmpty()) return null
|
return forwardSubstitutionCandidates.minByOrNull { it.typeDistance }?.id
|
||||||
if (candidates.size == 1) return candidates.first()
|
?: backwardsSubstitutionCandidates.maxByOrNull { it.typeDistance }?.id
|
||||||
|
}
|
||||||
return candidates.maxByOrNull { candidate -> types.count { it.classifierId == candidate } }!!
|
}
|
||||||
}
|
|
||||||
|
private class TypeSubstitutionCandidate(
|
||||||
private fun CirClassOrTypeAliasType.isAnyUnderlyingClassifier(classifierId: CirEntityId): Boolean {
|
val id: CirEntityId,
|
||||||
return when (this) {
|
val typeDistance: CirTypeDistance
|
||||||
is CirClassType -> false
|
)
|
||||||
is CirTypeAliasType -> this.isAnyUnderlyingClassifier(classifierId)
|
|
||||||
}
|
private fun resolveTypeSubstitutionCandidates(
|
||||||
}
|
classifiers: CirKnownClassifiers, commonId: CirCommonClassifierId, types: List<CirClassOrTypeAliasType>
|
||||||
|
): List<TypeSubstitutionCandidate> {
|
||||||
private fun CirTypeAliasType.isAnyUnderlyingClassifier(classifierId: CirEntityId): Boolean {
|
return commonId.aliases.mapNotNull mapCandidateId@{ candidateId ->
|
||||||
return underlyingType.classifierId == classifierId || underlyingType.isAnyUnderlyingClassifier(classifierId)
|
val typeDistances = types.mapIndexed { targetIndex, type -> typeDistance(classifiers, targetIndex, type, candidateId) }
|
||||||
|
if (typeDistances.any { it.isNotReachable }) return@mapCandidateId null
|
||||||
|
TypeSubstitutionCandidate(
|
||||||
|
id = candidateId,
|
||||||
|
// TODO NOW: Any negative should outperform any positive substitution!, so negative will be chosen here as 'worst'
|
||||||
|
typeDistance = checkNotNull(typeDistances.maxByOrNull { distance -> distance.absoluteValue })
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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> {
|
||||||
|
|
||||||
|
val isReachable: Boolean get() = value != Int.MAX_VALUE
|
||||||
|
|
||||||
|
val isNotReachable: Boolean get() = !isReachable
|
||||||
|
|
||||||
|
val isNegative: Boolean get() = isReachable && value < 0
|
||||||
|
|
||||||
|
val isPositive: Boolean get() = isReachable && value > 0
|
||||||
|
|
||||||
|
val isZero: Boolean get() = value == 0
|
||||||
|
|
||||||
|
val absoluteValue get() = CirTypeDistance(value.absoluteValue)
|
||||||
|
|
||||||
|
operator fun plus(value: Int) = if (isReachable) CirTypeDistance(this.value + value) else this
|
||||||
|
|
||||||
|
operator fun plus(value: CirTypeDistance) = when {
|
||||||
|
this.isNotReachable -> this
|
||||||
|
value.isNotReachable -> value
|
||||||
|
else -> CirTypeDistance(this.value + value.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun minus(value: Int) = if (isReachable) CirTypeDistance(this.value - value) else this
|
||||||
|
|
||||||
|
operator fun minus(value: CirTypeDistance) = when {
|
||||||
|
this.isNotReachable -> this
|
||||||
|
value.isNotReachable -> value
|
||||||
|
else -> CirTypeDistance(this.value - value.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun inc() = this + 1
|
||||||
|
|
||||||
|
operator fun dec() = this - 1
|
||||||
|
|
||||||
|
override fun compareTo(other: CirTypeDistance): Int {
|
||||||
|
return value.compareTo(other.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return if (isNotReachable) "CirTypeDistance([unreachable])"
|
||||||
|
else "CirTypeDistance($value)"
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun unreachable(): CirTypeDistance = CirTypeDistance(Int.MAX_VALUE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun typeDistance(
|
||||||
|
classifiers: CirKnownClassifiers,
|
||||||
|
target: CommonizerTarget,
|
||||||
|
from: CirClassOrTypeAliasType,
|
||||||
|
to: CirEntityId
|
||||||
|
): CirTypeDistance {
|
||||||
|
return typeDistance(classifiers, classifiers.classifierIndices.indexOf(target), from = from, to = to)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun typeDistance(
|
||||||
|
classifiers: CirKnownClassifiers,
|
||||||
|
targetIndex: Int,
|
||||||
|
from: CirClassOrTypeAliasType,
|
||||||
|
to: CirEntityId
|
||||||
|
): CirTypeDistance {
|
||||||
|
if (from.classifierId == to) return CirTypeDistance(0)
|
||||||
|
val forwardDistance = forwardTypeDistance(from, to)
|
||||||
|
if (forwardDistance.isReachable) return forwardDistance
|
||||||
|
|
||||||
|
val backwardsDistance = backwardsTypeDistance(classifiers, targetIndex, from.classifierId, to)
|
||||||
|
if (backwardsDistance.isReachable) return backwardsDistance
|
||||||
|
|
||||||
|
val fromExpansion = from.expandedType()
|
||||||
|
val distanceToExpansion = typeDistance(classifiers, targetIndex, from, fromExpansion.classifierId)
|
||||||
|
return backwardsTypeDistance(classifiers, targetIndex, from.expandedType().classifierId, to) - distanceToExpansion
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun forwardTypeDistance(from: CirClassOrTypeAliasType, to: CirEntityId): CirTypeDistance {
|
||||||
|
if (from !is CirTypeAliasType) return unreachable()
|
||||||
|
|
||||||
|
var iteration = 0
|
||||||
|
var underlyingType: CirClassOrTypeAliasType? = from.underlyingType
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
iteration++
|
||||||
|
val capturedUnderlyingType = underlyingType ?: return unreachable()
|
||||||
|
if (capturedUnderlyingType.classifierId == to) return CirTypeDistance(iteration)
|
||||||
|
underlyingType = (capturedUnderlyingType as? CirTypeAliasType)?.underlyingType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun backwardsTypeDistance(
|
||||||
|
classifiers: CirKnownClassifiers, targetIndex: Int, from: CirEntityId, to: CirEntityId
|
||||||
|
): CirTypeDistance {
|
||||||
|
val resolvedDependencyClassifier =
|
||||||
|
classifiers.commonDependencies.classifier(to) ?: classifiers.targetDependencies[targetIndex].classifier(to)
|
||||||
|
if (resolvedDependencyClassifier != null) {
|
||||||
|
return classifiers.backwardsTypeDistance(targetIndex, from, resolvedDependencyClassifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
val resolvedClassifier = classifiers.classifierIndices[targetIndex].findClassifier(to) ?: return unreachable()
|
||||||
|
return classifiers.backwardsTypeDistance(targetIndex, from, resolvedClassifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CirKnownClassifiers.backwardsTypeDistance(
|
||||||
|
targetIndex: Int, from: CirEntityId, to: CirProvided.Classifier
|
||||||
|
): CirTypeDistance {
|
||||||
|
if (to !is CirProvided.TypeAlias) return unreachable()
|
||||||
|
if (to.underlyingType.classifierId == from) return CirTypeDistance(-1)
|
||||||
|
return backwardsTypeDistance(this, targetIndex, from, to.underlyingType.classifierId) - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CirKnownClassifiers.backwardsTypeDistance(
|
||||||
|
targetIndex: Int, from: CirEntityId, to: CirClassifier
|
||||||
|
): CirTypeDistance {
|
||||||
|
if (to !is CirTypeAlias) return unreachable()
|
||||||
|
if (to.underlyingType.classifierId == from) return CirTypeDistance(-1)
|
||||||
|
return backwardsTypeDistance(this, targetIndex, from, to.underlyingType.classifierId) - 1
|
||||||
|
}
|
||||||
+78
-4
@@ -154,8 +154,9 @@ class CirCommonClassifierIdResolverTest : AbstractInlineSourcesCommonizationTest
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
Rather esoteric case!
|
Rather esoteric case!
|
||||||
Platform A: A -> B -> C D -> E
|
Platform A: A -> B -> C
|
||||||
Platform B: B -> C - D
|
D -> E
|
||||||
|
Platform B: B -> C -> D
|
||||||
|
|
||||||
Expected: B, C, D
|
Expected: B, C, D
|
||||||
*/
|
*/
|
||||||
@@ -180,10 +181,10 @@ class CirCommonClassifierIdResolverTest : AbstractInlineSourcesCommonizationTest
|
|||||||
)
|
)
|
||||||
|
|
||||||
val resolver = createCommonClassifierIdResolver(rootB, rootA)
|
val resolver = createCommonClassifierIdResolver(rootB, rootA)
|
||||||
|
assertEquals(setOf("B", "C", "D"), resolver.findCommonId("A"))
|
||||||
assertEquals(setOf("B", "C", "D"), resolver.findCommonId("B"))
|
assertEquals(setOf("B", "C", "D"), resolver.findCommonId("B"))
|
||||||
assertEquals(setOf("B", "C", "D"), resolver.findCommonId("C"))
|
assertEquals(setOf("B", "C", "D"), resolver.findCommonId("C"))
|
||||||
assertEquals(setOf("B", "C", "D"), resolver.findCommonId("D"))
|
assertEquals(setOf("B", "C", "D"), resolver.findCommonId("D"))
|
||||||
assertEquals(setOf("B", "C", "D"), resolver.findCommonId("A"))
|
|
||||||
assertEquals(setOf("B", "C", "D"), resolver.findCommonId("E"))
|
assertEquals(setOf("B", "C", "D"), resolver.findCommonId("E"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,7 +233,7 @@ class CirCommonClassifierIdResolverTest : AbstractInlineSourcesCommonizationTest
|
|||||||
source(
|
source(
|
||||||
"""
|
"""
|
||||||
class D_X
|
class D_X
|
||||||
class D_TA = D_X
|
typealias D_TA = D_X
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -268,6 +269,79 @@ class CirCommonClassifierIdResolverTest : AbstractInlineSourcesCommonizationTest
|
|||||||
assertEquals(setOf("D_X", "D_TA", "A", "C"), resolver.findCommonId("B"))
|
assertEquals(setOf("D_X", "D_TA", "A", "C"), resolver.findCommonId("B"))
|
||||||
assertEquals(setOf("D_X", "D_TA", "A", "C"), resolver.findCommonId("C"))
|
assertEquals(setOf("D_X", "D_TA", "A", "C"), resolver.findCommonId("C"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Platform A: A1 -> A -> B -> C
|
||||||
|
Platform B: A2 -> A -> D -> E
|
||||||
|
|
||||||
|
Expected: A
|
||||||
|
*/
|
||||||
|
fun `test sample 8`() {
|
||||||
|
val resolver = createCommonClassifierIdResolver(
|
||||||
|
createCirTreeRootFromSourceCode(
|
||||||
|
"""
|
||||||
|
class C
|
||||||
|
typealias B = C
|
||||||
|
typealias A = B
|
||||||
|
typealias A1 = A
|
||||||
|
""".trimIndent()
|
||||||
|
),
|
||||||
|
createCirTreeRootFromSourceCode(
|
||||||
|
"""
|
||||||
|
class E
|
||||||
|
typealias D = E
|
||||||
|
typealias A = D
|
||||||
|
typealias A2 = A
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(setOf("A"), resolver.findCommonId("A"))
|
||||||
|
assertEquals(setOf("A"), resolver.findCommonId("A1"))
|
||||||
|
assertEquals(setOf("A"), resolver.findCommonId("A2"))
|
||||||
|
assertEquals(setOf("A"), resolver.findCommonId("B"))
|
||||||
|
assertEquals(setOf("A"), resolver.findCommonId("C"))
|
||||||
|
assertEquals(setOf("A"), resolver.findCommonId("E"))
|
||||||
|
assertEquals(setOf("A"), resolver.findCommonId("D"))
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Platform A: A -> B -> C
|
||||||
|
Platform B: A -> D -> E
|
||||||
|
F -> G -> C
|
||||||
|
|
||||||
|
Expected: A, C
|
||||||
|
*/
|
||||||
|
fun `test sample 9`() {
|
||||||
|
val resolver = createCommonClassifierIdResolver(
|
||||||
|
createCirTreeRootFromSourceCode(
|
||||||
|
"""
|
||||||
|
class C
|
||||||
|
typealias B = C
|
||||||
|
typealias A = B
|
||||||
|
""".trimIndent()
|
||||||
|
),
|
||||||
|
createCirTreeRootFromSourceCode(
|
||||||
|
"""
|
||||||
|
class E
|
||||||
|
typealias D = E
|
||||||
|
typealias A = D
|
||||||
|
|
||||||
|
class C
|
||||||
|
typealias G = C
|
||||||
|
typealias F = G
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(setOf("A", "C"), resolver.findCommonId("A"))
|
||||||
|
assertEquals(setOf("A", "C"), resolver.findCommonId("B"))
|
||||||
|
assertEquals(setOf("A", "C"), resolver.findCommonId("C"))
|
||||||
|
assertEquals(setOf("A", "C"), resolver.findCommonId("D"))
|
||||||
|
assertEquals(setOf("A", "C"), resolver.findCommonId("E"))
|
||||||
|
assertEquals(setOf("A", "C"), resolver.findCommonId("F"))
|
||||||
|
assertEquals(setOf("A", "C"), resolver.findCommonId("G"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createCommonClassifierIdResolver(
|
private fun createCommonClassifierIdResolver(
|
||||||
|
|||||||
@@ -0,0 +1,322 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.commonizer
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.commonizer.cir.CirEntityId
|
||||||
|
import org.jetbrains.kotlin.commonizer.mergedtree.*
|
||||||
|
import org.jetbrains.kotlin.commonizer.utils.*
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertFalse
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
class CirTypeDistanceTest : KtInlineSourceCommonizerTestCase() {
|
||||||
|
|
||||||
|
private val target = LeafCommonizerTarget("a")
|
||||||
|
|
||||||
|
fun `test sample 0`() {
|
||||||
|
|
||||||
|
val root = createCirTreeRootFromSourceCode(
|
||||||
|
"""
|
||||||
|
class A
|
||||||
|
typealias B = A
|
||||||
|
typealias C = B
|
||||||
|
typealias D = C
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
val classifiers = CirKnownClassifiers(
|
||||||
|
classifierIndices = TargetDependent(target to CirClassifierIndex(root)),
|
||||||
|
targetDependencies = TargetDependent(target to CirProvidedClassifiers.EMPTY),
|
||||||
|
commonizedNodes = CirCommonizedClassifierNodes.default(),
|
||||||
|
commonDependencies = CirProvidedClassifiers.EMPTY
|
||||||
|
)
|
||||||
|
|
||||||
|
val idOfA = CirEntityId.create("A")
|
||||||
|
val idOfB = CirEntityId.create("B")
|
||||||
|
val idOfC = CirEntityId.create("C")
|
||||||
|
val idOfD = CirEntityId.create("D")
|
||||||
|
|
||||||
|
val typeA = mockClassType("A")
|
||||||
|
val typeB = mockTAType("B") { typeA }
|
||||||
|
val typeC = mockTAType("C") { typeB }
|
||||||
|
val typeD = mockTAType("D") { typeC }
|
||||||
|
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CirTypeDistance(0),
|
||||||
|
typeDistance(classifiers, target, typeA, idOfA)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CirTypeDistance(1),
|
||||||
|
typeDistance(classifiers, target, typeB, idOfA)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CirTypeDistance(-1),
|
||||||
|
typeDistance(classifiers, target, typeA, idOfB)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CirTypeDistance(2),
|
||||||
|
typeDistance(classifiers, target, typeC, idOfA)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CirTypeDistance(-2),
|
||||||
|
typeDistance(classifiers, target, typeA, idOfC)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CirTypeDistance(3),
|
||||||
|
typeDistance(classifiers, target, typeD, idOfA)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CirTypeDistance(-3),
|
||||||
|
typeDistance(classifiers, target, typeA, idOfD)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CirTypeDistance(2),
|
||||||
|
typeDistance(classifiers, target, typeD, idOfB)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CirTypeDistance(-2),
|
||||||
|
typeDistance(classifiers, target, typeB, idOfD)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun `test sample 1 - unreachable types`() {
|
||||||
|
val root = createCirTreeRootFromSourceCode(
|
||||||
|
"""
|
||||||
|
class X
|
||||||
|
class Y
|
||||||
|
typealias A = X
|
||||||
|
typealias B = Y
|
||||||
|
typealias C = B
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
val classifiers = CirKnownClassifiers(
|
||||||
|
classifierIndices = TargetDependent(target to CirClassifierIndex(root)),
|
||||||
|
targetDependencies = TargetDependent(target to CirProvidedClassifiers.EMPTY),
|
||||||
|
commonizedNodes = CirCommonizedClassifierNodes.default(),
|
||||||
|
commonDependencies = CirProvidedClassifiers.EMPTY
|
||||||
|
)
|
||||||
|
|
||||||
|
val idOfX = CirEntityId.create("X")
|
||||||
|
val idOfY = CirEntityId.create("Y")
|
||||||
|
val idOfA = CirEntityId.create("A")
|
||||||
|
val idOfB = CirEntityId.create("B")
|
||||||
|
val idOfC = CirEntityId.create("C")
|
||||||
|
|
||||||
|
val typeX = mockClassType("X")
|
||||||
|
val typeY = mockClassType("Y")
|
||||||
|
val typeA = mockTAType("A") { typeX }
|
||||||
|
val typeB = mockTAType("B") { typeY }
|
||||||
|
val typeC = mockTAType("C") { typeB }
|
||||||
|
|
||||||
|
assertUnreachable(typeDistance(classifiers, target, typeX, idOfY))
|
||||||
|
assertUnreachable(typeDistance(classifiers, target, typeY, idOfX))
|
||||||
|
assertUnreachable(typeDistance(classifiers, target, typeA, idOfY))
|
||||||
|
assertUnreachable(typeDistance(classifiers, target, typeY, idOfA))
|
||||||
|
assertUnreachable(typeDistance(classifiers, target, typeB, idOfA))
|
||||||
|
assertUnreachable(typeDistance(classifiers, target, typeA, idOfB))
|
||||||
|
assertUnreachable(typeDistance(classifiers, target, typeC, idOfA))
|
||||||
|
assertUnreachable(typeDistance(classifiers, target, typeA, idOfC))
|
||||||
|
assertUnreachable(typeDistance(classifiers, target, typeC, idOfX))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun `test sample 2 - indirect backwards reachable types`() {
|
||||||
|
val root = createCirTreeRootFromSourceCode(
|
||||||
|
"""
|
||||||
|
class X
|
||||||
|
typealias A = X
|
||||||
|
typealias B = X
|
||||||
|
typealias C = B
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
val idOfX = CirEntityId.create("X")
|
||||||
|
val idOfA = CirEntityId.create("A")
|
||||||
|
val idOfB = CirEntityId.create("B")
|
||||||
|
val idOfC = CirEntityId.create("C")
|
||||||
|
|
||||||
|
val typeX = mockClassType("X")
|
||||||
|
val typeA = mockTAType("A") { typeX }
|
||||||
|
val typeB = mockTAType("B") { typeX }
|
||||||
|
val typeC = mockTAType("C") { typeB }
|
||||||
|
|
||||||
|
val classifiers = CirKnownClassifiers(
|
||||||
|
classifierIndices = TargetDependent(target to CirClassifierIndex(root)),
|
||||||
|
targetDependencies = TargetDependent(target to CirProvidedClassifiers.EMPTY),
|
||||||
|
commonizedNodes = CirCommonizedClassifierNodes.default(),
|
||||||
|
commonDependencies = CirProvidedClassifiers.EMPTY
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CirTypeDistance(1),
|
||||||
|
typeDistance(classifiers, target, typeA, idOfX)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CirTypeDistance(-2),
|
||||||
|
typeDistance(classifiers, target, typeB, idOfA)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CirTypeDistance(-3),
|
||||||
|
typeDistance(classifiers, target, typeC, idOfA)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CirTypeDistance(-2),
|
||||||
|
typeDistance(classifiers, target, typeA, idOfB)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CirTypeDistance(-3),
|
||||||
|
typeDistance(classifiers, target, typeA, idOfC)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type Alias Chains:
|
||||||
|
* E -> Z
|
||||||
|
* B -> Y
|
||||||
|
* D -> C -> A -> X
|
||||||
|
*/
|
||||||
|
fun `test sample 3 - with dependencies`() {
|
||||||
|
fun InlineSourceBuilder.ModuleBuilder.commonDependencies() {
|
||||||
|
source(
|
||||||
|
"""
|
||||||
|
class X
|
||||||
|
typealias A = X
|
||||||
|
""".trimIndent(), "commonDependencies.kt"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun InlineSourceBuilder.ModuleBuilder.targetDependencies() {
|
||||||
|
dependency { commonDependencies() }
|
||||||
|
source(
|
||||||
|
"""
|
||||||
|
class Y
|
||||||
|
typealias B = Y
|
||||||
|
typealias C = A
|
||||||
|
""".trimIndent(), "targetDependencies.kt"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val root = createCirTreeRoot {
|
||||||
|
dependency { commonDependencies() }
|
||||||
|
dependency { targetDependencies() }
|
||||||
|
source(
|
||||||
|
"""
|
||||||
|
class Z
|
||||||
|
typealias D = C
|
||||||
|
typealias E = Z
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val classifiers = CirKnownClassifiers(
|
||||||
|
classifierIndices = TargetDependent(target to CirClassifierIndex(root)),
|
||||||
|
commonDependencies = createCirProvidedClassifiers { commonDependencies() },
|
||||||
|
targetDependencies = TargetDependent(target to createCirProvidedClassifiers { targetDependencies() }),
|
||||||
|
commonizedNodes = CirCommonizedClassifierNodes.default()
|
||||||
|
)
|
||||||
|
|
||||||
|
val idOfX = CirEntityId.create("X")
|
||||||
|
val idOfY = CirEntityId.create("Y")
|
||||||
|
val idOfZ = CirEntityId.create("Z")
|
||||||
|
val idOfA = CirEntityId.create("A")
|
||||||
|
val idOfB = CirEntityId.create("B")
|
||||||
|
val idOfC = CirEntityId.create("C")
|
||||||
|
val idOfD = CirEntityId.create("D")
|
||||||
|
val idOfE = CirEntityId.create("E")
|
||||||
|
|
||||||
|
val typeX = mockClassType("X")
|
||||||
|
val typeY = mockClassType("Y")
|
||||||
|
val typeZ = mockClassType("Z")
|
||||||
|
val typeA = mockTAType("A") { typeX }
|
||||||
|
val typeB = mockTAType("B") { typeY }
|
||||||
|
val typeC = mockTAType("C") { typeA }
|
||||||
|
val typeD = mockTAType("D") { typeC }
|
||||||
|
val typeE = mockTAType("E") { typeZ }
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CirTypeDistance(1), typeDistance(classifiers, target, typeA, idOfX)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CirTypeDistance(-1), typeDistance(classifiers, target, typeX, idOfA)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CirTypeDistance(1), typeDistance(classifiers, target, typeB, idOfY)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CirTypeDistance(-1), typeDistance(classifiers, target, typeY, idOfB)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CirTypeDistance(2), typeDistance(classifiers, target, typeC, idOfX)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CirTypeDistance(-2), typeDistance(classifiers, target, typeX, idOfC)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CirTypeDistance(3), typeDistance(classifiers, target, typeD, idOfX)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CirTypeDistance(-3), typeDistance(classifiers, target, typeX, idOfD)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CirTypeDistance(2), typeDistance(classifiers, target, typeD, idOfA)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CirTypeDistance(-2), typeDistance(classifiers, target, typeA, idOfD)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CirTypeDistance(1), typeDistance(classifiers, target, typeE, idOfZ)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CirTypeDistance(-1), typeDistance(classifiers, target, typeZ, idOfE)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun `test unreachable distance`() {
|
||||||
|
assertUnreachable(CirTypeDistance.unreachable() + CirTypeDistance.unreachable())
|
||||||
|
assertUnreachable(CirTypeDistance.unreachable() + 1)
|
||||||
|
assertUnreachable(CirTypeDistance.unreachable().inc())
|
||||||
|
assertUnreachable(CirTypeDistance.unreachable() + CirTypeDistance(1))
|
||||||
|
assertUnreachable(CirTypeDistance(1) + CirTypeDistance.unreachable())
|
||||||
|
assertUnreachable(CirTypeDistance.unreachable() - 1)
|
||||||
|
assertUnreachable(CirTypeDistance.unreachable().dec())
|
||||||
|
assertUnreachable(CirTypeDistance.unreachable() - CirTypeDistance(1))
|
||||||
|
assertUnreachable(CirTypeDistance(1) - CirTypeDistance.unreachable())
|
||||||
|
assertUnreachable(CirTypeDistance.unreachable().absoluteValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertUnreachable(typeDistance: CirTypeDistance) {
|
||||||
|
assertEquals(CirTypeDistance.unreachable(), typeDistance)
|
||||||
|
assertTrue(typeDistance.isNotReachable)
|
||||||
|
assertFalse(typeDistance.isReachable)
|
||||||
|
assertFalse(typeDistance.isPositive)
|
||||||
|
assertFalse(typeDistance.isNegative)
|
||||||
|
assertFalse(typeDistance.isZero)
|
||||||
|
}
|
||||||
+82
-3
@@ -158,13 +158,92 @@ class ParameterizedTypesCommonizationTest : AbstractInlineSourcesCommonizationTe
|
|||||||
typealias T3<T, M> = Triple<T, String, M>
|
typealias T3<T, M> = Triple<T, String, M>
|
||||||
typealias T4<T, M> = Triple<T, String, M>
|
typealias T4<T, M> = Triple<T, String, M>
|
||||||
|
|
||||||
/* Note: No hard requirement whether T4 or T3 is chosen! */
|
expect fun x1(x: Triple<Int, String, Long>)
|
||||||
expect fun x1(x: T4<Int, Long>)
|
expect fun x2(x: Triple<Int, String, Long>)
|
||||||
expect fun x2(x: T4<Int, Long>)
|
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun `test parameterized type alias - 3`() {
|
||||||
|
val result = commonize {
|
||||||
|
outputTarget("(a, b)")
|
||||||
|
|
||||||
|
simpleSingleSourceTarget(
|
||||||
|
"a", """
|
||||||
|
class Triple<T, R, M>
|
||||||
|
typealias T1<T, R, M> = Triple<T, R, M>
|
||||||
|
typealias T2<T, R, M> = Triple<T, R, M>
|
||||||
|
typealias T3<T, M> = Triple<T, String, M>
|
||||||
|
typealias T4<T, M> = Triple<T, String, M>
|
||||||
|
|
||||||
|
fun x1(x: T4<Int, Long>)
|
||||||
|
fun x2(x: T3<Int, Long>)
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
simpleSingleSourceTarget(
|
||||||
|
"b", """
|
||||||
|
class Triple<T, R, M>
|
||||||
|
typealias T1<T, R, M> = Triple<T, R, M>
|
||||||
|
typealias T2<T, R, M> = Triple<T, R, M>
|
||||||
|
typealias T3<T, M> = Triple<T, String, M>
|
||||||
|
typealias T4<T, M> = T3<T, M>
|
||||||
|
|
||||||
|
fun x1(x: T3<Int, Long>) // NOTE: T3 & T4 flipped
|
||||||
|
fun x2(x: T4<Int, Long>) // NOTE: T3 & T4 flipped
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
result.assertCommonized(
|
||||||
|
"(a, b)", """
|
||||||
|
expect class Triple<T, R, M>()
|
||||||
|
typealias T1<T, R, M> = Triple<T, R, M>
|
||||||
|
typealias T2<T, R, M> = Triple<T, R, M>
|
||||||
|
typealias T3<T, M> = Triple<T, String, M>
|
||||||
|
typealias T4<T, M> = Triple<T, String, M>
|
||||||
|
|
||||||
|
expect fun x1(x: Triple<Int, String, Long>)
|
||||||
|
expect fun x2(x: T3<Int, Long>)
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun `test parameterized type alias - 4`() {
|
||||||
|
val result = commonize {
|
||||||
|
outputTarget("(a, b)")
|
||||||
|
|
||||||
|
simpleSingleSourceTarget(
|
||||||
|
"a", """
|
||||||
|
class Triple<T, R, M>
|
||||||
|
typealias A1 = String
|
||||||
|
typealias A2 = Long
|
||||||
|
typealias A3<T, R> = Triple<T, String, R>
|
||||||
|
|
||||||
|
fun x(x: A3<A1, A2>)
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
simpleSingleSourceTarget(
|
||||||
|
"b", """
|
||||||
|
class Triple<T, R, M>
|
||||||
|
typealias B1 = String
|
||||||
|
typealias B2 = Long
|
||||||
|
|
||||||
|
fun x(x: Triple<B1, String, B2>)
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
result.assertCommonized(
|
||||||
|
"(a, b)", """
|
||||||
|
expect class Triple<T, R, M>()
|
||||||
|
expect fun x(x: Triple<String, String, Long>)
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fun `test type alias from dependencies parameterized with library source type`() {
|
fun `test type alias from dependencies parameterized with library source type`() {
|
||||||
val result = commonize {
|
val result = commonize {
|
||||||
outputTarget("(a, b)")
|
outputTarget("(a, b)")
|
||||||
|
|||||||
+1
-1
@@ -62,7 +62,7 @@ class UnderscoredTypeAliasTypeSubstitutonTest : AbstractInlineSourcesCommonizati
|
|||||||
typealias X = Int
|
typealias X = Int
|
||||||
typealias __X = X
|
typealias __X = X
|
||||||
/* No hard requirement. Picking X over __X seems equally fine here */
|
/* No hard requirement. Picking X over __X seems equally fine here */
|
||||||
expect fun x(x: __X)
|
expect fun x(x: X)
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user