[K2, MPP] Restore ir functions actualization by argument types instead of full signatures

Refactor IrActualizer
This commit is contained in:
Ivan Kochurkin
2023-03-09 20:14:08 +01:00
committed by Space Team
parent d99b4c78d2
commit ec34b9fa7b
6 changed files with 193 additions and 154 deletions
@@ -6,15 +6,12 @@
package org.jetbrains.kotlin.backend.common.actualizer
import org.jetbrains.kotlin.KtDiagnosticReporterWithImplicitIrBasedContext
import org.jetbrains.kotlin.backend.common.ir.isExpect
import org.jetbrains.kotlin.backend.common.ir.isProperExpect
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.util.kotlinFqName
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.name.FqName
@@ -26,110 +23,119 @@ internal class ExpectActualCollector(
) {
fun collect(): Pair<Map<IrSymbol, IrSymbol>, Map<FqName, FqName>> {
val result = mutableMapOf<IrSymbol, IrSymbol>()
// Collect and link classifiers at first to make it possible to expand type aliases on the callables linking
val (allActualDeclarations, typeAliasMap) = result.appendExpectActualClassifiersMap()
result.appendExpectActualCallablesMap(allActualDeclarations, typeAliasMap)
return result to typeAliasMap
// Collect and link classes at first to make it possible to expand type aliases on the members linking
val (actualMembers, expectActualTypeAliasMap) = result.appendExpectActualClassMap()
result.appendExpectActualMemberMap(actualMembers, expectActualTypeAliasMap)
return result to expectActualTypeAliasMap
}
private fun MutableMap<IrSymbol, IrSymbol>.appendExpectActualClassifiersMap(): Pair<Set<IrDeclaration>, Map<FqName, FqName>> {
val actualClassifiers = mutableMapOf<String, IrSymbol>()
private fun MutableMap<IrSymbol, IrSymbol>.appendExpectActualClassMap(): Pair<List<IrDeclarationBase>, Map<FqName, FqName>> {
val actualClasses = mutableMapOf<String, IrClassSymbol>()
// There is no list for builtins declarations; that's why they are being collected from typealiases
val allActualDeclarations = mutableSetOf<IrDeclaration>()
val typeAliasMap = mutableMapOf<FqName, FqName>() // It's used to link members from expect class that have typealias actual
val actualMembers = mutableListOf<IrDeclarationBase>()
val expectActualTypeAliasMap = mutableMapOf<FqName, FqName>() // It's used to link members from expect class that have typealias actual
val fragmentsWithActuals = (dependentFragments.drop(1) + mainFragment)
for (fragment in fragmentsWithActuals) {
ActualClassifiersCollector(actualClassifiers, allActualDeclarations, typeAliasMap).visitModuleFragment(fragment, false)
}
val fragmentsWithActuals = dependentFragments.drop(1) + mainFragment
val actualClassesAndMembersCollector = ActualClassesAndMembersCollector(actualClasses, actualMembers, expectActualTypeAliasMap)
fragmentsWithActuals.forEach { actualClassesAndMembersCollector.collect(it) }
val linkCollector = ClassifiersLinkCollector(this, actualClassifiers, typeAliasMap, diagnosticsReporter)
val linkCollector = ClassLinksCollector(this, actualClasses, expectActualTypeAliasMap, diagnosticsReporter)
dependentFragments.forEach { linkCollector.visitModuleFragment(it) }
return allActualDeclarations to typeAliasMap
return actualMembers to expectActualTypeAliasMap
}
private fun MutableMap<IrSymbol, IrSymbol>.appendExpectActualCallablesMap(
allActualDeclarations: Set<IrDeclaration>,
typeAliasMap: Map<FqName, FqName>
private fun MutableMap<IrSymbol, IrSymbol>.appendExpectActualMemberMap(
actualMembers: List<IrDeclarationBase>,
expectActualTypeAliasMap: Map<FqName, FqName>
) {
val actualMembers = mutableMapOf<String, IrDeclarationBase>()
collectActualCallables(this, actualMembers, typeAliasMap, allActualDeclarations)
val collector = CallablesLinkCollector(this, actualMembers, typeAliasMap, diagnosticsReporter)
val actualMembersMap = mutableMapOf<String, MutableList<IrDeclarationBase>>()
for (actualMember in actualMembers) {
actualMembersMap.getOrPut(generateIrElementFullNameFromExpect(actualMember, expectActualTypeAliasMap)) { mutableListOf() }
.add(actualMember)
}
val collector = MemberLinksCollector(this, actualMembersMap, expectActualTypeAliasMap, diagnosticsReporter)
dependentFragments.forEach { collector.visitModuleFragment(it) }
}
}
private class ActualClassifiersCollector(
private val actualClassifiers: MutableMap<String, IrSymbol>,
private val allActualClassifiers: MutableSet<IrDeclaration>,
private val typeAliasMap: MutableMap<FqName, FqName>
) : IrElementVisitor<Unit, Boolean> {
override fun visitTypeAlias(declaration: IrTypeAlias, data: Boolean) {
if (declaration.isActual) {
val expandedTypeSymbol = declaration.expandedType.classifierOrFail
actualClassifiers[generateIrElementFullName(declaration)] = expandedTypeSymbol
if (expandedTypeSymbol is IrClassSymbol) {
allActualClassifiers.add(expandedTypeSymbol.owner)
typeAliasMap[declaration.kotlinFqName] = expandedTypeSymbol.owner.kotlinFqName
private class ActualClassesAndMembersCollector(
private val actualClasses: MutableMap<String, IrClassSymbol>,
private val actualMembers: MutableList<IrDeclarationBase>,
private val expectActualTypeAliasMap: MutableMap<FqName, FqName>
) {
private val visitedActualClasses = mutableSetOf<IrClass>()
fun collect(element: IrElement) {
when (element) {
is IrModuleFragment -> {
for (file in element.files) {
collect(file)
}
}
is IrTypeAlias -> {
if (!element.isActual) return
val expandedTypeSymbol = element.expandedType.classifierOrFail as IrClassSymbol
addActualClass(element, expandedTypeSymbol)
collect(expandedTypeSymbol.owner)
expectActualTypeAliasMap[element.kotlinFqName] = expandedTypeSymbol.owner.kotlinFqName
}
is IrClass -> {
if (element.isExpect || !visitedActualClasses.add(element)) return
addActualClass(element, element.symbol)
for (declaration in element.declarations) {
collect(declaration)
}
}
is IrDeclarationContainer -> {
for (declaration in element.declarations) {
collect(declaration)
}
}
is IrEnumEntry -> {
actualMembers.add(element) // If enum entry is located inside expect enum, then this code is not executed
}
is IrProperty -> {
if (element.isExpect) return
actualMembers.add(element)
}
is IrFunction -> {
if (element.isExpect) return
actualMembers.add(element)
}
}
visitElement(declaration, data)
}
override fun visitClass(declaration: IrClass, data: Boolean) {
if (!data && !declaration.isExpect) {
actualClassifiers[generateIrElementFullName(declaration)] = declaration.symbol
}
visitDeclaration(declaration, data)
}
override fun visitEnumEntry(declaration: IrEnumEntry, data: Boolean) {
if (!data && !declaration.isExpect) {
actualClassifiers[generateIrElementFullName(declaration)] = declaration.symbol
}
visitDeclaration(declaration, data)
}
override fun visitDeclaration(declaration: IrDeclarationBase, data: Boolean) {
if (!data && !declaration.isExpect) {
allActualClassifiers.add(declaration)
}
visitElement(declaration, data || declaration.isExpect)
}
override fun visitElement(element: IrElement, data: Boolean) {
element.acceptChildren(this, data)
private fun addActualClass(classOrTypeAlias: IrElement, classSymbol: IrClassSymbol) {
actualClasses[generateActualIrClassOrTypeAliasFullName(classOrTypeAlias)] = classSymbol
}
}
private class ClassifiersLinkCollector(
private class ClassLinksCollector(
private val expectActualMap: MutableMap<IrSymbol, IrSymbol>,
private val actualClassifiers: Map<String, IrSymbol>,
private val typeAliasMap: Map<FqName, FqName>,
private val actualClasses: Map<String, IrClassSymbol>,
private val expectActualTypeAliasMap: Map<FqName, FqName>,
private val diagnosticsReporter: KtDiagnosticReporterWithImplicitIrBasedContext
) : IrElementVisitorVoid {
private fun addLinkOrReportMissing(expectElement: IrDeclaration) {
val actualClassifier = actualClassifiers[generateIrElementFullName(expectElement, expectActualMap, typeAliasMap)]
if (actualClassifier != null) {
expectActualMap[expectElement.symbol] = actualClassifier
} else if (!expectElement.containsOptionalExpectation()) {
diagnosticsReporter.reportMissingActual(expectElement)
}
}
override fun visitClass(declaration: IrClass) {
if (declaration.isExpect) {
addLinkOrReportMissing(declaration)
}
visitElement(declaration)
}
if (!declaration.isExpect) return
override fun visitEnumEntry(declaration: IrEnumEntry) {
if (declaration.isProperExpect) {
addLinkOrReportMissing(declaration)
val actualClassSymbol = actualClasses[generateIrElementFullNameFromExpect(declaration, expectActualTypeAliasMap)]
if (actualClassSymbol != null) {
expectActualMap[declaration.symbol] = actualClassSymbol
val actualClass = actualClassSymbol.owner
for (expectTypeParameter in declaration.typeParameters) {
actualClass.typeParameters.firstOrNull { it.name == expectTypeParameter.name }?.let { actualTypeParameter ->
expectActualMap[expectTypeParameter.symbol] = actualTypeParameter.symbol
}
}
} else if (!declaration.containsOptionalExpectation()) {
diagnosticsReporter.reportMissingActual(declaration)
}
visitElement(declaration)
}
@@ -138,44 +144,26 @@ private class ClassifiersLinkCollector(
}
}
private fun collectActualCallables(
expectActualMap: MutableMap<IrSymbol, IrSymbol>,
actualMembers: MutableMap<String, IrDeclarationBase>,
typeAliasMap: Map<FqName, FqName>,
allActualDeclarations: Set<IrDeclaration>,
) {
fun collectActualsCallables(declaration: IrDeclaration) {
when (declaration) {
is IrFunction,
is IrProperty -> {
actualMembers[generateIrElementFullName(declaration, expectActualMap, typeAliasMap)] = declaration as IrDeclarationBase
}
is IrClass -> {
for (member in declaration.declarations) {
collectActualsCallables(member)
}
}
}
}
for (actualDeclaration in allActualDeclarations) {
collectActualsCallables(actualDeclaration)
}
}
private class CallablesLinkCollector(
private class MemberLinksCollector(
private val expectActualMap: MutableMap<IrSymbol, IrSymbol>,
private val actualMembers: Map<String, IrDeclarationBase>,
private val actualMembers: Map<String, List<IrDeclarationBase>>,
private val typeAliasMap: Map<FqName, FqName>,
private val diagnosticsReporter: KtDiagnosticReporterWithImplicitIrBasedContext
) : IrElementVisitorVoid {
override fun visitFunction(declaration: IrFunction) = addLink(declaration)
override fun visitFunction(declaration: IrFunction) {
if (declaration.isExpect) addLink(declaration)
}
override fun visitProperty(declaration: IrProperty) = addLink(declaration)
override fun visitProperty(declaration: IrProperty) {
if (declaration.isExpect) addLink(declaration)
}
override fun visitEnumEntry(declaration: IrEnumEntry) {
if ((declaration.parent as IrClass).isExpect) addLink(declaration)
}
private fun addLink(declaration: IrDeclarationBase) {
if (!declaration.isExpect) return
val actualMember = actualMembers[generateIrElementFullName(declaration, expectActualMap, typeAliasMap)]
val actualMember = actualMembers.getMatch(declaration, expectActualMap, typeAliasMap)
if (actualMember != null) {
expectActualMap[declaration.symbol] = actualMember.symbol
if (declaration is IrProperty) {
@@ -20,10 +20,10 @@ object IrActualizer {
languageVersionSettings: LanguageVersionSettings
) {
val ktDiagnosticReporter = KtDiagnosticReporterWithImplicitIrBasedContext(diagnosticReporter, languageVersionSettings)
val (expectActualMap, typeAliasMap) = ExpectActualCollector(mainFragment, dependentFragments, ktDiagnosticReporter).collect()
val (expectActualMap, expectActualTypeAliasMap) = ExpectActualCollector(mainFragment, dependentFragments, ktDiagnosticReporter).collect()
FunctionDefaultParametersActualizer(expectActualMap).actualize()
removeExpectDeclarations(dependentFragments, expectActualMap)
addMissingFakeOverrides(expectActualMap, dependentFragments, typeAliasMap, ktDiagnosticReporter)
addMissingFakeOverrides(expectActualMap, dependentFragments, expectActualTypeAliasMap, ktDiagnosticReporter)
linkExpectToActual(expectActualMap, dependentFragments)
mergeIrFragments(mainFragment, dependentFragments)
}
@@ -48,10 +48,14 @@ object IrActualizer {
private fun addMissingFakeOverrides(
expectActualMap: Map<IrSymbol, IrSymbol>,
dependentFragments: List<IrModuleFragment>,
typeAliasMap: Map<FqName, FqName>,
expectActualTypeAliasMap: Map<FqName, FqName>,
diagnosticsReporter: KtDiagnosticReporterWithImplicitIrBasedContext
) {
MissingFakeOverridesAdder(expectActualMap, typeAliasMap, diagnosticsReporter).apply { dependentFragments.forEach { visitModuleFragment(it) } }
MissingFakeOverridesAdder(
expectActualMap,
expectActualTypeAliasMap,
diagnosticsReporter
).apply { dependentFragments.forEach { visitModuleFragment(it) } }
}
private fun linkExpectToActual(expectActualMap: Map<IrSymbol, IrSymbol>, dependentFragments: List<IrModuleFragment>) {
@@ -12,27 +12,95 @@ import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.util.hasAnnotation
import org.jetbrains.kotlin.ir.util.kotlinFqName
import org.jetbrains.kotlin.ir.util.module
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.multiplatform.OptionalAnnotationUtil
import org.jetbrains.kotlin.utils.addToStdlib.runIf
fun generateIrElementFullName(
fun Map<String, List<IrDeclaration>>.getMatch(
expectDeclaration: IrDeclaration,
expectActualTypesMap: Map<IrSymbol, IrSymbol>,
expectActualTypeAliasMap: Map<FqName, FqName>
): IrDeclaration? {
val members = this[generateIrElementFullNameFromExpect(expectDeclaration, expectActualTypeAliasMap)] ?: return null
return if (expectDeclaration is IrFunction) {
members.firstNotNullOfOrNull { runIf(expectDeclaration.match(it as IrFunction, expectActualTypesMap)) { it } }
} else {
members.singleOrNull()
}
}
private fun IrFunction.match(actualFunction: IrFunction, expectActualTypesMap: Map<IrSymbol, IrSymbol>): Boolean {
fun checkParameter(
expectParameter: IrValueParameter?,
actualParameter: IrValueParameter?,
typeParametersMap: Map<IrTypeParameterSymbol, IrTypeParameterSymbol>
): Boolean {
if (expectParameter == null) {
return actualParameter == null
}
if (actualParameter == null) {
return false
}
val actualizedParameterTypeSymbol = expectParameter.type.classifierOrFail.let {
var mappedSymbol: IrSymbol? = null
if (it is IrTypeParameterSymbol) {
mappedSymbol = typeParametersMap[it]
}
if (mappedSymbol == null) {
mappedSymbol = expectActualTypesMap[it] ?: it
}
mappedSymbol
}
if (actualizedParameterTypeSymbol != actualParameter.type.classifierOrFail) {
return false
}
return true
}
if (valueParameters.size != actualFunction.valueParameters.size || typeParameters.size != actualFunction.typeParameters.size) {
return false
}
val typeParametersMap = mutableMapOf<IrTypeParameterSymbol, IrTypeParameterSymbol>()
for ((expectTypeParameter, actualTypeParameter) in typeParameters.zip(actualFunction.typeParameters)) {
if (expectTypeParameter.name != actualTypeParameter.name) {
return false
}
typeParametersMap[expectTypeParameter.symbol] = actualTypeParameter.symbol
}
if (!checkParameter(extensionReceiverParameter, actualFunction.extensionReceiverParameter, typeParametersMap)) {
return false
}
for ((expectParameter, actualParameter) in valueParameters.zip(actualFunction.valueParameters)) {
if (!checkParameter(expectParameter, actualParameter, typeParametersMap)) {
return false
}
}
return true
}
fun generateActualIrClassOrTypeAliasFullName(declaration: IrElement) = generateIrElementFullNameFromExpect(declaration, emptyMap())
fun generateIrElementFullNameFromExpect(
declaration: IrElement,
expectActualTypesMap: Map<IrSymbol, IrSymbol>? = null,
typeAliasMap: Map<FqName, FqName>? = null
expectActualTypeAliasMap: Map<FqName, FqName>
): String {
return StringBuilder().apply { appendElementFullName(declaration, this, expectActualTypesMap, typeAliasMap) }.toString()
return StringBuilder().apply { appendElementFullName(declaration, this, expectActualTypeAliasMap) }.toString()
}
private fun appendElementFullName(
declaration: IrElement,
result: StringBuilder,
expectActualTypesMap: Map<IrSymbol, IrSymbol>? = null,
expectActualTypeAliasMap: Map<FqName, FqName>? = null
expectActualTypeAliasMap: Map<FqName, FqName>
) {
if (declaration !is IrDeclarationBase) return
@@ -47,7 +115,7 @@ private fun appendElementFullName(
continue
}
}
val parentString = parent.kotlinFqName.let { (expectActualTypeAliasMap?.get(it) ?: it).asString() }
val parentString = parent.kotlinFqName.let { (expectActualTypeAliasMap[it] ?: it).asString() }
if (parentString.isNotEmpty()) {
parents.add(parentString)
}
@@ -64,27 +132,7 @@ private fun appendElementFullName(
}
if (declaration is IrFunction) {
fun appendType(type: IrType) {
val typeClassifier = type.classifierOrFail
val actualizedTypeSymbol = expectActualTypesMap?.get(typeClassifier) ?: typeClassifier
appendElementFullName(actualizedTypeSymbol.owner, result, expectActualTypesMap)
}
val extensionReceiverType = declaration.extensionReceiverParameter?.type
if (extensionReceiverType != null) {
result.append('[')
appendType(extensionReceiverType)
result.append(']')
}
result.append('(')
for ((index, parameter) in declaration.valueParameters.withIndex()) {
appendType(parameter.type)
if (index < declaration.valueParameters.size - 1) {
result.append(',')
}
}
result.append(')')
result.append("()")
}
}
@@ -39,9 +39,12 @@ class MissingFakeOverridesAdder(
private fun processSupertypes(declaration: IrClass) {
val members by lazy(LazyThreadSafetyMode.NONE) {
declaration.declarations.filter { !it.isBuiltinMember() }.associateBy {
generateIrElementFullName(it, expectActualMap, typeAliasMap)
val notBuiltinMembers = declaration.declarations.filter { !it.isBuiltinMember() }
val result = mutableMapOf<String, MutableList<IrDeclaration>>()
for (member in notBuiltinMembers) {
result.getOrPut(generateIrElementFullNameFromExpect(member, typeAliasMap)) { mutableListOf() }.add(member)
}
result
}
for (superType in declaration.superTypes) {
@@ -68,15 +71,11 @@ class MissingFakeOverridesAdder(
}
}
private fun addFakeOverride(
actualMember: IrDeclaration,
members: Map<String, IrDeclaration>,
declaration: IrClass
) {
private fun addFakeOverride(actualMember: IrDeclaration, members: Map<String, List<IrDeclaration>>, declaration: IrClass) {
when (actualMember) {
is IrFunctionImpl,
is IrPropertyImpl -> {
if (members[generateIrElementFullName(actualMember, expectActualMap, typeAliasMap)] != null) {
if (members.getMatch(actualMember, expectActualMap, typeAliasMap) != null) {
diagnosticsReporter.reportManyInterfacesMembersNotImplemented(declaration, actualMember as IrDeclarationWithName)
return
}
@@ -2,7 +2,7 @@
// FILE: common.kt
<!NO_ACTUAL_FOR_EXPECT{JVM}!>expect enum class Foo {
<!NO_ACTUAL_FOR_EXPECT{JVM}!>ENTRY<!>
ENTRY
}<!>
expect enum class _TimeUnit
@@ -8,7 +8,7 @@ expect class Foo {
<!NO_ACTUAL_FOR_EXPECT{JVM}!>fun f2(s: List<String>?): MutableMap<Boolean?, Foo><!>
<!NO_ACTUAL_FOR_EXPECT{JVM}!>fun <T : Set<Number>> f3(t: T): T?<!>
fun <T : Set<Number>> f3(t: T): T?
}
// MODULE: m2-jvm()()(m1-common)