JVM_IR. Fix bridge generation
This commit is contained in:
@@ -18,5 +18,3 @@ sourceSets {
|
|||||||
"main" { projectDefault() }
|
"main" { projectDefault() }
|
||||||
"test" {}
|
"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 {
|
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 isAbstract get() = irFunction.modality == Modality.ABSTRACT
|
||||||
override val mayBeUsedAsSuperImplementation get() = !irFunction.parentAsClass.isInterface || irFunction.hasJvmDefault()
|
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) {
|
private fun generateInterfaceMethods(irClass: IrClass) {
|
||||||
irClass.declarations.transform { declaration ->
|
irClass.declarations.transform { declaration ->
|
||||||
(declaration as? IrSimpleFunction)?.getTargetForRedirection()?.let { implementation ->
|
(declaration as? IrSimpleFunction)?.findInterfaceImplementation()?.let { implementation ->
|
||||||
generateDelegationToDefaultImpl(implementation, declaration)
|
generateDelegationToDefaultImpl(implementation, declaration)
|
||||||
} ?: 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.
|
// if the overriden symbol has been, or will be, replaced and patch it accordingly.
|
||||||
override fun visitSimpleFunction(declaration: IrSimpleFunction) {
|
override fun visitSimpleFunction(declaration: IrSimpleFunction) {
|
||||||
declaration.overriddenSymbols.replaceAll { symbol ->
|
declaration.overriddenSymbols.replaceAll { symbol ->
|
||||||
if (symbol.owner.getTargetForRedirection() != null)
|
if (symbol.owner.findInterfaceImplementation() != null)
|
||||||
context.declarationFactory.getDefaultImplsRedirection(symbol.owner).symbol
|
context.declarationFactory.getDefaultImplsRedirection(symbol.owner).symbol
|
||||||
else symbol
|
else symbol
|
||||||
}
|
}
|
||||||
super.visitSimpleFunction(declaration)
|
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(
|
private fun generateDelegationToDefaultImpl(
|
||||||
interfaceImplementation: IrSimpleFunction,
|
interfaceImplementation: IrSimpleFunction,
|
||||||
classOverride: IrSimpleFunction
|
classOverride: IrSimpleFunction
|
||||||
@@ -217,3 +193,32 @@ private class InterfaceObjectCallsLowering(val context: JvmBackendContext) : IrE
|
|||||||
return super.visitCall(irCall(expression, resolved, newSuperQualifierSymbol = newSuperQualifierSymbol))
|
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
|
||||||
|
}
|
||||||
@@ -14,5 +14,3 @@ sourceSets {
|
|||||||
"main" { projectDefault() }
|
"main" { projectDefault() }
|
||||||
"test" {}
|
"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");
|
runTest("compiler/testData/compileKotlinAgainstKotlin/innerClassConstructor.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("interfaceDelegationAndBridgesProcessing.kt")
|
||||||
|
public void testInterfaceDelegationAndBridgesProcessing() throws Exception {
|
||||||
|
runTest("compiler/testData/compileKotlinAgainstKotlin/interfaceDelegationAndBridgesProcessing.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("internalSetterOverridden.kt")
|
@TestMetadata("internalSetterOverridden.kt")
|
||||||
public void testInternalSetterOverridden() throws Exception {
|
public void testInternalSetterOverridden() throws Exception {
|
||||||
runTest("compiler/testData/compileKotlinAgainstKotlin/internalSetterOverridden.kt");
|
runTest("compiler/testData/compileKotlinAgainstKotlin/internalSetterOverridden.kt");
|
||||||
|
|||||||
Generated
+5
@@ -158,6 +158,11 @@ public class IrCompileKotlinAgainstKotlinTestGenerated extends AbstractIrCompile
|
|||||||
runTest("compiler/testData/compileKotlinAgainstKotlin/innerClassConstructor.kt");
|
runTest("compiler/testData/compileKotlinAgainstKotlin/innerClassConstructor.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("interfaceDelegationAndBridgesProcessing.kt")
|
||||||
|
public void testInterfaceDelegationAndBridgesProcessing() throws Exception {
|
||||||
|
runTest("compiler/testData/compileKotlinAgainstKotlin/interfaceDelegationAndBridgesProcessing.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("internalSetterOverridden.kt")
|
@TestMetadata("internalSetterOverridden.kt")
|
||||||
public void testInternalSetterOverridden() throws Exception {
|
public void testInternalSetterOverridden() throws Exception {
|
||||||
runTest("compiler/testData/compileKotlinAgainstKotlin/internalSetterOverridden.kt");
|
runTest("compiler/testData/compileKotlinAgainstKotlin/internalSetterOverridden.kt");
|
||||||
|
|||||||
@@ -23,6 +23,3 @@ sourceSets {
|
|||||||
"main" { projectDefault() }
|
"main" { projectDefault() }
|
||||||
"test" { none() }
|
"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