JVM_IR. Fix bridge generation
This commit is contained in:
@@ -18,5 +18,3 @@ sourceSets {
|
||||
"main" { projectDefault() }
|
||||
"test" {}
|
||||
}
|
||||
|
||||
val compileKotlin: org.jetbrains.kotlin.gradle.tasks.KotlinCompile by tasks
|
||||
|
||||
+1
-1
@@ -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()
|
||||
|
||||
|
||||
+31
-26
@@ -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
|
||||
}
|
||||
@@ -13,6 +13,4 @@ dependencies {
|
||||
sourceSets {
|
||||
"main" { projectDefault() }
|
||||
"test" {}
|
||||
}
|
||||
|
||||
val compileKotlin: org.jetbrains.kotlin.gradle.tasks.KotlinCompile by tasks
|
||||
}
|
||||
+31
@@ -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()
|
||||
}
|
||||
+5
@@ -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");
|
||||
|
||||
Generated
+5
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user