[K2, MPP] Correct actualization of nested objects

^KT-57182 Fixed
This commit is contained in:
Ivan Kochurkin
2023-03-06 23:05:29 +01:00
committed by Space Team
parent 8a3e2543f7
commit d99b4c78d2
4 changed files with 42 additions and 45 deletions
@@ -33,7 +33,7 @@ internal class ExpectActualCollector(
} }
private fun MutableMap<IrSymbol, IrSymbol>.appendExpectActualClassifiersMap(): Pair<Set<IrDeclaration>, Map<FqName, FqName>> { private fun MutableMap<IrSymbol, IrSymbol>.appendExpectActualClassifiersMap(): Pair<Set<IrDeclaration>, Map<FqName, FqName>> {
val actualClassifiers = mutableMapOf<FqName, IrSymbol>() val actualClassifiers = mutableMapOf<String, IrSymbol>()
// There is no list for builtins declarations; that's why they are being collected from typealiases // There is no list for builtins declarations; that's why they are being collected from typealiases
val allActualDeclarations = mutableSetOf<IrDeclaration>() val allActualDeclarations = mutableSetOf<IrDeclaration>()
val typeAliasMap = mutableMapOf<FqName, FqName>() // It's used to link members from expect class that have typealias actual val typeAliasMap = mutableMapOf<FqName, FqName>() // It's used to link members from expect class that have typealias actual
@@ -43,7 +43,7 @@ internal class ExpectActualCollector(
ActualClassifiersCollector(actualClassifiers, allActualDeclarations, typeAliasMap).visitModuleFragment(fragment, false) ActualClassifiersCollector(actualClassifiers, allActualDeclarations, typeAliasMap).visitModuleFragment(fragment, false)
} }
val linkCollector = ClassifiersLinkCollector(this, actualClassifiers, diagnosticsReporter) val linkCollector = ClassifiersLinkCollector(this, actualClassifiers, typeAliasMap, diagnosticsReporter)
dependentFragments.forEach { linkCollector.visitModuleFragment(it) } dependentFragments.forEach { linkCollector.visitModuleFragment(it) }
return allActualDeclarations to typeAliasMap return allActualDeclarations to typeAliasMap
@@ -55,21 +55,21 @@ internal class ExpectActualCollector(
) { ) {
val actualMembers = mutableMapOf<String, IrDeclarationBase>() val actualMembers = mutableMapOf<String, IrDeclarationBase>()
collectActualCallables(this, actualMembers, allActualDeclarations) collectActualCallables(this, actualMembers, typeAliasMap, allActualDeclarations)
val collector = CallablesLinkCollector(this, actualMembers, typeAliasMap, diagnosticsReporter) val collector = CallablesLinkCollector(this, actualMembers, typeAliasMap, diagnosticsReporter)
dependentFragments.forEach { collector.visitModuleFragment(it) } dependentFragments.forEach { collector.visitModuleFragment(it) }
} }
} }
private class ActualClassifiersCollector( private class ActualClassifiersCollector(
private val actualClassifiers: MutableMap<FqName, IrSymbol>, private val actualClassifiers: MutableMap<String, IrSymbol>,
private val allActualClassifiers: MutableSet<IrDeclaration>, private val allActualClassifiers: MutableSet<IrDeclaration>,
private val typeAliasMap: MutableMap<FqName, FqName> private val typeAliasMap: MutableMap<FqName, FqName>
) : IrElementVisitor<Unit, Boolean> { ) : IrElementVisitor<Unit, Boolean> {
override fun visitTypeAlias(declaration: IrTypeAlias, data: Boolean) { override fun visitTypeAlias(declaration: IrTypeAlias, data: Boolean) {
if (declaration.isActual) { if (declaration.isActual) {
val expandedTypeSymbol = declaration.expandedType.classifierOrFail val expandedTypeSymbol = declaration.expandedType.classifierOrFail
actualClassifiers[declaration.kotlinFqName] = expandedTypeSymbol actualClassifiers[generateIrElementFullName(declaration)] = expandedTypeSymbol
if (expandedTypeSymbol is IrClassSymbol) { if (expandedTypeSymbol is IrClassSymbol) {
allActualClassifiers.add(expandedTypeSymbol.owner) allActualClassifiers.add(expandedTypeSymbol.owner)
typeAliasMap[declaration.kotlinFqName] = expandedTypeSymbol.owner.kotlinFqName typeAliasMap[declaration.kotlinFqName] = expandedTypeSymbol.owner.kotlinFqName
@@ -80,19 +80,14 @@ private class ActualClassifiersCollector(
override fun visitClass(declaration: IrClass, data: Boolean) { override fun visitClass(declaration: IrClass, data: Boolean) {
if (!data && !declaration.isExpect) { if (!data && !declaration.isExpect) {
actualClassifiers[declaration.kotlinFqName] = declaration.symbol actualClassifiers[generateIrElementFullName(declaration)] = declaration.symbol
} }
visitDeclaration(declaration, data) visitDeclaration(declaration, data)
} }
override fun visitEnumEntry(declaration: IrEnumEntry, data: Boolean) { override fun visitEnumEntry(declaration: IrEnumEntry, data: Boolean) {
if (!data && !declaration.isExpect) { if (!data && !declaration.isExpect) {
actualClassifiers[FqName.fromSegments( actualClassifiers[generateIrElementFullName(declaration)] = declaration.symbol
listOf(
declaration.parent.kotlinFqName.asString(),
declaration.name.asString()
)
)] = declaration.symbol
} }
visitDeclaration(declaration, data) visitDeclaration(declaration, data)
} }
@@ -111,11 +106,12 @@ private class ActualClassifiersCollector(
private class ClassifiersLinkCollector( private class ClassifiersLinkCollector(
private val expectActualMap: MutableMap<IrSymbol, IrSymbol>, private val expectActualMap: MutableMap<IrSymbol, IrSymbol>,
private val actualClassifiers: Map<FqName, IrSymbol>, private val actualClassifiers: Map<String, IrSymbol>,
private val typeAliasMap: Map<FqName, FqName>,
private val diagnosticsReporter: KtDiagnosticReporterWithImplicitIrBasedContext private val diagnosticsReporter: KtDiagnosticReporterWithImplicitIrBasedContext
) : IrElementVisitorVoid { ) : IrElementVisitorVoid {
private fun addLinkOrReportMissing(expectElement: IrDeclaration, actualTypeId: FqName) { private fun addLinkOrReportMissing(expectElement: IrDeclaration) {
val actualClassifier = actualClassifiers[actualTypeId] val actualClassifier = actualClassifiers[generateIrElementFullName(expectElement, expectActualMap, typeAliasMap)]
if (actualClassifier != null) { if (actualClassifier != null) {
expectActualMap[expectElement.symbol] = actualClassifier expectActualMap[expectElement.symbol] = actualClassifier
} else if (!expectElement.containsOptionalExpectation()) { } else if (!expectElement.containsOptionalExpectation()) {
@@ -125,16 +121,14 @@ private class ClassifiersLinkCollector(
override fun visitClass(declaration: IrClass) { override fun visitClass(declaration: IrClass) {
if (declaration.isExpect) { if (declaration.isExpect) {
addLinkOrReportMissing(declaration, declaration.kotlinFqName) addLinkOrReportMissing(declaration)
} }
visitElement(declaration) visitElement(declaration)
} }
override fun visitEnumEntry(declaration: IrEnumEntry) { override fun visitEnumEntry(declaration: IrEnumEntry) {
if (declaration.isProperExpect) { if (declaration.isProperExpect) {
addLinkOrReportMissing( addLinkOrReportMissing(declaration)
declaration, FqName.fromSegments(listOf(declaration.parent.kotlinFqName.asString(), declaration.name.asString()))
)
} }
visitElement(declaration) visitElement(declaration)
} }
@@ -147,13 +141,14 @@ private class ClassifiersLinkCollector(
private fun collectActualCallables( private fun collectActualCallables(
expectActualMap: MutableMap<IrSymbol, IrSymbol>, expectActualMap: MutableMap<IrSymbol, IrSymbol>,
actualMembers: MutableMap<String, IrDeclarationBase>, actualMembers: MutableMap<String, IrDeclarationBase>,
typeAliasMap: Map<FqName, FqName>,
allActualDeclarations: Set<IrDeclaration>, allActualDeclarations: Set<IrDeclaration>,
) { ) {
fun collectActualsCallables(declaration: IrDeclaration) { fun collectActualsCallables(declaration: IrDeclaration) {
when (declaration) { when (declaration) {
is IrFunction, is IrFunction,
is IrProperty -> { is IrProperty -> {
actualMembers[generateIrElementFullName(declaration, expectActualMap)] = declaration as IrDeclarationBase actualMembers[generateIrElementFullName(declaration, expectActualMap, typeAliasMap)] = declaration as IrDeclarationBase
} }
is IrClass -> { is IrClass -> {
for (member in declaration.declarations) { for (member in declaration.declarations) {
@@ -22,23 +22,40 @@ import org.jetbrains.kotlin.resolve.multiplatform.OptionalAnnotationUtil
fun generateIrElementFullName( fun generateIrElementFullName(
declaration: IrElement, declaration: IrElement,
expectActualTypesMap: Map<IrSymbol, IrSymbol>, expectActualTypesMap: Map<IrSymbol, IrSymbol>? = null,
typeAliasMap: Map<FqName, FqName>? = null typeAliasMap: Map<FqName, FqName>? = null
): String { ): String {
return StringBuilder().apply { appendElementFullName(declaration, expectActualTypesMap, this, typeAliasMap) }.toString() return StringBuilder().apply { appendElementFullName(declaration, this, expectActualTypesMap, typeAliasMap) }.toString()
} }
private fun appendElementFullName( private fun appendElementFullName(
declaration: IrElement, declaration: IrElement,
expectActualTypesMap: Map<IrSymbol, IrSymbol>,
result: StringBuilder, result: StringBuilder,
typeAliasMap: Map<FqName, FqName>? = null expectActualTypesMap: Map<IrSymbol, IrSymbol>? = null,
expectActualTypeAliasMap: Map<FqName, FqName>? = null
) { ) {
if (declaration !is IrDeclarationBase) return if (declaration !is IrDeclarationBase) return
val parentName = declaration.parent.kotlinFqName val parents = mutableListOf<String>()
if (parentName.asString().isNotEmpty()) { var parent: IrDeclarationParent? = declaration.parent
result.append(typeAliasMap?.get(parentName) ?: parentName.asString()) while (parent != null) {
if (parent is IrDeclarationWithName) {
val parentParent = parent.parent
if (parentParent is IrClass) {
parents.add(parent.name.asString())
parent = parentParent
continue
}
}
val parentString = parent.kotlinFqName.let { (expectActualTypeAliasMap?.get(it) ?: it).asString() }
if (parentString.isNotEmpty()) {
parents.add(parentString)
}
parent = null
}
if (parents.isNotEmpty()) {
result.append(parents.asReversed().joinToString(separator = "."))
result.append('.') result.append('.')
} }
@@ -49,8 +66,8 @@ private fun appendElementFullName(
if (declaration is IrFunction) { if (declaration is IrFunction) {
fun appendType(type: IrType) { fun appendType(type: IrType) {
val typeClassifier = type.classifierOrFail val typeClassifier = type.classifierOrFail
val actualizedTypeSymbol = expectActualTypesMap[typeClassifier] ?: typeClassifier val actualizedTypeSymbol = expectActualTypesMap?.get(typeClassifier) ?: typeClassifier
appendElementFullName(actualizedTypeSymbol.owner, expectActualTypesMap, result) appendElementFullName(actualizedTypeSymbol.owner, result, expectActualTypesMap)
} }
val extensionReceiverType = declaration.extensionReceiverParameter?.type val extensionReceiverType = declaration.extensionReceiverParameter?.type
@@ -1,16 +0,0 @@
// MODULE: m1-common
// FILE: common.kt
expect sealed class Presence {
<!NO_ACTUAL_FOR_EXPECT{JVM}!>object Online: Presence<!>
<!NO_ACTUAL_FOR_EXPECT{JVM}!>object Offline: Presence<!>
}
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
actual typealias Presence = P
sealed class P {
object Online : P()
object Offline : P()
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// MODULE: m1-common // MODULE: m1-common
// FILE: common.kt // FILE: common.kt