IR: refactor resolveFakeOverride call sites

Split it to 4 functions for clarity: resolveFakeOverride,
resolveFakeOverrideOrFail, resolveFakeOverrideMaybeAbstract,
resolveFakeOverrideMaybeAbstractOrFail. Remove/inline duplicated
utilities and remove unused parameters.
This commit is contained in:
Alexander Udalov
2023-08-23 15:37:01 +02:00
committed by Space Team
parent e52529a1d1
commit b5ba9ee671
19 changed files with 72 additions and 80 deletions
@@ -469,7 +469,7 @@ internal abstract class IrExpectActualMatchingContext(
var ir = asIr()
if (ir.isFakeOverride && ir is IrOverridableDeclaration<*>) {
ir.resolveFakeOverrideOrNull()?.let { ir = it }
ir.resolveFakeOverride()?.let { ir = it }
}
return when (ir.origin) {
@@ -778,7 +778,7 @@ private fun shouldDeclarationBeExported(declaration: IrDeclarationWithName, cont
fun IrOverridableDeclaration<*>.isAllowedFakeOverriddenDeclaration(context: JsIrBackendContext): Boolean {
val firstExportedRealOverride = runIf(isFakeOverride) {
resolveFakeOverrideOrNull(allowAbstract = true) { it === this || it.parentClassOrNull?.isExported(context) != true }
resolveFakeOverrideMaybeAbstract { it === this || it.parentClassOrNull?.isExported(context) != true }
}
if (firstExportedRealOverride?.parentClassOrNull.isExportedInterface(context)) {
@@ -6,14 +6,16 @@
package org.jetbrains.kotlin.ir.backend.js.ic
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.util.IdSignature
import org.jetbrains.kotlin.ir.util.isFakeOverride
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.ir.util.resolveFakeOverride
import org.jetbrains.kotlin.ir.util.resolveFakeOverrideOrFail
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
@@ -35,12 +37,8 @@ internal class IdSignatureHashCalculator(private val icHasher: ICHasher) {
private val IrFunction.inlineFunctionFlatHash: ICHash
get() = inlineFunctionFlatHashes.getOrPut(this) {
val flatHash = if (isFakeOverride && this is IrSimpleFunction) {
resolveFakeOverride()?.let { icHasher.calculateIrFunctionHash(it) }
?: icError("can not resolve fake override for ${render()}")
} else {
icHasher.calculateIrFunctionHash(this)
}
val function = if (isFakeOverride && this is IrSimpleFunction) resolveFakeOverrideOrFail() else this
val flatHash = icHasher.calculateIrFunctionHash(function)
ICHash(symbol.calculateSymbolHash().hash.combineWith(flatHash.hash))
}
@@ -248,3 +248,9 @@ data class IrBasedFunctionHandle(val function: IrSimpleFunction) : FunctionHandl
override fun getOverridden() =
function.overriddenSymbols.map { IrBasedFunctionHandle(it.owner) }
}
private fun IrSimpleFunction.findInterfaceImplementation(): IrSimpleFunction? {
if (isReal) return null
return resolveFakeOverride()?.run { if (parentAsClass.isInterface) this else null }
}
@@ -195,7 +195,7 @@ fun translateCall(
expression.superQualifierSymbol?.let { superQualifier ->
val (target: IrSimpleFunction, klass: IrClass) = if (superQualifier.owner.isInterface) {
val impl = function.resolveFakeOverride()!!
val impl = function.resolveFakeOverrideOrFail()
Pair(impl, impl.parentAsClass)
} else {
Pair(function, superQualifier.owner)
@@ -165,7 +165,8 @@ private class InterfaceSuperCallsLowering(val context: JvmBackendContext) : IrEl
}
val superCallee = expression.symbol.owner
if (superCallee.isDefinitelyNotDefaultImplsMethod(context.config.jvmDefaultMode)) return super.visitCall(expression)
if (superCallee.isDefinitelyNotDefaultImplsMethod(context.config.jvmDefaultMode, superCallee.resolveFakeOverride()))
return super.visitCall(expression)
val redirectTarget = context.cachedDeclarations.getDefaultImplsFunction(superCallee)
val newCall = createDelegatingCallWithPlaceholderTypeArguments(expression, redirectTarget, context.irBuiltIns)
@@ -235,7 +236,7 @@ private class InterfaceDefaultCallsLowering(val context: JvmBackendContext) : Ir
internal fun IrSimpleFunction.isDefinitelyNotDefaultImplsMethod(
jvmDefaultMode: JvmDefaultMode,
implementation: IrSimpleFunction? = resolveFakeOverride()
implementation: IrSimpleFunction?,
): Boolean =
implementation == null ||
implementation.origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB ||
@@ -22,7 +22,10 @@ import org.jetbrains.kotlin.ir.expressions.IrReturn
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.defaultType
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.util.functions
import org.jetbrains.kotlin.ir.util.isMethodOfAny
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.util.resolveFakeOverrideOrFail
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
@@ -101,7 +104,7 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran
if (function.name.asString().endsWith("\$default")) {
continue
}
val implementation = function.resolveFakeOverride() ?: error("No single implementation found for: ${function.render()}")
val implementation = function.resolveFakeOverrideOrFail()
when {
DescriptorVisibilities.isPrivate(implementation.visibility) || implementation.isMethodOfAny() ->
@@ -83,13 +83,13 @@ class JvmPropertiesLowering(private val backendContext: JvmBackendContext) : IrE
// to get the backing field which would no longer exist.
val inInlineFunctionScope = allScopes.any { scope -> (scope.irElement as? IrFunction)?.isInline ?: false }
if (inInlineFunctionScope) return false
val backingField = property.resolveFakeOverride()!!.backingField
val backingField = property.resolveFakeOverrideOrFail().backingField
return backingField?.parent == currentClass?.irElement &&
backingField?.origin == JvmLoweredDeclarationOrigin.COMPANION_PROPERTY_BACKING_FIELD
}
private fun IrBuilderWithScope.substituteSetter(irProperty: IrProperty, expression: IrCall): IrExpression {
val backingField = irProperty.resolveFakeOverride()!!.backingField!!
val backingField = irProperty.resolveFakeOverrideOrFail().backingField!!
return patchReceiver(
irSetField(
patchFieldAccessReceiver(expression, irProperty),
@@ -100,7 +100,7 @@ class JvmPropertiesLowering(private val backendContext: JvmBackendContext) : IrE
}
private fun IrBuilderWithScope.substituteGetter(irProperty: IrProperty, expression: IrCall): IrExpression {
val backingField = irProperty.resolveFakeOverride()!!.backingField!!
val backingField = irProperty.resolveFakeOverrideOrFail().backingField!!
val patchedReceiver = patchFieldAccessReceiver(expression, irProperty)
return if (irProperty.isLateinit) {
irBlock {
@@ -73,8 +73,8 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : FileL
return true
val declaration = when (declarationRaw) {
is IrSimpleFunction -> declarationRaw.resolveFakeOverride(allowAbstract = true)!!
is IrField -> declarationRaw.resolveFakeOverride()
is IrSimpleFunction -> declarationRaw.resolveFakeOverrideMaybeAbstractOrFail()
is IrField -> declarationRaw.resolveFieldFakeOverride()
else -> declarationRaw
}
@@ -376,15 +376,13 @@ private class SyntheticAccessorTransformer(
}
}
private fun IrField.resolveFakeOverride(): IrField {
private fun IrField.resolveFieldFakeOverride(): IrField {
val correspondingProperty = correspondingPropertySymbol?.owner
if (correspondingProperty == null || !correspondingProperty.isFakeOverride)
return this
val realProperty = correspondingProperty.resolveFakeOverride()
?: throw AssertionError("No real override for ${correspondingProperty.render()}")
return realProperty.backingField
return correspondingProperty.resolveFakeOverrideOrFail().backingField
?: throw AssertionError(
"Fake override property ${correspondingProperty.render()} with backing field " +
"overrides a real property with no backing field: ${realProperty.render()}"
"overrides a real property with no backing field: ${correspondingProperty.resolveFakeOverrideOrFail().render()}"
)
}
@@ -201,7 +201,7 @@ class JvmCachedDeclarations(
// The classes are not actually related and `I2.DefaultImpls.f` is not a fake override but a bridge.
val defaultImplsOrigin =
if (!forCompatibilityMode && !interfaceFun.isFakeOverride) interfaceFun.origin
else interfaceFun.resolveFakeOverride()!!.origin
else interfaceFun.resolveFakeOverrideOrFail().origin
// Interface functions are public or private, with one exception: clone in Cloneable, which is protected.
// However, Cloneable has no DefaultImpls, so this merely replicates the incorrect behavior of the old backend.
@@ -225,7 +225,7 @@ class JvmCachedDeclarations(
).also {
it.copyCorrespondingPropertyFrom(interfaceFun)
if (forCompatibilityMode && !interfaceFun.resolveFakeOverride()!!.origin.isSynthetic) {
if (forCompatibilityMode && !interfaceFun.resolveFakeOverrideOrFail().origin.isSynthetic) {
context.createJvmIrBuilder(it.symbol).run {
it.annotations = it.annotations
.filterNot { it.symbol.owner.constructedClass.hasEqualFqName(DeprecationResolver.JAVA_DEPRECATED) }
@@ -225,7 +225,7 @@ class MemoizedInlineClassReplacements(
// When using the new mangling scheme we might run into dependencies using the old scheme
// for which we will fall back to the old mangling scheme as well.
if (!useOldManglingScheme && replacement.name.asString().contains('-') && function.parentClassId != null) {
val resolved = (function as? IrSimpleFunction)?.resolveFakeOverride(true)
val resolved = (function as? IrSimpleFunction)?.resolveFakeOverrideMaybeAbstractOrFail()
if (resolved?.parentClassId?.let { classFileContainsMethod(it, replacement, context) } == false) {
return buildReplacementInner(function, replacementOrigin, noFakeOverride, true, body)
}
@@ -35,10 +35,6 @@ internal interface Complex : State {
}
}
fun getRealFunction(owner: IrSimpleFunction): IrSimpleFunction {
return owner.resolveFakeOverride() as IrSimpleFunction
}
override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? {
val receiver = expression.superQualifierSymbol?.owner ?: irClass
val irFunction = getIrFunctionFromGivenClass(receiver, expression.symbol.owner) ?: return null
@@ -19,20 +19,18 @@ val IrDeclaration.isFakeOverride: Boolean
}
val IrSimpleFunction.target: IrSimpleFunction
get() = if (modality == Modality.ABSTRACT)
this
else
resolveFakeOverride() ?: error("Could not resolveFakeOverride() for ${this.render()}")
get() = if (modality == Modality.ABSTRACT) this else resolveFakeOverrideOrFail()
val IrFunction.target: IrFunction get() = when (this) {
is IrSimpleFunction -> this.target
is IrConstructor -> this
else -> error(this)
}
val IrFunction.target: IrFunction
get() = when (this) {
is IrSimpleFunction -> this.target
is IrConstructor -> this
else -> error(this)
}
fun <S : IrSymbol, T : IrOverridableDeclaration<S>> T.collectRealOverrides(
toSkip: (T) -> Boolean = { false },
filter: (T) -> Boolean = { false }
filter: (T) -> Boolean = { false },
): Set<T> {
if (isReal && !toSkip(this)) return setOf(this)
@@ -92,31 +90,29 @@ fun Collection<IrOverridableMember>.collectAndFilterRealOverrides(): Set<IrOverr
else -> error("all members should be of the same kind, got ${map { it.render() }}")
}
fun <S : IrSymbol, T : IrOverridableDeclaration<S>> T.resolveFakeOverride(
allowAbstract: Boolean = false,
toSkip: (T) -> Boolean = { false }
): T? =
resolveFakeOverrideOrNull(allowAbstract, toSkip).also {
if (allowAbstract && it == null) {
error("No real overrides for ${this.render()}")
}
}
fun <S : IrSymbol, T : IrOverridableDeclaration<S>> T.resolveFakeOverrideMaybeAbstractOrFail(): T =
resolveFakeOverrideMaybeAbstract() ?: error("No real overrides for ${this.render()}")
// TODO: use this implementation instead of any other
fun <S : IrSymbol, T : IrOverridableDeclaration<S>> T.resolveFakeOverrideOrNull(
allowAbstract: Boolean = false,
toSkip: (T) -> Boolean = { false }
fun <S : IrSymbol, T : IrOverridableDeclaration<S>> T.resolveFakeOverrideMaybeAbstract(
toSkip: (T) -> Boolean = { false },
): T? {
if (!isFakeOverride && !toSkip(this)) return this
return if (allowAbstract) {
collectRealOverrides(toSkip).firstOrNull()
} else {
collectRealOverrides(toSkip, { it.modality == Modality.ABSTRACT })
.let { realOverrides ->
// Kotlin forbids conflicts between overrides, but they may trickle down from Java.
realOverrides.singleOrNull { (it.parent as? IrClass)?.isInterface != true }
// TODO: We take firstOrNull instead of singleOrNull here because of KT-36188.
?: realOverrides.firstOrNull()
}
}
return collectRealOverrides(toSkip).firstOrNull()
}
fun <S : IrSymbol, T : IrOverridableDeclaration<S>> T.resolveFakeOverrideOrFail(): T =
resolveFakeOverride() ?: error("No real overrides for ${this.render()}")
// TODO: use this implementation instead of any other
fun <S : IrSymbol, T : IrOverridableDeclaration<S>> T.resolveFakeOverride(
toSkip: (T) -> Boolean = { false },
): T? {
if (!isFakeOverride && !toSkip(this)) return this
return collectRealOverrides(toSkip) { it.modality == Modality.ABSTRACT }
.let { realOverrides ->
// Kotlin forbids conflicts between overrides, but they may trickle down from Java.
realOverrides.singleOrNull { (it.parent as? IrClass)?.isInterface != true }
// TODO: We take firstOrNull instead of singleOrNull here because of KT-36188.
?: realOverrides.firstOrNull()
}
}
@@ -306,12 +306,6 @@ fun IrClass.isSubclassOf(ancestor: IrClass): Boolean {
return this.hasAncestorInSuperTypes()
}
fun IrSimpleFunction.findInterfaceImplementation(): IrSimpleFunction? {
if (isReal) return null
return resolveFakeOverride()?.run { if (parentAsClass.isInterface) this else null }
}
val IrClass.isAnnotationClass get() = kind == ClassKind.ANNOTATION_CLASS
val IrClass.isEnumClass get() = kind == ClassKind.ENUM_CLASS
val IrClass.isEnumEntry get() = kind == ClassKind.ENUM_ENTRY
@@ -6,14 +6,14 @@
package org.jetbrains.kotlin.test.backend.handlers
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrExternalPackageFragment
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.declarations.IrExternalPackageFragment
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.lazy.AbstractIrLazyFunction
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
import org.jetbrains.kotlin.ir.util.DeserializableClass
import org.jetbrains.kotlin.ir.util.IdSignature
import org.jetbrains.kotlin.ir.util.resolveFakeOverride
import org.jetbrains.kotlin.ir.util.resolveFakeOverrideOrFail
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.test.backend.ir.IrBackendInput
@@ -59,7 +59,7 @@ class IrInlineBodiesHandler(testServices: TestServices) : AbstractIrHandler(test
assertions.assertTrue(symbol.isBound)
val callee = symbol.owner
if (callee.symbol.signature in declaredInlineFunctionSignatures) {
val trueCallee = (callee as IrSimpleFunction).resolveFakeOverride()!!
val trueCallee = (callee as IrSimpleFunction).resolveFakeOverrideOrFail()
assertions.assertTrue(trueCallee.hasBody()) {
"IrInlineBodiesHandler: function with body expected"
}
@@ -307,7 +307,7 @@ internal fun KotlinStubs.generateObjCCall(
receiver: ObjCCallReceiver,
arguments: List<IrExpression?>
) = builder.irBlock {
val resolved = method.resolveFakeOverride(allowAbstract = true)?: method
val resolved = method.resolveFakeOverrideMaybeAbstract() ?: method
val isDirect = directSymbolName != null
val exceptionMode = ForeignExceptionMode.byValue(
@@ -306,7 +306,7 @@ internal object VirtualTablesLookup {
}
internal fun IrSimpleFunction.findOverriddenMethodOfAny() =
resolveFakeOverride(allowAbstract = false).takeIf { it?.parentClassOrNull?.isAny() == true }
resolveFakeOverride().takeIf { it?.parentClassOrNull?.isAny() == true }
/*
* Special trampoline function to call actual virtual implementation. This helps with reducing
@@ -1533,7 +1533,7 @@ private fun ObjCExportCodeGenerator.itablePlace(irFunction: IrSimpleFunction): C
assert(irFunction.isOverridable)
val irClass = irFunction.parentAsClass
return if (irClass.isInterface
&& (irFunction.isReal || irFunction.resolveFakeOverride(allowAbstract = true)?.parent != context.irBuiltIns.anyClass.owner)
&& (irFunction.isReal || irFunction.resolveFakeOverrideMaybeAbstract()?.parent != context.irBuiltIns.anyClass.owner)
) {
context.getLayoutBuilder(irClass).itablePlace(irFunction)
} else {
@@ -1088,7 +1088,7 @@ private class InteropTransformer(
builder.at(expression)
val function = expression.symbol.owner
if ((function as? IrSimpleFunction)?.resolveFakeOverride(allowAbstract = true)?.symbol
if ((function as? IrSimpleFunction)?.resolveFakeOverrideMaybeAbstract()?.symbol
== symbols.interopNativePointedRawPtrGetter) {
// Replace by the intrinsic call to be handled by code generator: