diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrFakeOverrideUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrFakeOverrideUtils.kt new file mode 100644 index 00000000000..6b33a4b6882 --- /dev/null +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrFakeOverrideUtils.kt @@ -0,0 +1,92 @@ +/* + * Copyright 2010-2019 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.ir.util + +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.utils.addToStdlib.safeAs + +val IrDeclaration.isReal: Boolean get() = !isFakeOverride + +val IrDeclaration.isFakeOverride: Boolean + get() = when (this) { + is IrSimpleFunction -> isFakeOverride + is IrProperty -> isFakeOverride + is IrField -> isFakeOverride + else -> false + } + +val IrSimpleFunction.target: IrSimpleFunction + get() = if (modality == Modality.ABSTRACT) + this + else + resolveFakeOverride() ?: error("Could not resolveFakeOverride() for ${this.render()}") + +val IrFunction.target: IrFunction get() = when (this) { + is IrSimpleFunction -> this.target + is IrConstructor -> this + else -> error(this) +} + +fun IrField.resolveFakeOverride(): IrField? { + var toVisit = setOf(this) + val nonOverridden = mutableSetOf() + while (toVisit.isNotEmpty()) { + nonOverridden += toVisit.filter { it.overriddenSymbols.isEmpty() } + toVisit = toVisit.flatMap { it.overriddenSymbols }.map { it.owner }.toSet() + } + return nonOverridden.singleOrNull() +} +fun IrSimpleFunction.collectRealOverrides(toSkip: (IrSimpleFunction) -> Boolean = { false }): Set { + if (isReal && !toSkip(this)) return setOf(this) + + val visited = mutableSetOf() + val realOverrides = mutableSetOf() + + fun collectRealOverrides(func: IrSimpleFunction) { + if (!visited.add(func)) return + + if (func.isReal && !toSkip(func)) { + realOverrides += func + } else { + func.overriddenSymbols.forEach { collectRealOverrides(it.owner) } + } + } + + overriddenSymbols.forEach { collectRealOverrides(it.owner) } + + fun excludeRepeated(func: IrSimpleFunction) { + if (!visited.add(func)) return + + func.overriddenSymbols.forEach { + realOverrides.remove(it.owner) + excludeRepeated(it.owner) + } + } + + visited.clear() + realOverrides.toList().forEach { excludeRepeated(it) } + + return realOverrides +} + +// TODO: use this implementation instead of any other +fun IrSimpleFunction.resolveFakeOverride(allowAbstract: Boolean = false, toSkip: (IrSimpleFunction) -> Boolean = { false }): IrSimpleFunction? { + val reals = collectRealOverrides(toSkip) + return if (allowAbstract) { + if (reals.isEmpty()) error("No real overrides for ${this.render()}") + reals.first() + } else { + reals + .filter { it.modality != Modality.ABSTRACT } + .let { realOverrides -> + // Kotlin forbids conflicts between overrides, but they may trickle down from Java. + realOverrides.singleOrNull { it.parent.safeAs()?.isInterface != true } + // TODO: We take firstOrNull instead of singleOrNull here because of KT-36188. + ?: realOverrides.firstOrNull() + } + } +} 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 353d4e15b71..368f842b1ba 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 @@ -236,16 +236,6 @@ val IrClass.defaultType: IrSimpleType val IrSimpleFunction.isSynthesized: Boolean get() = descriptor.kind == CallableMemberDescriptor.Kind.SYNTHESIZED -val IrDeclaration.isReal: Boolean get() = !isFakeOverride - -val IrDeclaration.isFakeOverride: Boolean - get() = when (this) { - is IrSimpleFunction -> isFakeOverride - is IrProperty -> isFakeOverride - is IrField -> isFakeOverride - else -> false - } - fun IrClass.isSubclassOf(ancestor: IrClass): Boolean { val alreadyVisited = mutableSetOf() @@ -262,50 +252,6 @@ fun IrClass.isSubclassOf(ancestor: IrClass): Boolean { return this.hasAncestorInSuperTypes() } -fun IrSimpleFunction.collectRealOverrides(toSkip: (IrSimpleFunction) -> Boolean = { false }): Set { - if (isReal && !toSkip(this)) return setOf(this) - - val visited = mutableSetOf() - val realOverrides = mutableSetOf() - - fun collectRealOverrides(func: IrSimpleFunction) { - if (!visited.add(func)) return - - if (func.isReal && !toSkip(func)) { - realOverrides += func - } else { - func.overriddenSymbols.forEach { collectRealOverrides(it.owner) } - } - } - - overriddenSymbols.forEach { collectRealOverrides(it.owner) } - - fun excludeRepeated(func: IrSimpleFunction) { - if (!visited.add(func)) return - - func.overriddenSymbols.forEach { - realOverrides.remove(it.owner) - excludeRepeated(it.owner) - } - } - - visited.clear() - realOverrides.toList().forEach { excludeRepeated(it) } - - return realOverrides -} - -// This implementation is from kotlin-native -// TODO: use this implementation instead of any other -fun IrSimpleFunction.resolveFakeOverride(toSkip: (IrSimpleFunction) -> Boolean = { false }): IrSimpleFunction? { - return collectRealOverrides(toSkip) - .filter { it.modality != Modality.ABSTRACT } - .let { realOverrides -> - // Kotlin forbids conflicts between overrides, but they may trickle down from Java. - realOverrides.singleOrNull { it.parent.safeAs()?.isInterface != true } ?: realOverrides.singleOrNull() - } -} - fun IrSimpleFunction.isOrOverridesSynthesized(): Boolean { if (isSynthesized) return true @@ -322,16 +268,6 @@ fun IrSimpleFunction.findInterfaceImplementation(): IrSimpleFunction? { return resolveFakeOverride()?.run { if (parentAsClass.isInterface) this else null } } -fun IrField.resolveFakeOverride(): IrField? { - var toVisit = setOf(this) - val nonOverridden = mutableSetOf() - while (toVisit.isNotEmpty()) { - nonOverridden += toVisit.filter { it.overriddenSymbols.isEmpty() } - toVisit = toVisit.flatMap { it.overriddenSymbols }.map { it.owner }.toSet() - } - return nonOverridden.singleOrNull() -} - val IrClass.isAnnotationClass get() = kind == ClassKind.ANNOTATION_CLASS val IrClass.isEnumClass get() = kind == ClassKind.ENUM_CLASS val IrClass.isEnumEntry get() = kind == ClassKind.ENUM_ENTRY