From 3278451b073b683fa04f290c20f14c60914e0797 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 11 Feb 2020 20:22:26 +0100 Subject: [PATCH] JVM IR: do not generate certain special bridges as final Special bridges which are generated as a replacement for a non-final fake override and use invokespecial to call the already existing implementation in the superclass, should not be final. Otherwise we can't generate an override for the original Kotlin function in a subclass with the same JVM signature. --- .../kotlin/backend/jvm/lower/BridgeLowering.kt | 12 +++++------- .../specialBuiltins/specialBridgeModality.kt | 17 +++++++++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 5 +++++ .../codegen/LightAnalysisModeTestGenerated.java | 5 +++++ .../ir/FirBlackBoxCodegenTestGenerated.java | 5 +++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 5 +++++ 6 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 compiler/testData/codegen/box/specialBuiltins/specialBridgeModality.kt diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt index 54858922059..e4e8fa1585e 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt @@ -136,7 +136,8 @@ private class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass, val signature: Method, val specializedReturnType: IrType? = null, val methodInfo: SpecialMethodWithDefaultInfo? = null, - val superQualifierSymbol: IrClassSymbol? = null + val superQualifierSymbol: IrClassSymbol? = null, + val isFinal: Boolean = true, ) override fun lower(irFile: IrFile) = irFile.transformChildrenVoid() @@ -229,7 +230,8 @@ private class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass, val superTarget = irFunction.overriddenSymbols.first { !it.owner.parentAsClass.isInterface }.owner val superBridge = SpecialBridge( irFunction, irFunction.jvmMethod, superQualifierSymbol = superTarget.parentAsClass.symbol, - methodInfo = specialBridge.methodInfo?.copy(argumentsToCheck = 0) // For potential argument boxing + methodInfo = specialBridge.methodInfo?.copy(argumentsToCheck = 0), // For potential argument boxing + isFinal = false, ) irClass.declarations.remove(irFunction) irClass.addSpecialBridge(superBridge, superTarget) @@ -366,8 +368,7 @@ private class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass, private fun IrClass.addSpecialBridge(specialBridge: SpecialBridge, target: IrSimpleFunction): IrSimpleFunction = addFunction { - // FIXME: This seems to be a work-around for superfluous specialized collection stubs - modality = if (!target.isCollectionStub()) Modality.FINAL else Modality.OPEN + modality = if (specialBridge.isFinal) Modality.FINAL else Modality.OPEN origin = IrDeclarationOrigin.BRIDGE_SPECIAL name = Name.identifier(specialBridge.signature.name) returnType = specialBridge.specializedReturnType ?: specialBridge.overridden.returnType.eraseTypeParameters() @@ -490,7 +491,4 @@ private class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass, get() = context.methodSignatureMapper.mapAsmMethod(this) } -private fun IrSimpleFunction.isCollectionStub(): Boolean = - origin == IrDeclarationOrigin.IR_BUILTINS_STUB - private fun IrDeclaration.comesFromJava() = parentAsClass.origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB diff --git a/compiler/testData/codegen/box/specialBuiltins/specialBridgeModality.kt b/compiler/testData/codegen/box/specialBuiltins/specialBridgeModality.kt new file mode 100644 index 00000000000..d19b1e9fced --- /dev/null +++ b/compiler/testData/codegen/box/specialBuiltins/specialBridgeModality.kt @@ -0,0 +1,17 @@ +// TARGET_BACKEND: JVM +// IGNORE_BACKEND_FIR: JVM_IR + +import java.util.AbstractMap + +// Neither of getSize, getKeys, getEntries, getValues generated here should be final. +abstract class AbstractMutableMap : MutableMap, AbstractMap() + +class MyMap : AbstractMutableMap() { + override val size: Int + get() = 1 + override val entries: MutableSet> + get() = null!! +} + +fun box(): String = + if (MyMap().size == 1) "OK" else "Fail" diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 1ae2732dbdc..c491dbbfebc 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -27216,6 +27216,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/specialBuiltins/removeSetInt.kt"); } + @TestMetadata("specialBridgeModality.kt") + public void testSpecialBridgeModality() throws Exception { + runTest("compiler/testData/codegen/box/specialBuiltins/specialBridgeModality.kt"); + } + @TestMetadata("throwable.kt") public void testThrowable() throws Exception { runTest("compiler/testData/codegen/box/specialBuiltins/throwable.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index dcfa9ada765..9b7316fb06a 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -26033,6 +26033,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/specialBuiltins/removeSetInt.kt"); } + @TestMetadata("specialBridgeModality.kt") + public void testSpecialBridgeModality() throws Exception { + runTest("compiler/testData/codegen/box/specialBuiltins/specialBridgeModality.kt"); + } + @TestMetadata("throwable.kt") public void testThrowable() throws Exception { runTest("compiler/testData/codegen/box/specialBuiltins/throwable.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index ee8df61ce20..c0c17f90744 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -25720,6 +25720,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/specialBuiltins/removeSetInt.kt"); } + @TestMetadata("specialBridgeModality.kt") + public void testSpecialBridgeModality() throws Exception { + runTest("compiler/testData/codegen/box/specialBuiltins/specialBridgeModality.kt"); + } + @TestMetadata("throwable.kt") public void testThrowable() throws Exception { runTest("compiler/testData/codegen/box/specialBuiltins/throwable.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 08e145b5e73..cb4568ba59a 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -25720,6 +25720,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/specialBuiltins/removeSetInt.kt"); } + @TestMetadata("specialBridgeModality.kt") + public void testSpecialBridgeModality() throws Exception { + runTest("compiler/testData/codegen/box/specialBuiltins/specialBridgeModality.kt"); + } + @TestMetadata("throwable.kt") public void testThrowable() throws Exception { runTest("compiler/testData/codegen/box/specialBuiltins/throwable.kt");