From cafe2cdb12f49dd8f855ff86b1a0fe37c6476610 Mon Sep 17 00:00:00 2001 From: Ilya Matveev Date: Tue, 30 Jul 2019 17:59:29 +0700 Subject: [PATCH] IR: Fix fake-override resolution for fields Earlier we used a result of a corresponding getter resolution to obtain a fake overridden field. This approach is incorrect because the getter resolved may not contain a backing field. This patch fixes the issue by using the overriddenSymbols property of an IrField directly. Issue #KT-33034 fixed --- .../org/jetbrains/kotlin/ir/util/IrUtils.kt | 6 +- .../serialization/IrFakeOverrideUtils.kt | 66 ++++++++++++------- .../SerializeDescriptorReference.kt | 2 +- 3 files changed, 47 insertions(+), 27 deletions(-) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt index 2f235c7e575..ae1f6ddb9a2 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt @@ -210,11 +210,11 @@ val IrBody.statements: List val IrClass.defaultType: IrSimpleType get() = this.thisReceiver!!.type as IrSimpleType -val IrSimpleFunction.isReal: Boolean get() = descriptor.kind.isReal - val IrSimpleFunction.isSynthesized: Boolean get() = descriptor.kind == CallableMemberDescriptor.Kind.SYNTHESIZED -val IrSimpleFunction.isFakeOverride: Boolean get() = origin == IrDeclarationOrigin.FAKE_OVERRIDE +val IrDeclaration.isReal: Boolean get() = !isFakeOverride + +val IrDeclaration.isFakeOverride: Boolean get() = origin == IrDeclarationOrigin.FAKE_OVERRIDE fun IrClass.isSubclassOf(ancestor: IrClass): Boolean { diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFakeOverrideUtils.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFakeOverrideUtils.kt index 1b9817c4b82..407ba2a48b2 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFakeOverrideUtils.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFakeOverrideUtils.kt @@ -7,30 +7,27 @@ package org.jetbrains.kotlin.backend.common.serialization import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.symbols.IrBindableSymbol import org.jetbrains.kotlin.ir.util.isReal import org.jetbrains.kotlin.ir.util.original - -/** - * Implementation of given method. - * - * TODO: this method is actually a part of resolve and probably duplicates another one - */ -fun IrSimpleFunction.resolveFakeOverride(allowAbstract: Boolean = false): IrSimpleFunction { +// We may get several real supers here (e.g. see the code snippet from KT-33034). +// TODO: Consider reworking the resolution algorithm to get a determined super declaration. +private fun , D: IrOverridableDeclaration> D.getRealSupers(): Set { if (this.isReal) { - return this + return setOf(this) } - val visited = mutableSetOf() - val realSupers = mutableSetOf() + val visited = mutableSetOf() + val realSupers = mutableSetOf() - fun findRealSupers(function: IrSimpleFunction) { - if (function in visited) return - visited += function - if (function.isReal) { - realSupers += function + fun findRealSupers(declaration: D) { + if (declaration in visited) return + visited += declaration + if (declaration.isReal) { + realSupers += declaration } else { - function.overriddenSymbols.forEach { findRealSupers(it.owner) } + declaration.overriddenSymbols.forEach { findRealSupers(it.owner) } } } @@ -39,10 +36,10 @@ fun IrSimpleFunction.resolveFakeOverride(allowAbstract: Boolean = false): IrSimp if (realSupers.size > 1) { visited.clear() - fun excludeOverridden(function: IrSimpleFunction) { - if (function in visited) return - visited += function - function.overriddenSymbols.forEach { + fun excludeOverridden(declaration: D) { + if (declaration in visited) return + visited += declaration + declaration.overriddenSymbols.forEach { realSupers.remove(it.owner) excludeOverridden(it.owner) } @@ -51,7 +48,22 @@ fun IrSimpleFunction.resolveFakeOverride(allowAbstract: Boolean = false): IrSimp realSupers.toList().forEach { excludeOverridden(it) } } - return realSupers.first { allowAbstract || it.modality != Modality.ABSTRACT } + return realSupers +} + +/** + * Implementation of given method. + * + * TODO: this method is actually a part of resolve and probably duplicates another one + */ +fun IrSimpleFunction.resolveFakeOverride(allowAbstract: Boolean = false): IrSimpleFunction { + val realSupers = getRealSupers() + + return if (allowAbstract) { + realSupers.first() + } else { + realSupers.single { it.modality != Modality.ABSTRACT } + } } /** @@ -61,9 +73,17 @@ fun IrSimpleFunction.resolveFakeOverride(allowAbstract: Boolean = false): IrSimp */ internal fun IrSimpleFunction.resolveFakeOverrideMaybeAbstract() = this.resolveFakeOverride(allowAbstract = true) -internal fun IrProperty.resolveFakeOverrideMaybeAbstract() = this.getter!!.resolveFakeOverrideMaybeAbstract().correspondingProperty!! +internal fun IrProperty.resolveFakeOverrideMaybeAbstract(): IrProperty = + this.getter!!.resolveFakeOverrideMaybeAbstract().correspondingPropertySymbol!!.owner -internal fun IrField.resolveFakeOverrideMaybeAbstract() = this.correspondingProperty!!.getter!!.resolveFakeOverrideMaybeAbstract().correspondingProperty!!.backingField +/** + * TODO: This method can be simplified if the "overriddenSymbols" list of an IrField always includes only one element. + * Currently it's not the case for some cinterop libraries (e.g. Foundation). In these libraries interfaces containing + * final properties with external getters are created (corresponding compiler error is suppressed). Due to KT-33081 + * such a property gets a backing field and a field of a class implementing such interfaces can have several elements + * in the overriddenSymbols list. + */ +internal fun IrField.resolveFakeOverride(): IrField = getRealSupers().first() val IrSimpleFunction.target: IrSimpleFunction get() = (if (modality == Modality.ABSTRACT) this else resolveFakeOverride()).original diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/SerializeDescriptorReference.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/SerializeDescriptorReference.kt index ea21fe61d8f..1d77155d605 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/SerializeDescriptorReference.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/SerializeDescriptorReference.kt @@ -78,7 +78,7 @@ open class DescriptorReferenceSerializer( val realDeclaration = if (isFakeOverride) { when (declaration) { is IrSimpleFunction -> declaration.resolveFakeOverrideMaybeAbstract() - is IrField -> declaration.resolveFakeOverrideMaybeAbstract() + is IrField -> declaration.resolveFakeOverride() is IrProperty -> declaration.resolveFakeOverrideMaybeAbstract() else -> error("Unexpected fake override declaration") }