[K2, MPP] Fix actualization of fake overrides (fixes a set of bugs in coroutines / ktor)
Split MissingFakeOverridesAdder on FakeOverridesActualizer and ActualFakeOverridesAdder ^KT-57984 Fixed ^KT-58003 Fixed ^KT-58124 Fixed ^KT-57833 Fixed ^KT-58153 Fixed
This commit is contained in:
committed by
Space Team
parent
58f8e25bfe
commit
432c781ff7
+7
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.diagnostics.rendering.RootDiagnosticRendererFactory
|
||||
object CommonBackendErrors {
|
||||
val NO_ACTUAL_FOR_EXPECT by error2<PsiElement, String, ModuleDescriptor>()
|
||||
val MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED by error2<PsiElement, String, String>()
|
||||
val MANY_IMPL_MEMBER_NOT_IMPLEMENTED by error2<PsiElement, String, String>()
|
||||
|
||||
init {
|
||||
RootDiagnosticRendererFactory.registerFactory(KtDefaultCommonBackendErrorMessages)
|
||||
@@ -37,5 +38,11 @@ object KtDefaultCommonBackendErrorMessages : BaseDiagnosticRendererFactory() {
|
||||
STRING,
|
||||
STRING,
|
||||
)
|
||||
map.put(
|
||||
CommonBackendErrors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED,
|
||||
"{0} must override {1} because it inherits many implementations of it",
|
||||
STRING,
|
||||
STRING,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.backend.common.actualizer
|
||||
|
||||
import org.jetbrains.kotlin.KtDiagnosticReporterWithImplicitIrBasedContext
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendErrors
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
import org.jetbrains.kotlin.ir.util.isInterface
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
|
||||
/**
|
||||
* It adds fake overrides to non-expect classes inside common or multi-platform module,
|
||||
* taken from these non-expect classes actualized super classes.
|
||||
*
|
||||
* In case when a non-expect class has direct or indirect expect supertypes,
|
||||
* it may happen that the actual classes for these supertypes contain additional (non-actual) members that don't exist in their expect counterparts.
|
||||
* We still should have fake overrides generated for these members, but FIR2IR isn't able to see their base members in common or multi-platform module.
|
||||
* This class is intended to search for such situations and generate such fake overrides.
|
||||
*/
|
||||
internal class ActualFakeOverridesAdder(
|
||||
private val expectActualMap: Map<IrSymbol, IrSymbol>,
|
||||
private val diagnosticsReporter: KtDiagnosticReporterWithImplicitIrBasedContext
|
||||
) : IrElementVisitorVoid {
|
||||
private val missingActualMembersMap = mutableMapOf<IrClass, MutableMap<String, MutableList<IrDeclaration>>>()
|
||||
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
extractMissingActualMembersFromSupertypes(declaration)
|
||||
visitElement(declaration)
|
||||
}
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
private fun extractMissingActualMembersFromSupertypes(klass: IrClass): Map<String, MutableList<IrDeclaration>> {
|
||||
missingActualMembersMap[klass]?.let { return it }
|
||||
|
||||
val missingActualMembers = mutableMapOf<String, MutableList<IrDeclaration>>()
|
||||
missingActualMembersMap[klass] = missingActualMembers
|
||||
|
||||
// New members from supertypes are only relevant for not expect (ordinary) classes
|
||||
// New members from the current class are only relevant for actualized expect classes
|
||||
|
||||
val processedMembers = mutableMapOf<String, MutableList<IrDeclaration>>()
|
||||
for (superType in klass.superTypes) {
|
||||
val membersFromSupertype = extractMissingActualMembersFromSupertypes(superType.classifierOrFail.owner as IrClass)
|
||||
if (!klass.isExpect) {
|
||||
missingActualMembers.appendMissingMembersToNotExpectClass(klass, membersFromSupertype, processedMembers)
|
||||
}
|
||||
}
|
||||
|
||||
val actualClass = expectActualMap[klass.symbol]?.owner as? IrClass ?: return missingActualMembers
|
||||
|
||||
missingActualMembers.appendMissingMembersFromActualizedExpectClass(klass, actualClass)
|
||||
|
||||
return missingActualMembers
|
||||
}
|
||||
|
||||
private fun MutableMap<String, MutableList<IrDeclaration>>.appendMissingMembersToNotExpectClass(
|
||||
klass: IrClass,
|
||||
membersFromSupertype: Map<String, MutableList<IrDeclaration>>,
|
||||
processedMembers: MutableMap<String, MutableList<IrDeclaration>>
|
||||
) {
|
||||
for (memberFromSupertype in membersFromSupertype.flatMap { it.value }) {
|
||||
val newMember = createFakeOverrideMember(listOf(memberFromSupertype), klass)
|
||||
val name = newMember.getFunctionOrPropertyName()
|
||||
if (getMatches(name, newMember, expectActualMap).isEmpty()) {
|
||||
processedMembers.addMember(memberFromSupertype as IrOverridableDeclaration<*>)
|
||||
addMember(newMember)
|
||||
klass.addMember(newMember)
|
||||
} else {
|
||||
val baseMember = processedMembers.getMatches(name, newMember, expectActualMap).single()
|
||||
val errorFactory =
|
||||
if ((baseMember.parent as IrClass).isInterface && (memberFromSupertype.parent as IrClass).isInterface)
|
||||
CommonBackendErrors.MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED
|
||||
else
|
||||
CommonBackendErrors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED
|
||||
diagnosticsReporter.at(klass).report(
|
||||
errorFactory,
|
||||
klass.name.asString(),
|
||||
(memberFromSupertype as IrDeclarationWithName).name.asString()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableMap<String, MutableList<IrDeclaration>>.appendMissingMembersFromActualizedExpectClass(
|
||||
expectClass: IrClass,
|
||||
actualClass: IrClass,
|
||||
) {
|
||||
val actualWithCorrespondingExpectMembers = hashSetOf<IrSymbol>().apply {
|
||||
expectClass.declarations.mapNotNullTo(this) { expectActualMap[(it as? IrOverridableDeclaration<*>)?.symbol] }
|
||||
}
|
||||
|
||||
for (actualMember in actualClass.declarations) {
|
||||
if (actualMember is IrOverridableDeclaration<*> &&
|
||||
(actualMember as? IrDeclarationWithVisibility)?.visibility != DescriptorVisibilities.PRIVATE &&
|
||||
!actualWithCorrespondingExpectMembers.contains(actualMember.symbol)
|
||||
) {
|
||||
addMember(actualMember)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableMap<String, MutableList<IrDeclaration>>.addMember(member: IrOverridableDeclaration<*>) {
|
||||
getOrPut(member.getFunctionOrPropertyName()) { mutableListOf() }.add(member)
|
||||
}
|
||||
|
||||
private fun IrOverridableDeclaration<*>.getFunctionOrPropertyName(): String {
|
||||
return (this as IrDeclarationWithName).name.asString() + (if (this is IrSimpleFunction) "()" else "")
|
||||
}
|
||||
}
|
||||
+19
-20
@@ -11,6 +11,7 @@ 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.isFakeOverride
|
||||
import org.jetbrains.kotlin.ir.util.kotlinFqName
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
@@ -21,12 +22,12 @@ internal class ExpectActualCollector(
|
||||
private val dependentFragments: List<IrModuleFragment>,
|
||||
private val diagnosticsReporter: KtDiagnosticReporterWithImplicitIrBasedContext
|
||||
) {
|
||||
fun collect(): Pair<Map<IrSymbol, IrSymbol>, Map<FqName, FqName>> {
|
||||
fun collect(): MutableMap<IrSymbol, IrSymbol> {
|
||||
val result = mutableMapOf<IrSymbol, IrSymbol>()
|
||||
// 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
|
||||
return result
|
||||
}
|
||||
|
||||
private fun MutableMap<IrSymbol, IrSymbol>.appendExpectActualClassMap(): Pair<List<IrDeclarationBase>, Map<FqName, FqName>> {
|
||||
@@ -157,39 +158,37 @@ private class MemberLinksCollector(
|
||||
if ((declaration.parent as IrClass).isExpect) addLink(declaration)
|
||||
}
|
||||
|
||||
private fun addLink(declaration: IrDeclarationBase) {
|
||||
val actualMemberMatches = actualMembers.getMatches(declaration, expectActualMap, typeAliasMap)
|
||||
private fun addLink(expectDeclaration: IrDeclarationBase) {
|
||||
val actualMemberMatches = actualMembers.getMatches(expectDeclaration, expectActualMap, typeAliasMap)
|
||||
when {
|
||||
actualMemberMatches.size == 1 -> {
|
||||
val actualMember = actualMemberMatches.single()
|
||||
expectActualMap[declaration.symbol] = actualMember.symbol
|
||||
if (declaration is IrProperty) {
|
||||
val actualProperty = actualMember as IrProperty
|
||||
declaration.getter?.let {
|
||||
val getter = actualProperty.getter!!
|
||||
expectActualMap[it.symbol] = getter.symbol
|
||||
expectActualMap.appendTypeParametersMap(it, getter)
|
||||
}
|
||||
declaration.setter?.symbol?.let { expectActualMap[it] = actualProperty.setter!!.symbol }
|
||||
} else if (declaration is IrFunction) {
|
||||
expectActualMap.appendTypeParametersMap(declaration, actualMember as IrFunction)
|
||||
}
|
||||
expectActualMap.addLink(expectDeclaration, actualMemberMatches.single())
|
||||
}
|
||||
actualMemberMatches.size > 1 -> {
|
||||
// TODO: report AMBIGUOUS_ACTUALS here, see KT-57932
|
||||
}
|
||||
!declaration.parent.containsOptionalExpectation() && !(declaration is IrConstructor && declaration.isPrimary) -> {
|
||||
diagnosticsReporter.reportMissingActual(declaration)
|
||||
(expectDeclaration.parent as? IrClass)?.isExpect == false && expectDeclaration.isFakeOverride -> {
|
||||
// Remaining expect fake override members from not expect classes will be actualized in FakeOverridesTransformer
|
||||
// It occurs in a separated step because they require filled expectActualMap for members from expect classes
|
||||
}
|
||||
else -> {
|
||||
if (shouldReportMissingActual(expectDeclaration)) {
|
||||
diagnosticsReporter.reportMissingActual(expectDeclaration)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun shouldReportMissingActual(declaration: IrDeclarationBase): Boolean {
|
||||
return !declaration.parent.containsOptionalExpectation() && !(declaration is IrConstructor && declaration.isPrimary)
|
||||
}
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableMap<IrSymbol, IrSymbol>.appendTypeParametersMap(
|
||||
fun MutableMap<IrSymbol, IrSymbol>.appendTypeParametersMap(
|
||||
expectTypeParametersContainer: IrTypeParametersContainer,
|
||||
actualTypeParametersContainer: IrTypeParametersContainer
|
||||
) {
|
||||
|
||||
+17
-4
@@ -7,7 +7,11 @@ package org.jetbrains.kotlin.backend.common.actualizer
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.util.DeepCopyIrTreeWithSymbols
|
||||
import org.jetbrains.kotlin.ir.util.SymbolRemapper
|
||||
import org.jetbrains.kotlin.ir.util.SymbolRenamer
|
||||
import org.jetbrains.kotlin.ir.util.TypeRemapper
|
||||
import org.jetbrains.kotlin.utils.memoryOptimizedMap
|
||||
|
||||
internal class ActualizerSymbolRemapper(private val expectActualMap: Map<IrSymbol, IrSymbol>) : SymbolRemapper {
|
||||
override fun getDeclaredClass(symbol: IrClassSymbol) = symbol
|
||||
@@ -71,7 +75,7 @@ internal class ActualizerSymbolRemapper(private val expectActualMap: Map<IrSymbo
|
||||
private inline fun <reified S : IrSymbol> S.actualizeSymbol(): S = (expectActualMap[this] as? S) ?: this
|
||||
}
|
||||
|
||||
internal open class ActualizerVisitor(symbolRemapper: SymbolRemapper, typeRemapper: TypeRemapper) :
|
||||
internal open class ActualizerVisitor(private val symbolRemapper: SymbolRemapper, typeRemapper: TypeRemapper) :
|
||||
DeepCopyIrTreeWithSymbols(symbolRemapper, typeRemapper, SymbolRenamer.DEFAULT) {
|
||||
override fun visitModuleFragment(declaration: IrModuleFragment) =
|
||||
declaration.also { it.transformChildren(this, null) }
|
||||
@@ -94,7 +98,11 @@ internal open class ActualizerVisitor(symbolRemapper: SymbolRemapper, typeRemapp
|
||||
it.transformChildren(this, null)
|
||||
}
|
||||
|
||||
override fun visitSimpleFunction(declaration: IrSimpleFunction) = visitFunction(declaration) as IrSimpleFunction
|
||||
override fun visitSimpleFunction(declaration: IrSimpleFunction) = (visitFunction(declaration) as IrSimpleFunction).also {
|
||||
it.overriddenSymbols = it.overriddenSymbols.memoryOptimizedMap { symbol ->
|
||||
symbolRemapper.getReferencedFunction(symbol) as IrSimpleFunctionSymbol
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitConstructor(declaration: IrConstructor) = visitFunction(declaration) as IrConstructor
|
||||
|
||||
@@ -105,7 +113,12 @@ internal open class ActualizerVisitor(symbolRemapper: SymbolRemapper, typeRemapp
|
||||
}
|
||||
|
||||
override fun visitProperty(declaration: IrProperty) =
|
||||
declaration.also { it.transformChildren(this, null) }
|
||||
declaration.also {
|
||||
it.transformChildren(this, null)
|
||||
it.overriddenSymbols = it.overriddenSymbols.memoryOptimizedMap { symbol ->
|
||||
symbolRemapper.getReferencedProperty(symbol)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitField(declaration: IrField) =
|
||||
declaration.also {
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.backend.common.actualizer
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ir.isExpect
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationBase
|
||||
import org.jetbrains.kotlin.ir.declarations.IrOverridableDeclaration
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.util.isFakeOverride
|
||||
import org.jetbrains.kotlin.ir.util.transformInPlace
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
|
||||
/**
|
||||
* It actualizes expect fake overrides in non-expect classes inside common or multi-platform module.
|
||||
*
|
||||
* When some non-expect class inside a common or multi-platform module has an expect base class,
|
||||
* FIR2IR generates expect fake overrides overriding the expect base class members for this non-expect class which is not correct for the backend.
|
||||
* This Actualizer processes expect overridable declarations in non-expect classes and replaces them with the associated actual overridable
|
||||
* declarations overriding the actual base class members.The newly created actual fake overrides are stored in expectActualMap.
|
||||
*/
|
||||
internal class FakeOverridesActualizer(private val expectActualMap: MutableMap<IrSymbol, IrSymbol>) : IrElementVisitorVoid {
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
if (!declaration.isExpect) {
|
||||
actualizeFakeOverrides(declaration)
|
||||
}
|
||||
visitElement(declaration)
|
||||
}
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
private fun actualizeFakeOverrides(klass: IrClass) {
|
||||
fun IrDeclaration.actualize(): IrDeclaration {
|
||||
if (!isExpect) return this
|
||||
|
||||
(expectActualMap[symbol]?.owner as? IrDeclaration)?.let { return it }
|
||||
|
||||
require(this is IrOverridableDeclaration<*>)
|
||||
val actualizedOverrides = overriddenSymbols.map { (it.owner as IrDeclaration).actualize() }
|
||||
val actualFakeOverride = createFakeOverrideMember(actualizedOverrides, parent as IrClass)
|
||||
|
||||
expectActualMap.addLink(this as IrDeclarationBase, actualFakeOverride)
|
||||
|
||||
return actualFakeOverride
|
||||
}
|
||||
|
||||
klass.declarations.transformInPlace { if (it.isExpect && it.isFakeOverride) it.actualize() else it }
|
||||
}
|
||||
}
|
||||
+20
-7
@@ -23,27 +23,40 @@ object IrActualizer {
|
||||
): IrActualizedResult {
|
||||
val ktDiagnosticReporter = KtDiagnosticReporterWithImplicitIrBasedContext(diagnosticReporter, languageVersionSettings)
|
||||
|
||||
val (expectActualMap, expectActualTypeAliasMap) = ExpectActualCollector(
|
||||
// The ir modules processing is performed phase-to-phase:
|
||||
// 1. Collect expect-actual links for classes and their members from dependent fragments
|
||||
val expectActualMap = ExpectActualCollector(
|
||||
mainFragment,
|
||||
dependentFragments,
|
||||
ktDiagnosticReporter
|
||||
).collect()
|
||||
|
||||
// 2. Remove top-only expect declarations since they are not needed anymore and should not be presented in the final IrFragment
|
||||
// Expect fake-overrides from non-expect classes remain untouched since they will be actualized in the next phase.
|
||||
// Also, it doesn't remove unactualized expect declarations marked with @OptionalExpectation
|
||||
val removedExpectDeclarations = removeExpectDeclarations(dependentFragments, expectActualMap)
|
||||
|
||||
// 3. Actualize expect fake overrides in non-expect classes inside common or multi-platform module.
|
||||
// It's probably important to run FakeOverridesActualizer before ActualFakeOverridesAdder
|
||||
FakeOverridesActualizer(expectActualMap).apply { dependentFragments.forEach { visitModuleFragment(it) } }
|
||||
|
||||
// 4. Add fake overrides to non-expect classes inside common or multi-platform module,
|
||||
// taken from these non-expect classes actualized super classes.
|
||||
ActualFakeOverridesAdder(
|
||||
expectActualMap,
|
||||
ktDiagnosticReporter
|
||||
).apply { dependentFragments.forEach { visitModuleFragment(it) } }
|
||||
|
||||
// 5. Copy and actualize function parameter default values from expect functions
|
||||
val symbolRemapper = ActualizerSymbolRemapper(expectActualMap)
|
||||
val typeRemapper = DeepCopyTypeRemapper(symbolRemapper)
|
||||
FunctionDefaultParametersActualizer(symbolRemapper, typeRemapper, expectActualMap).actualize()
|
||||
|
||||
MissingFakeOverridesAdder(
|
||||
expectActualMap,
|
||||
expectActualTypeAliasMap,
|
||||
ktDiagnosticReporter
|
||||
).apply { dependentFragments.forEach { visitModuleFragment(it) } }
|
||||
|
||||
// 6. Actualize expect calls in dependent fragments using info obtained in the previous steps
|
||||
val actualizerVisitor = ActualizerVisitor(symbolRemapper, typeRemapper)
|
||||
dependentFragments.forEach { it.transform(actualizerVisitor, null) }
|
||||
|
||||
// 7. Merge dependent fragments into the main one
|
||||
mergeIrFragments(mainFragment, dependentFragments)
|
||||
|
||||
return IrActualizedResult(removedExpectDeclarations)
|
||||
|
||||
+92
-4
@@ -10,18 +10,20 @@ import org.jetbrains.kotlin.backend.common.CommonBackendErrors
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildProperty
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrDynamicType
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
import org.jetbrains.kotlin.ir.types.isNullable
|
||||
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.ir.util.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.OptionalAnnotationUtil
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
|
||||
private val FLEXIBLE_NULLABILITY_ANNOTATION_FQ_NAME = StandardClassIds.Annotations.FlexibleNullability.asSingleFqName()
|
||||
|
||||
@@ -29,8 +31,15 @@ internal fun Map<String, List<IrDeclaration>>.getMatches(
|
||||
expectDeclaration: IrDeclaration,
|
||||
expectActualTypesMap: Map<IrSymbol, IrSymbol>,
|
||||
expectActualTypeAliasMap: Map<FqName, FqName>
|
||||
): List<IrDeclaration> =
|
||||
getMatches(generateIrElementFullNameFromExpect(expectDeclaration, expectActualTypeAliasMap), expectDeclaration, expectActualTypesMap)
|
||||
|
||||
internal fun Map<String, List<IrDeclaration>>.getMatches(
|
||||
mainSignature: String,
|
||||
expectDeclaration: IrDeclaration,
|
||||
expectActualTypesMap: Map<IrSymbol, IrSymbol>
|
||||
): List<IrDeclaration> {
|
||||
val members = this[generateIrElementFullNameFromExpect(expectDeclaration, expectActualTypeAliasMap)] ?: return emptyList()
|
||||
val members = this[mainSignature] ?: return emptyList()
|
||||
return when (expectDeclaration) {
|
||||
is IrFunction -> members.getMatches(expectDeclaration, expectActualTypesMap) { it as IrFunction }
|
||||
is IrProperty -> members.getMatches(expectDeclaration, expectActualTypesMap) { (it as IrProperty).getter!! }
|
||||
@@ -167,6 +176,21 @@ private fun appendElementFullName(
|
||||
}
|
||||
}
|
||||
|
||||
internal fun MutableMap<IrSymbol, IrSymbol>.addLink(expectMember: IrDeclarationBase, actualMember: IrDeclaration) {
|
||||
this[expectMember.symbol] = actualMember.symbol
|
||||
if (expectMember is IrProperty) {
|
||||
val actualProperty = actualMember as IrProperty
|
||||
expectMember.getter!!.let {
|
||||
val getter = actualProperty.getter!!
|
||||
this[it.symbol] = getter.symbol
|
||||
this.appendTypeParametersMap(it, getter)
|
||||
}
|
||||
expectMember.setter?.symbol?.let { this[it] = actualProperty.setter!!.symbol }
|
||||
} else if (expectMember is IrFunction) {
|
||||
this.appendTypeParametersMap(expectMember, actualMember as IrFunction)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
internal fun KtDiagnosticReporterWithImplicitIrBasedContext.reportMissingActual(irDeclaration: IrDeclaration) {
|
||||
at(irDeclaration).report(
|
||||
@@ -181,3 +205,67 @@ internal fun IrElement.containsOptionalExpectation(): Boolean {
|
||||
this.kind == ClassKind.ANNOTATION_CLASS &&
|
||||
this.hasAnnotation(OptionalAnnotationUtil.OPTIONAL_EXPECTATION_FQ_NAME)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
internal fun createFakeOverrideMember(actualMembers: List<IrDeclaration>, declaration: IrClass): IrOverridableDeclaration<*> {
|
||||
return when (actualMembers.first()) {
|
||||
is IrSimpleFunction -> createFakeOverrideFunction(actualMembers as List<IrSimpleFunction>, declaration)
|
||||
is IrProperty -> createFakeOverrideProperty(actualMembers as List<IrProperty>, declaration)
|
||||
else -> error("Only function or property can be overridden")
|
||||
}
|
||||
}
|
||||
|
||||
private fun createFakeOverrideProperty(actualProperties: List<IrProperty>, parent: IrClass): IrProperty {
|
||||
val actualProperty = actualProperties.first() // TODO: Currently FIR2IR works in the similar way but it looks incorrect
|
||||
return parent.factory.buildProperty {
|
||||
updateFrom(actualProperty)
|
||||
name = actualProperty.name
|
||||
origin = IrDeclarationOrigin.FAKE_OVERRIDE
|
||||
isFakeOverride = true
|
||||
isExpect = false
|
||||
}.apply {
|
||||
this.parent = parent
|
||||
annotations = actualProperty.annotations
|
||||
backingField = null
|
||||
getter = createFakeOverrideFunction(actualProperties.map { it.getter as IrSimpleFunction }, parent, symbol)
|
||||
setter = runIf(actualProperty.setter != null) {
|
||||
createFakeOverrideFunction(actualProperties.map { it.setter as IrSimpleFunction }, parent, symbol)
|
||||
}
|
||||
overriddenSymbols = actualProperties.map { it.symbol }
|
||||
}
|
||||
}
|
||||
|
||||
private fun createFakeOverrideFunction(
|
||||
actualFunctions: List<IrSimpleFunction>,
|
||||
parent: IrDeclarationParent,
|
||||
correspondingPropertySymbol: IrPropertySymbol? = null
|
||||
): IrSimpleFunction {
|
||||
val actualFunction = actualFunctions.first() // TODO: Currently FIR2IR works in the similar way but it looks incorrect
|
||||
|
||||
return actualFunction.factory.buildFun {
|
||||
updateFrom(actualFunction)
|
||||
name = actualFunction.name
|
||||
returnType = actualFunction.returnType
|
||||
origin = IrDeclarationOrigin.FAKE_OVERRIDE
|
||||
isFakeOverride = true
|
||||
isExpect = false
|
||||
}.also {
|
||||
it.parent = parent
|
||||
it.annotations = actualFunction.annotations.map { p -> p.deepCopyWithSymbols(it) }
|
||||
it.typeParameters = actualFunction.typeParameters.map { p -> p.deepCopyWithSymbols(it) }
|
||||
|
||||
val typeRemapper = IrTypeParameterRemapper(actualFunction.typeParameters.zip(it.typeParameters).toMap())
|
||||
fun IrValueParameter.deepCopyWithTypeParameters(): IrValueParameter = deepCopyWithSymbols(it) { symbolRemapper, _ ->
|
||||
DeepCopyIrTreeWithSymbols(symbolRemapper, typeRemapper)
|
||||
}
|
||||
|
||||
it.dispatchReceiverParameter = actualFunction.dispatchReceiverParameter?.deepCopyWithTypeParameters()
|
||||
it.extensionReceiverParameter = actualFunction.extensionReceiverParameter?.deepCopyWithTypeParameters()
|
||||
it.valueParameters = actualFunction.valueParameters.map { p -> p.deepCopyWithTypeParameters() }
|
||||
it.contextReceiverParametersCount = actualFunction.contextReceiverParametersCount
|
||||
it.metadata = actualFunction.metadata
|
||||
it.overriddenSymbols = actualFunctions.map { f -> f.symbol }
|
||||
it.attributeOwnerId = it
|
||||
it.correspondingPropertySymbol = correspondingPropertySymbol
|
||||
}
|
||||
}
|
||||
-147
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.backend.common.actualizer
|
||||
|
||||
import org.jetbrains.kotlin.KtDiagnosticReporterWithImplicitIrBasedContext
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendErrors
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildProperty
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrPropertyImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
import org.jetbrains.kotlin.ir.types.isAny
|
||||
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
internal class MissingFakeOverridesAdder(
|
||||
private val expectActualMap: Map<IrSymbol, IrSymbol>,
|
||||
private val typeAliasMap: Map<FqName, FqName>,
|
||||
private val diagnosticsReporter: KtDiagnosticReporterWithImplicitIrBasedContext
|
||||
) : IrElementVisitorVoid {
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
if (!declaration.isExpect) {
|
||||
processSupertypes(declaration)
|
||||
}
|
||||
visitElement(declaration)
|
||||
}
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
private fun processSupertypes(declaration: IrClass) {
|
||||
val members by lazy(LazyThreadSafetyMode.NONE) {
|
||||
val notBuiltinMembers = declaration.declarations.filterNot { 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) {
|
||||
val expectClass = superType.classifierOrFail.owner as? IrClass ?: continue
|
||||
val added = mutableSetOf<IrDeclaration>()
|
||||
for (expectMember in expectClass.declarations) {
|
||||
if (expectMember.isBuiltinMember()) continue
|
||||
val actualMember = expectActualMap[expectMember.symbol]?.owner as? IrDeclaration ?: continue
|
||||
added += actualMember
|
||||
|
||||
// Do not add FAKE_OVERRIDE if the subclass already has overridden member
|
||||
if (declaration.declarations.filterIsInstance<IrOverridableDeclaration<*>>()
|
||||
.any { expectMember.symbol in it.overriddenSymbols }
|
||||
) {
|
||||
continue
|
||||
}
|
||||
addFakeOverride(actualMember, members, declaration)
|
||||
}
|
||||
val actualClass = expectActualMap[expectClass.symbol]?.owner as? IrClass ?: continue
|
||||
for (actualMember in actualClass.declarations) {
|
||||
if (actualMember.isBuiltinMember() || actualMember in added) continue
|
||||
if ((actualMember as? IrDeclarationWithVisibility)?.visibility == DescriptorVisibilities.PRIVATE) continue
|
||||
addFakeOverride(actualMember, members, declaration)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun addFakeOverride(
|
||||
actualMember: IrDeclaration,
|
||||
members: MutableMap<String, MutableList<IrDeclaration>>,
|
||||
declaration: IrClass
|
||||
) {
|
||||
val newMember = when (actualMember) {
|
||||
is IrFunctionImpl -> createFakeOverrideFunction(actualMember, declaration)
|
||||
is IrPropertyImpl -> createFakeOverrideProperty(actualMember, declaration)
|
||||
else -> return
|
||||
}
|
||||
|
||||
if (members.getMatches(newMember, expectActualMap, typeAliasMap).isEmpty()) {
|
||||
declaration.declarations.add(newMember)
|
||||
members.getOrPut(generateIrElementFullNameFromExpect(newMember, typeAliasMap)) { mutableListOf() }.add(newMember)
|
||||
} else {
|
||||
diagnosticsReporter.at(declaration).report(
|
||||
CommonBackendErrors.MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED,
|
||||
declaration.name.asString(),
|
||||
(actualMember as IrDeclarationWithName).name.asString()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrDeclaration.isBuiltinMember(): Boolean {
|
||||
if (this !is IrFunction) return false
|
||||
return this is IrConstructor || dispatchReceiverParameter?.type?.isAny() == true
|
||||
}
|
||||
|
||||
private fun createFakeOverrideProperty(actualMember: IrPropertyImpl, declaration: IrClass) =
|
||||
declaration.factory.buildProperty {
|
||||
updateFrom(actualMember)
|
||||
name = actualMember.name
|
||||
origin = IrDeclarationOrigin.FAKE_OVERRIDE
|
||||
}.apply {
|
||||
parent = declaration
|
||||
annotations = actualMember.annotations
|
||||
backingField = actualMember.backingField
|
||||
getter = (actualMember.getter as? IrFunctionImpl)?.let { getter ->
|
||||
createFakeOverrideFunction(getter, declaration, symbol)
|
||||
}
|
||||
setter = (actualMember.setter as? IrFunctionImpl)?.let { setter ->
|
||||
createFakeOverrideFunction(setter, declaration, symbol)
|
||||
}
|
||||
overriddenSymbols = listOf(actualMember.symbol)
|
||||
}
|
||||
|
||||
private fun createFakeOverrideFunction(
|
||||
actualFunction: IrFunctionImpl,
|
||||
parent: IrDeclarationParent,
|
||||
correspondingPropertySymbol: IrPropertySymbol? = null
|
||||
) = actualFunction.factory.buildFun {
|
||||
updateFrom(actualFunction)
|
||||
name = actualFunction.name
|
||||
returnType = actualFunction.returnType
|
||||
origin = IrDeclarationOrigin.FAKE_OVERRIDE
|
||||
isFakeOverride = true
|
||||
isExpect = false
|
||||
}.also {
|
||||
it.parent = parent
|
||||
it.annotations = actualFunction.annotations.map { p -> p.deepCopyWithSymbols(it) }
|
||||
it.typeParameters = actualFunction.typeParameters.map { p -> p.deepCopyWithSymbols(it) }
|
||||
it.dispatchReceiverParameter = actualFunction.dispatchReceiverParameter?.deepCopyWithSymbols(it)
|
||||
it.extensionReceiverParameter = actualFunction.extensionReceiverParameter?.deepCopyWithSymbols(it)
|
||||
it.valueParameters = actualFunction.valueParameters.map { p -> p.deepCopyWithSymbols(it) }
|
||||
it.contextReceiverParametersCount = actualFunction.contextReceiverParametersCount
|
||||
it.metadata = actualFunction.metadata
|
||||
it.overriddenSymbols = listOf(actualFunction.symbol)
|
||||
it.attributeOwnerId = it
|
||||
it.correspondingPropertySymbol = correspondingPropertySymbol
|
||||
}
|
||||
Reference in New Issue
Block a user