diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index 6b5b22fd29f..4239bb77182 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -290,7 +290,7 @@ private val jvmFilePhases = defaultArgumentInjectorPhase then interfacePhase then - interfaceDelegationPhase then + inheritedDefaultMethodsOnClassesPhase then interfaceSuperCallsPhase then interfaceDefaultCallsPhase then interfaceObjectCallsPhase then diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt index cddf68856ff..6c42d22df8b 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt @@ -170,7 +170,7 @@ private fun IrDeclarationWithVisibility.specialCaseVisibility(kind: OwnerKind?): // return ACC_PUBLIC // } if (this is IrClass && Visibilities.isPrivate(visibility) && - parent.safeAs()?.isInterface ?: false + hasInterfaceParent() ) { // TODO: non-intrinsic return Opcodes.ACC_PUBLIC } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt index 83a7161230f..e539164516d 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt @@ -39,10 +39,7 @@ import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.isNullable import org.jetbrains.kotlin.ir.types.makeNullable -import org.jetbrains.kotlin.ir.util.defaultType -import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable -import org.jetbrains.kotlin.ir.util.isInterface -import org.jetbrains.kotlin.ir.util.parentAsClass +import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.utils.addToStdlib.safeAs @@ -487,7 +484,7 @@ private data class SignatureWithSource(val signature: Method, val source: IrSimp fun IrSimpleFunction.overriddenInClasses(): Sequence = - allOverridden().filter { !(it.parent.safeAs()?.isInterface ?: true) } + allOverridden().filterNot(IrDeclaration::hasInterfaceParent) fun IrSimpleFunction.isCollectionStub(): Boolean = origin == IrDeclarationOrigin.IR_BUILTINS_STUB diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceDelegationLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InheritedDefaultMethodsOnClassesLowering.kt similarity index 85% rename from compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceDelegationLowering.kt rename to compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InheritedDefaultMethodsOnClassesLowering.kt index a0d8c60ffa4..e3365d0f079 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceDelegationLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InheritedDefaultMethodsOnClassesLowering.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.backend.jvm.lower +import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext import org.jetbrains.kotlin.backend.common.ir.isMethodOfAny @@ -30,27 +31,25 @@ import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.util.* -import org.jetbrains.kotlin.ir.visitors.* +import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid +import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid +import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid +import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.utils.addToStdlib.safeAs -internal val interfaceDelegationPhase = makeIrFilePhase( - ::InterfaceDelegationLowering, - name = "InterfaceDelegation", - description = "Delegate calls to interface members with default implementations to DefaultImpls" +internal val inheritedDefaultMethodsOnClassesPhase = makeIrFilePhase( + ::InheritedDefaultMethodsOnClassesLowering, + name = "InheritedDefaultMethodsOnClasses", + description = "Add bridge-implementations in classes that inherit default implementations from interfaces" ) -private class InterfaceDelegationLowering(val context: JvmBackendContext) : IrElementVisitorVoid, FileLoweringPass { - - override fun lower(irFile: IrFile) { - irFile.acceptChildrenVoid(this) - irFile.acceptVoid(OverriddenSymbolsReplacer()) - } +private class InheritedDefaultMethodsOnClassesLowering(val context: JvmBackendContext) : IrElementVisitorVoid, ClassLoweringPass { override fun visitElement(element: IrElement) { element.acceptChildrenVoid(this) } - override fun visitClass(declaration: IrClass) { + override fun lower(declaration: IrClass) { super.visitClass(declaration) if (declaration.isJvmInterface) return @@ -65,6 +64,18 @@ private class InterfaceDelegationLowering(val context: JvmBackendContext) : IrEl } } + // Functions introduced by this lowering may be inherited lower in the hierarchy. + // Here we use the same logic as the delegation itself (`getTargetForRedirection`) to determine + // if the overriden symbol has been, or will be, replaced and patch it accordingly. + override fun visitSimpleFunction(declaration: IrSimpleFunction) { + declaration.overriddenSymbols.replaceAll { symbol -> + if (symbol.owner.getTargetForRedirection() != null) + context.declarationFactory.getDefaultImplsRedirection(symbol.owner).symbol + else symbol + } + super.visitSimpleFunction(declaration) + } + private fun IrSimpleFunction.getTargetForRedirection(): IrSimpleFunction? { if (origin != IrDeclarationOrigin.FAKE_OVERRIDE) return null parent.let { if (it is IrClass && it.isJvmInterface) return null } @@ -111,27 +122,8 @@ private class InterfaceDelegationLowering(val context: JvmBackendContext) : IrEl return irFunction } - - private inner class OverriddenSymbolsReplacer : IrElementVisitorVoid { - - override fun visitElement(element: IrElement) { - element.acceptChildrenVoid(this) - } - - override fun visitSimpleFunction(declaration: IrSimpleFunction) { - declaration.overriddenSymbols.replaceAll { symbol -> - if (symbol.owner.getTargetForRedirection() != null) - context.declarationFactory.getDefaultImplsRedirection(symbol.owner).symbol - else symbol - } - super.visitSimpleFunction(declaration) - } - } } -private fun IrSimpleFunction.hasInterfaceParent() = - (parent as? IrClass)?.isInterface == true - internal val interfaceSuperCallsPhase = makeIrFilePhase( lowering = ::InterfaceSuperCallsLowering, name = "InterfaceSuperCalls", @@ -174,7 +166,7 @@ private class InterfaceDefaultCallsLowering(val context: JvmBackendContext) : Ir override fun visitCall(expression: IrCall): IrExpression { val callee = expression.symbol.owner - if (callee.parent.safeAs()?.isInterface != true || + if (!callee.hasInterfaceParent() || callee.origin != IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER || (callee.hasJvmDefault() && !context.state.jvmDefaultMode.isCompatibility) ) { 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 eee4782b031..90c502dee77 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 @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.resolve.source.PsiSourceElement import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.utils.DFS +import org.jetbrains.kotlin.utils.addToStdlib.safeAs /** * Binds the arguments explicitly represented in the IR to the parameters of the accessed function. @@ -379,6 +380,10 @@ fun IrFunction.isFakeOverriddenFromAny(): Boolean { fun IrCall.isSuperToAny() = superQualifierSymbol?.let { this.symbol.owner.isFakeOverriddenFromAny() } ?: false + +fun IrDeclaration.hasInterfaceParent() = + parent.safeAs()?.isInterface == true + fun IrDeclaration.isEffectivelyExternal(): Boolean { fun IrFunction.effectiveParentDeclaration(): IrDeclaration? =