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
This commit is contained in:
Ilya Matveev
2019-07-30 17:59:29 +07:00
parent ac667403ef
commit cafe2cdb12
3 changed files with 47 additions and 27 deletions
@@ -210,11 +210,11 @@ val IrBody.statements: List<IrStatement>
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 {
@@ -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 <S: IrBindableSymbol<*, D>, D: IrOverridableDeclaration<S>> D.getRealSupers(): Set<D> {
if (this.isReal) {
return this
return setOf(this)
}
val visited = mutableSetOf<IrSimpleFunction>()
val realSupers = mutableSetOf<IrSimpleFunction>()
val visited = mutableSetOf<D>()
val realSupers = mutableSetOf<D>()
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
@@ -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")
}