[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.
This commit is contained in:
Kristoffer Andersen
2020-01-08 16:04:17 +01:00
committed by Alexander Udalov
parent a5ff88f897
commit 0abdd0cb7b
5 changed files with 33 additions and 39 deletions
@@ -290,7 +290,7 @@ private val jvmFilePhases =
defaultArgumentInjectorPhase then defaultArgumentInjectorPhase then
interfacePhase then interfacePhase then
interfaceDelegationPhase then inheritedDefaultMethodsOnClassesPhase then
interfaceSuperCallsPhase then interfaceSuperCallsPhase then
interfaceDefaultCallsPhase then interfaceDefaultCallsPhase then
interfaceObjectCallsPhase then interfaceObjectCallsPhase then
@@ -170,7 +170,7 @@ private fun IrDeclarationWithVisibility.specialCaseVisibility(kind: OwnerKind?):
// return ACC_PUBLIC // return ACC_PUBLIC
// } // }
if (this is IrClass && Visibilities.isPrivate(visibility) && if (this is IrClass && Visibilities.isPrivate(visibility) &&
parent.safeAs<IrClass>()?.isInterface ?: false hasInterfaceParent()
) { // TODO: non-intrinsic ) { // TODO: non-intrinsic
return Opcodes.ACC_PUBLIC return Opcodes.ACC_PUBLIC
} }
@@ -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.IrType
import org.jetbrains.kotlin.ir.types.isNullable import org.jetbrains.kotlin.ir.types.isNullable
import org.jetbrains.kotlin.ir.types.makeNullable import org.jetbrains.kotlin.ir.types.makeNullable
import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.*
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.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addToStdlib.safeAs 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<IrSimpleFunction> = fun IrSimpleFunction.overriddenInClasses(): Sequence<IrSimpleFunction> =
allOverridden().filter { !(it.parent.safeAs<IrClass>()?.isInterface ?: true) } allOverridden().filterNot(IrDeclaration::hasInterfaceParent)
fun IrSimpleFunction.isCollectionStub(): Boolean = fun IrSimpleFunction.isCollectionStub(): Boolean =
origin == IrDeclarationOrigin.IR_BUILTINS_STUB origin == IrDeclarationOrigin.IR_BUILTINS_STUB
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.backend.jvm.lower 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.FileLoweringPass
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.ir.isMethodOfAny 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.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.util.* 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 import org.jetbrains.kotlin.utils.addToStdlib.safeAs
internal val interfaceDelegationPhase = makeIrFilePhase( internal val inheritedDefaultMethodsOnClassesPhase = makeIrFilePhase(
::InterfaceDelegationLowering, ::InheritedDefaultMethodsOnClassesLowering,
name = "InterfaceDelegation", name = "InheritedDefaultMethodsOnClasses",
description = "Delegate calls to interface members with default implementations to DefaultImpls" description = "Add bridge-implementations in classes that inherit default implementations from interfaces"
) )
private class InterfaceDelegationLowering(val context: JvmBackendContext) : IrElementVisitorVoid, FileLoweringPass { private class InheritedDefaultMethodsOnClassesLowering(val context: JvmBackendContext) : IrElementVisitorVoid, ClassLoweringPass {
override fun lower(irFile: IrFile) {
irFile.acceptChildrenVoid(this)
irFile.acceptVoid(OverriddenSymbolsReplacer())
}
override fun visitElement(element: IrElement) { override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this) element.acceptChildrenVoid(this)
} }
override fun visitClass(declaration: IrClass) { override fun lower(declaration: IrClass) {
super.visitClass(declaration) super.visitClass(declaration)
if (declaration.isJvmInterface) return 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? { private fun IrSimpleFunction.getTargetForRedirection(): IrSimpleFunction? {
if (origin != IrDeclarationOrigin.FAKE_OVERRIDE) return null if (origin != IrDeclarationOrigin.FAKE_OVERRIDE) return null
parent.let { if (it is IrClass && it.isJvmInterface) 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 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( internal val interfaceSuperCallsPhase = makeIrFilePhase(
lowering = ::InterfaceSuperCallsLowering, lowering = ::InterfaceSuperCallsLowering,
name = "InterfaceSuperCalls", name = "InterfaceSuperCalls",
@@ -174,7 +166,7 @@ private class InterfaceDefaultCallsLowering(val context: JvmBackendContext) : Ir
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
val callee = expression.symbol.owner val callee = expression.symbol.owner
if (callee.parent.safeAs<IrClass>()?.isInterface != true || if (!callee.hasInterfaceParent() ||
callee.origin != IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER || callee.origin != IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER ||
(callee.hasJvmDefault() && !context.state.jvmDefaultMode.isCompatibility) (callee.hasJvmDefault() && !context.state.jvmDefaultMode.isCompatibility)
) { ) {
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.resolve.source.PsiSourceElement
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.utils.DFS 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. * 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 IrCall.isSuperToAny() = superQualifierSymbol?.let { this.symbol.owner.isFakeOverriddenFromAny() } ?: false
fun IrDeclaration.hasInterfaceParent() =
parent.safeAs<IrClass>()?.isInterface == true
fun IrDeclaration.isEffectivelyExternal(): Boolean { fun IrDeclaration.isEffectivelyExternal(): Boolean {
fun IrFunction.effectiveParentDeclaration(): IrDeclaration? = fun IrFunction.effectiveParentDeclaration(): IrDeclaration? =