[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
interfacePhase then
interfaceDelegationPhase then
inheritedDefaultMethodsOnClassesPhase then
interfaceSuperCallsPhase then
interfaceDefaultCallsPhase then
interfaceObjectCallsPhase then
@@ -170,7 +170,7 @@ private fun IrDeclarationWithVisibility.specialCaseVisibility(kind: OwnerKind?):
// return ACC_PUBLIC
// }
if (this is IrClass && Visibilities.isPrivate(visibility) &&
parent.safeAs<IrClass>()?.isInterface ?: false
hasInterfaceParent()
) { // TODO: non-intrinsic
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.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<IrSimpleFunction> =
allOverridden().filter { !(it.parent.safeAs<IrClass>()?.isInterface ?: true) }
allOverridden().filterNot(IrDeclaration::hasInterfaceParent)
fun IrSimpleFunction.isCollectionStub(): Boolean =
origin == IrDeclarationOrigin.IR_BUILTINS_STUB
@@ -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<IrClass>()?.isInterface != true ||
if (!callee.hasInterfaceParent() ||
callee.origin != IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER ||
(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.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<IrClass>()?.isInterface == true
fun IrDeclaration.isEffectivelyExternal(): Boolean {
fun IrFunction.effectiveParentDeclaration(): IrDeclaration? =