JVM_IR. Fix bridge generation

This commit is contained in:
Mikhael Bogdanov
2020-01-27 11:29:26 +01:00
parent dfa509ec5b
commit 6e94eddb71
8 changed files with 74 additions and 35 deletions
-2
View File
@@ -18,5 +18,3 @@ sourceSets {
"main" { projectDefault() }
"test" {}
}
val compileKotlin: org.jetbrains.kotlin.gradle.tasks.KotlinCompile by tasks
@@ -454,7 +454,7 @@ private class BridgeLowering(val context: JvmBackendContext) : ClassLoweringPass
private inner class FunctionHandleForIrFunction(val irFunction: IrSimpleFunction) : FunctionHandle {
override val isDeclaration get() = irFunction.origin != IrDeclarationOrigin.FAKE_OVERRIDE
override val isDeclaration get() = irFunction.origin != IrDeclarationOrigin.FAKE_OVERRIDE || irFunction.findInterfaceImplementation() != null
override val isAbstract get() = irFunction.modality == Modality.ABSTRACT
override val mayBeUsedAsSuperImplementation get() = !irFunction.parentAsClass.isInterface || irFunction.hasJvmDefault()
@@ -58,7 +58,7 @@ private class InheritedDefaultMethodsOnClassesLowering(val context: JvmBackendCo
private fun generateInterfaceMethods(irClass: IrClass) {
irClass.declarations.transform { declaration ->
(declaration as? IrSimpleFunction)?.getTargetForRedirection()?.let { implementation ->
(declaration as? IrSimpleFunction)?.findInterfaceImplementation()?.let { implementation ->
generateDelegationToDefaultImpl(implementation, declaration)
} ?: declaration
}
@@ -69,37 +69,13 @@ private class InheritedDefaultMethodsOnClassesLowering(val context: JvmBackendCo
// 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)
if (symbol.owner.findInterfaceImplementation() != 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 }
val implementation = resolveFakeOverride() ?: return null
// Only generate interface delegation for functions immediately inherited from an interface.
// (Otherwise, delegation will be present in the parent class)
if (overriddenSymbols.any { !it.owner.parentAsClass.isInterface && it.owner.modality != Modality.ABSTRACT && it.owner.resolveFakeOverride() == implementation }) {
return null
}
if (!implementation.hasInterfaceParent()
|| Visibilities.isPrivate(implementation.visibility)
|| implementation.isDefinitelyNotDefaultImplsMethod()
|| implementation.isMethodOfAny()
|| implementation.hasJvmDefault()
) {
return null
}
return implementation
}
private fun generateDelegationToDefaultImpl(
interfaceImplementation: IrSimpleFunction,
classOverride: IrSimpleFunction
@@ -217,3 +193,32 @@ private class InterfaceObjectCallsLowering(val context: JvmBackendContext) : IrE
return super.visitCall(irCall(expression, resolved, newSuperQualifierSymbol = newSuperQualifierSymbol))
}
}
/**
* Given a fake override in a class, returns an overridden declaration with implementation in interface, such that a method delegating to that
* interface implementation should be generated into the class containing the fake override; or null if the given function is not a fake
* override of any interface implementation or such method was already generated into the superclass or is a method from Any.
*/
internal fun IrSimpleFunction.findInterfaceImplementation(): IrSimpleFunction? {
if (!isFakeOverride) return null
parent.let { if (it is IrClass && it.isJvmInterface) return null }
val implementation = resolveFakeOverride() ?: return null
// Only generate interface delegation for functions immediately inherited from an interface.
// (Otherwise, delegation will be present in the parent class)
if (overriddenSymbols.any { !it.owner.parentAsClass.isInterface && it.owner.modality != Modality.ABSTRACT && it.owner.resolveFakeOverride() == implementation }) {
return null
}
if (!implementation.hasInterfaceParent()
|| Visibilities.isPrivate(implementation.visibility)
|| implementation.isDefinitelyNotDefaultImplsMethod()
|| implementation.isMethodOfAny()
|| implementation.hasJvmDefault()
) {
return null
}
return implementation
}
+1 -3
View File
@@ -13,6 +13,4 @@ dependencies {
sourceSets {
"main" { projectDefault() }
"test" {}
}
val compileKotlin: org.jetbrains.kotlin.gradle.tasks.KotlinCompile by tasks
}
@@ -0,0 +1,31 @@
// FILE: A.kt
package test
interface CodeBlock {
fun foo(): String
}
interface CompositeCodeBlock: CodeBlock {
override fun foo(): String {
return "OK"
}
}
interface ForLoopBody : CodeBlock
abstract class CodeBlockBase: CompositeCodeBlock
abstract class LineSeparatedCodeBlock: CodeBlockBase()
// FILE: B.kt
import test.*
open class KotlinCodeBlock: LineSeparatedCodeBlock()
class KotlinForLoopBody : KotlinCodeBlock(), ForLoopBody
fun box(): String {
return KotlinForLoopBody().foo()
}
@@ -163,6 +163,11 @@ public class CompileKotlinAgainstKotlinTestGenerated extends AbstractCompileKotl
runTest("compiler/testData/compileKotlinAgainstKotlin/innerClassConstructor.kt");
}
@TestMetadata("interfaceDelegationAndBridgesProcessing.kt")
public void testInterfaceDelegationAndBridgesProcessing() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/interfaceDelegationAndBridgesProcessing.kt");
}
@TestMetadata("internalSetterOverridden.kt")
public void testInternalSetterOverridden() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/internalSetterOverridden.kt");
@@ -158,6 +158,11 @@ public class IrCompileKotlinAgainstKotlinTestGenerated extends AbstractIrCompile
runTest("compiler/testData/compileKotlinAgainstKotlin/innerClassConstructor.kt");
}
@TestMetadata("interfaceDelegationAndBridgesProcessing.kt")
public void testInterfaceDelegationAndBridgesProcessing() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/interfaceDelegationAndBridgesProcessing.kt");
}
@TestMetadata("internalSetterOverridden.kt")
public void testInternalSetterOverridden() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/internalSetterOverridden.kt");
@@ -23,6 +23,3 @@ sourceSets {
"main" { projectDefault() }
"test" { none() }
}
val compileKotlin: org.jetbrains.kotlin.gradle.tasks.KotlinCompile by tasks
compileKotlin.kotlinOptions.freeCompilerArgs += "-Xno-use-ir"