diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirBlackBoxCodegenBasedTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirBlackBoxCodegenBasedTestGenerated.java index 76050a3179a96..899ea3fc3bfbe 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirBlackBoxCodegenBasedTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirBlackBoxCodegenBasedTestGenerated.java @@ -57934,6 +57934,24 @@ public void testJavaMapWithCustomEntries() { runTest("compiler/testData/codegen/box/specialBuiltins/javaMapWithCustomEntries.kt"); } + @Test + @TestMetadata("kt20070_1.kt") + public void testKt20070_1() { + runTest("compiler/testData/codegen/box/specialBuiltins/kt20070_1.kt"); + } + + @Test + @TestMetadata("kt20070_2.kt") + public void testKt20070_2() { + runTest("compiler/testData/codegen/box/specialBuiltins/kt20070_2.kt"); + } + + @Test + @TestMetadata("kt20070_3.kt") + public void testKt20070_3() { + runTest("compiler/testData/codegen/box/specialBuiltins/kt20070_3.kt"); + } + @Test @TestMetadata("mapGetOrDefault.kt") public void testMapGetOrDefault() { diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirReversedBlackBoxCodegenBasedTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirReversedBlackBoxCodegenBasedTestGenerated.java index f2fe5850d875e..97d2c66eb6f10 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirReversedBlackBoxCodegenBasedTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirReversedBlackBoxCodegenBasedTestGenerated.java @@ -57934,6 +57934,24 @@ public void testJavaMapWithCustomEntries() { runTest("compiler/testData/codegen/box/specialBuiltins/javaMapWithCustomEntries.kt"); } + @Test + @TestMetadata("kt20070_1.kt") + public void testKt20070_1() { + runTest("compiler/testData/codegen/box/specialBuiltins/kt20070_1.kt"); + } + + @Test + @TestMetadata("kt20070_2.kt") + public void testKt20070_2() { + runTest("compiler/testData/codegen/box/specialBuiltins/kt20070_2.kt"); + } + + @Test + @TestMetadata("kt20070_3.kt") + public void testKt20070_3() { + runTest("compiler/testData/codegen/box/specialBuiltins/kt20070_3.kt"); + } + @Test @TestMetadata("mapGetOrDefault.kt") public void testMapGetOrDefault() { diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java index d8c7e1e15b668..a553493a43bf6 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java @@ -57455,6 +57455,24 @@ public void testJavaMapWithCustomEntries() { runTest("compiler/testData/codegen/box/specialBuiltins/javaMapWithCustomEntries.kt"); } + @Test + @TestMetadata("kt20070_1.kt") + public void testKt20070_1() { + runTest("compiler/testData/codegen/box/specialBuiltins/kt20070_1.kt"); + } + + @Test + @TestMetadata("kt20070_2.kt") + public void testKt20070_2() { + runTest("compiler/testData/codegen/box/specialBuiltins/kt20070_2.kt"); + } + + @Test + @TestMetadata("kt20070_3.kt") + public void testKt20070_3() { + runTest("compiler/testData/codegen/box/specialBuiltins/kt20070_3.kt"); + } + @Test @TestMetadata("mapGetOrDefault.kt") public void testMapGetOrDefault() { diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java index 10dfdfad05dcc..03aed8f3987c2 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java @@ -57519,6 +57519,24 @@ public void testJavaMapWithCustomEntries() { runTest("compiler/testData/codegen/box/specialBuiltins/javaMapWithCustomEntries.kt"); } + @Test + @TestMetadata("kt20070_1.kt") + public void testKt20070_1() { + runTest("compiler/testData/codegen/box/specialBuiltins/kt20070_1.kt"); + } + + @Test + @TestMetadata("kt20070_2.kt") + public void testKt20070_2() { + runTest("compiler/testData/codegen/box/specialBuiltins/kt20070_2.kt"); + } + + @Test + @TestMetadata("kt20070_3.kt") + public void testKt20070_3() { + runTest("compiler/testData/codegen/box/specialBuiltins/kt20070_3.kt"); + } + @Test @TestMetadata("mapGetOrDefault.kt") public void testMapGetOrDefault() { diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt index aa60852eab9d4..d46c4c74a4e93 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.backend.common.phaser.PhaseDescription import org.jetbrains.kotlin.backend.jvm.* import org.jetbrains.kotlin.backend.jvm.ir.* import org.jetbrains.kotlin.backend.jvm.mapping.MethodSignatureMapper +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.Modality @@ -315,8 +316,8 @@ internal class BridgeLowering(val context: JvmBackendContext) : ClassLoweringPas // Generate common bridges val generated = mutableMapOf() - - for (override in irFunction.allOverridden()) { + val allOverridden = irFunction.allOverridden() + for (override in allOverridden) { if (override.isFakeOverride) continue val signature = override.jvmMethod @@ -328,6 +329,47 @@ internal class BridgeLowering(val context: JvmBackendContext) : ClassLoweringPas } } + /** + * See KT-20070. + * + * Check if a method indirectly overridden [kotlin.collections.Map.entries]. + * If [irFunction] directly override [kotlin.collections.Map.entries], no issue here. + * If an overridden chain like this: A1.entries -> A2.entries -> ... -> An.entries -> Map.entries + * ("->" represents "override"), and all "entries" functions in from 'A2' to 'An' are FAKEOVERRIDE, + * the issue occurs. + * To solve this, we add a hardcoded bridge "getEntries()Ljava/util/Set;" here. + * + * This issue occurred because we forgot to add "getEntries()Ljava/tilt/Set;". The + * bridge method for [kotlin.collections.Map.entries] is "entrySet()Ljava/tilt/Set;" + * (see [org.jetbrains.kotlin.load.java.BuiltinSpecialProperties.PROPERTY_FQ_NAME_TO_JVM_GETTER_NAME_MAP]). + * But when the above situation occurs, we also need a "getEntries()Ljava/util/Set;". + * So the hardcoded bridge will not affect other situations. + */ + val entriesGetterName = "" + val mapEntriesName = StandardNames.FqNames.map.child(Name.identifier("")) + val entriesGetters = allOverridden.filter { + it.kotlinFqName != mapEntriesName && it.name.asString() == entriesGetterName + } + val overrideMapEntries = + // Check not directly override [kotlin.collections.Map.entries] + irFunction.overriddenSymbols.none { it.owner.kotlinFqName == mapEntriesName } + // Check all override in chain is FAKEOVERRIDE + && entriesGetters.isNotEmpty() + && entriesGetters.all { it.isFakeOverride } + // Check if really override [kotlin.collections.Map.entries] + && allOverridden.any { it.kotlinFqName == mapEntriesName } + if (overrideMapEntries) { + val override = irFunction.overriddenSymbols.first { + it.owner.isFakeOverride && it.owner.name.asString() == entriesGetterName + }.owner + val signature = override.jvmMethod + if (targetMethod != signature && signature !in blacklist) { + val bridge = generated.getOrPut(signature) { + Bridge(override, signature) + } + bridge.overriddenSymbols += override.symbol + } + } if (generated.isEmpty()) return diff --git a/compiler/testData/codegen/box/specialBuiltins/kt20070_1.kt b/compiler/testData/codegen/box/specialBuiltins/kt20070_1.kt new file mode 100644 index 0000000000000..811ca334c8ff0 --- /dev/null +++ b/compiler/testData/codegen/box/specialBuiltins/kt20070_1.kt @@ -0,0 +1,19 @@ +// WITH_STDLIB +// TARGET_BACKEND: JVM + +class KtMap : AbstractMap() { + override val entries: HashSet> + get() = HashSet>().apply { + add(object : Map.Entry { + override val key: String + get() = "O" + override val value: String + get() = "K" + }) + } +} + +fun box(): String { + val entry = KtMap().entries.first() + return entry.key + entry.value +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/specialBuiltins/kt20070_2.kt b/compiler/testData/codegen/box/specialBuiltins/kt20070_2.kt new file mode 100644 index 0000000000000..a1d694f3b3dde --- /dev/null +++ b/compiler/testData/codegen/box/specialBuiltins/kt20070_2.kt @@ -0,0 +1,46 @@ +// WITH_STDLIB +// TARGET_BACKEND: JVM +abstract class MyMap : AbstractMap() { + override val keys: Set + get() = TODO("Not yet implemented") + override val size: Int + get() = TODO("Not yet implemented") + override val values: Collection + get() = TODO("Not yet implemented") + + override fun isEmpty(): Boolean { + TODO("Not yet implemented") + } + + override fun get(key: String): String? { + TODO("Not yet implemented") + } + + override fun containsValue(value: String): Boolean { + TODO("Not yet implemented") + } + + override fun containsKey(key: String): Boolean { + TODO("Not yet implemented") + } + +} + +abstract class MyMap1 : MyMap(), Map +abstract class MyMap2 : MyMap1() +class KtMap : MyMap2() { + override val entries: HashSet> + get() = HashSet>().apply { + add(object : Map.Entry { + override val key: String + get() = "O" + override val value: String + get() = "K" + }) + } +} + +fun box(): String { + val entry = KtMap().entries.first() + return entry.key + entry.value +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/specialBuiltins/kt20070_3.kt b/compiler/testData/codegen/box/specialBuiltins/kt20070_3.kt new file mode 100644 index 0000000000000..f428d782360b1 --- /dev/null +++ b/compiler/testData/codegen/box/specialBuiltins/kt20070_3.kt @@ -0,0 +1,49 @@ +// WITH_STDLIB +// TARGET_BACKEND: JVM +// FILE: MyMap2.java +abstract public class MyMap2 extends MyMap1 {} + +// FILE: main.kt +abstract class MyMap : AbstractMap() { + override val keys: Set + get() = TODO("Not yet implemented") + override val size: Int + get() = TODO("Not yet implemented") + override val values: Collection + get() = TODO("Not yet implemented") + + override fun isEmpty(): Boolean { + TODO("Not yet implemented") + } + + override fun get(key: String): String? { + TODO("Not yet implemented") + } + + override fun containsValue(value: String): Boolean { + TODO("Not yet implemented") + } + + override fun containsKey(key: String): Boolean { + TODO("Not yet implemented") + } + +} + +abstract class MyMap1 : MyMap(), Map +class KtMap : MyMap2() { + override val entries: HashSet> + get() = HashSet>().apply { + add(object : Map.Entry { + override val key: String + get() = "O" + override val value: String + get() = "K" + }) + } +} + +fun box(): String { + val entry = KtMap().entries.first() + return entry.key + entry.value +} \ No newline at end of file diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/JvmAbiConsistencyTestBoxGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/JvmAbiConsistencyTestBoxGenerated.java index 4b717bca4b15e..3b06340fa96fb 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/JvmAbiConsistencyTestBoxGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/JvmAbiConsistencyTestBoxGenerated.java @@ -56413,6 +56413,24 @@ public void testJavaMapWithCustomEntries() { runTest("compiler/testData/codegen/box/specialBuiltins/javaMapWithCustomEntries.kt"); } + @Test + @TestMetadata("kt20070_1.kt") + public void testKt20070_1() { + runTest("compiler/testData/codegen/box/specialBuiltins/kt20070_1.kt"); + } + + @Test + @TestMetadata("kt20070_2.kt") + public void testKt20070_2() { + runTest("compiler/testData/codegen/box/specialBuiltins/kt20070_2.kt"); + } + + @Test + @TestMetadata("kt20070_3.kt") + public void testKt20070_3() { + runTest("compiler/testData/codegen/box/specialBuiltins/kt20070_3.kt"); + } + @Test @TestMetadata("mapGetOrDefault.kt") public void testMapGetOrDefault() { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index ed9ce17da9177..f0fa588a2a100 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -56685,6 +56685,24 @@ public void testJavaMapWithCustomEntries() { runTest("compiler/testData/codegen/box/specialBuiltins/javaMapWithCustomEntries.kt"); } + @Test + @TestMetadata("kt20070_1.kt") + public void testKt20070_1() { + runTest("compiler/testData/codegen/box/specialBuiltins/kt20070_1.kt"); + } + + @Test + @TestMetadata("kt20070_2.kt") + public void testKt20070_2() { + runTest("compiler/testData/codegen/box/specialBuiltins/kt20070_2.kt"); + } + + @Test + @TestMetadata("kt20070_3.kt") + public void testKt20070_3() { + runTest("compiler/testData/codegen/box/specialBuiltins/kt20070_3.kt"); + } + @Test @TestMetadata("mapGetOrDefault.kt") public void testMapGetOrDefault() { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java index 96f19524526a1..ca9273c124ac0 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java @@ -56685,6 +56685,24 @@ public void testJavaMapWithCustomEntries() { runTest("compiler/testData/codegen/box/specialBuiltins/javaMapWithCustomEntries.kt"); } + @Test + @TestMetadata("kt20070_1.kt") + public void testKt20070_1() { + runTest("compiler/testData/codegen/box/specialBuiltins/kt20070_1.kt"); + } + + @Test + @TestMetadata("kt20070_2.kt") + public void testKt20070_2() { + runTest("compiler/testData/codegen/box/specialBuiltins/kt20070_2.kt"); + } + + @Test + @TestMetadata("kt20070_3.kt") + public void testKt20070_3() { + runTest("compiler/testData/codegen/box/specialBuiltins/kt20070_3.kt"); + } + @Test @TestMetadata("mapGetOrDefault.kt") public void testMapGetOrDefault() { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/inlineScopes/FirBlackBoxCodegenTestWithInlineScopesGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/inlineScopes/FirBlackBoxCodegenTestWithInlineScopesGenerated.java index d90d61bd8bdde..e6628fb8cc738 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/inlineScopes/FirBlackBoxCodegenTestWithInlineScopesGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/inlineScopes/FirBlackBoxCodegenTestWithInlineScopesGenerated.java @@ -57455,6 +57455,24 @@ public void testJavaMapWithCustomEntries() { runTest("compiler/testData/codegen/box/specialBuiltins/javaMapWithCustomEntries.kt"); } + @Test + @TestMetadata("kt20070_1.kt") + public void testKt20070_1() { + runTest("compiler/testData/codegen/box/specialBuiltins/kt20070_1.kt"); + } + + @Test + @TestMetadata("kt20070_2.kt") + public void testKt20070_2() { + runTest("compiler/testData/codegen/box/specialBuiltins/kt20070_2.kt"); + } + + @Test + @TestMetadata("kt20070_3.kt") + public void testKt20070_3() { + runTest("compiler/testData/codegen/box/specialBuiltins/kt20070_3.kt"); + } + @Test @TestMetadata("mapGetOrDefault.kt") public void testMapGetOrDefault() { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 1cf995b1408ec..7ba6980b09779 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -45950,6 +45950,21 @@ public void testJavaMapWithCustomEntries() { runTest("compiler/testData/codegen/box/specialBuiltins/javaMapWithCustomEntries.kt"); } + @TestMetadata("kt20070_1.kt") + public void testKt20070_1() { + runTest("compiler/testData/codegen/box/specialBuiltins/kt20070_1.kt"); + } + + @TestMetadata("kt20070_2.kt") + public void testKt20070_2() { + runTest("compiler/testData/codegen/box/specialBuiltins/kt20070_2.kt"); + } + + @TestMetadata("kt20070_3.kt") + public void testKt20070_3() { + runTest("compiler/testData/codegen/box/specialBuiltins/kt20070_3.kt"); + } + @TestMetadata("mapGetOrDefault.kt") public void testMapGetOrDefault() { runTest("compiler/testData/codegen/box/specialBuiltins/mapGetOrDefault.kt");