From 0abdd0cb7b0bd0f19569437e877539209368197a Mon Sep 17 00:00:00 2001 From: Kristoffer Andersen Date: Wed, 8 Jan 2020 16:04:17 +0100 Subject: [PATCH] [JVM IR] Refactor InterfaceDelegationPhase Rename and refactor interface delegation phase. It didn't actually do what was said on the box. It should be more in line with the intentions of the phase now. --- .../jetbrains/kotlin/backend/jvm/JvmLower.kt | 2 +- .../backend/jvm/codegen/irCodegenUtils.kt | 2 +- .../backend/jvm/lower/BridgeLowering.kt | 7 +-- ...heritedDefaultMethodsOnClassesLowering.kt} | 56 ++++++++----------- .../org/jetbrains/kotlin/ir/util/IrUtils.kt | 5 ++ 5 files changed, 33 insertions(+), 39 deletions(-) rename compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/{InterfaceDelegationLowering.kt => InheritedDefaultMethodsOnClassesLowering.kt} (85%) 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? =