From 4252d9786bc261d43ca657af4e6a26edbe8e38f6 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Thu, 8 Jun 2017 12:13:25 +0300 Subject: [PATCH] Fix translation of interface with non-abstract methods in JS BE Fix additional case of generic interfaces in KT-18187 --- .../interfaceWithNonAbstractFunIndirect.kt | 2 +- ...erfaceWithNonAbstractFunIndirectGeneric.kt | 27 +++++++++++++++++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 6 +++++ .../codegen/BlackBoxCodegenTestGenerated.java | 6 +++++ .../LightAnalysisModeTestGenerated.java | 6 +++++ .../semantics/JsCodegenBoxTestGenerated.java | 6 +++++ .../declaration/ClassModelGenerator.kt | 14 +++++----- 7 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 compiler/testData/codegen/box/traits/interfaceWithNonAbstractFunIndirectGeneric.kt diff --git a/compiler/testData/codegen/box/traits/interfaceWithNonAbstractFunIndirect.kt b/compiler/testData/codegen/box/traits/interfaceWithNonAbstractFunIndirect.kt index 074f6d18a2f..e77b2472214 100644 --- a/compiler/testData/codegen/box/traits/interfaceWithNonAbstractFunIndirect.kt +++ b/compiler/testData/codegen/box/traits/interfaceWithNonAbstractFunIndirect.kt @@ -20,7 +20,7 @@ fun box(): String { if (bar1 != "bar:default") return "fail2: $bar1" val bar2 = A().bar("q") - if (bar2 != "bar:q") return "fail3: $bar1" + if (bar2 != "bar:q") return "fail3: $bar2" val foo2 = B().foo() if (foo2 != "foo") return "fail4: $foo2" diff --git a/compiler/testData/codegen/box/traits/interfaceWithNonAbstractFunIndirectGeneric.kt b/compiler/testData/codegen/box/traits/interfaceWithNonAbstractFunIndirectGeneric.kt new file mode 100644 index 00000000000..65f641c2d5a --- /dev/null +++ b/compiler/testData/codegen/box/traits/interfaceWithNonAbstractFunIndirectGeneric.kt @@ -0,0 +1,27 @@ +interface I { + fun foo(x: T): String = "foo($x)" + + fun bar(x: T, y: String = "default") = "bar($x,$y)" +} + +interface J : I + +class A : I, J + +class B : J, I + +fun box(): String { + val foo = A().foo("q") + if (foo != "foo(q)") return "fail1: $foo" + + val bar1 = A().bar("w") + if (bar1 != "bar(w,default)") return "fail2: $bar1" + + val bar2 = A().bar("e", "r") + if (bar2 != "bar(e,r)") return "fail3: $bar2" + + val foo2 = B().foo("t") + if (foo2 != "foo(t)") return "fail4: $foo2" + + return "OK" +} \ No newline at end of file diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index bb9cabbcdfc..ea6d4ee56ea 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -18056,6 +18056,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("interfaceWithNonAbstractFunIndirectGeneric.kt") + public void testInterfaceWithNonAbstractFunIndirectGeneric() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/traits/interfaceWithNonAbstractFunIndirectGeneric.kt"); + doTest(fileName); + } + @TestMetadata("kt1936.kt") public void testKt1936() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/traits/kt1936.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index a15852d3e06..657f7f7447e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -18056,6 +18056,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("interfaceWithNonAbstractFunIndirectGeneric.kt") + public void testInterfaceWithNonAbstractFunIndirectGeneric() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/traits/interfaceWithNonAbstractFunIndirectGeneric.kt"); + doTest(fileName); + } + @TestMetadata("kt1936.kt") public void testKt1936() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/traits/kt1936.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 6f43d1ea3ac..6c263635ada 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -18056,6 +18056,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes doTest(fileName); } + @TestMetadata("interfaceWithNonAbstractFunIndirectGeneric.kt") + public void testInterfaceWithNonAbstractFunIndirectGeneric() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/traits/interfaceWithNonAbstractFunIndirectGeneric.kt"); + doTest(fileName); + } + @TestMetadata("kt1936.kt") public void testKt1936() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/traits/kt1936.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 24d5e057ff7..7ee15168b74 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -22160,6 +22160,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } + @TestMetadata("interfaceWithNonAbstractFunIndirectGeneric.kt") + public void testInterfaceWithNonAbstractFunIndirectGeneric() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/traits/interfaceWithNonAbstractFunIndirectGeneric.kt"); + doTest(fileName); + } + @TestMetadata("kt1936.kt") public void testKt1936() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/traits/kt1936.kt"); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassModelGenerator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassModelGenerator.kt index 9aad236c5ea..80d4b70f83f 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassModelGenerator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassModelGenerator.kt @@ -156,7 +156,7 @@ class ClassModelGenerator(val context: StaticContext) { // If one of overridden members is non-abstract, copy it. // When none found, we have nothing to copy, ignore. // When multiple found, our current class should provide implementation, ignore. - val memberToCopy = member.findNonRepeatingOverriddenDescriptors { overriddenDescriptors } + val memberToCopy = member.findNonRepeatingOverriddenDescriptors({ overriddenDescriptors }, { original }) .filter { it.modality != Modality.ABSTRACT } .singleOrNull() ?: return null @@ -171,7 +171,7 @@ class ClassModelGenerator(val context: StaticContext) { // If one of overridden members has parameters with default value, copy it. // When non found, we have nothing to copy, ignore. // When multiple found, our current class should provide implementation, ignore. - val memberToCopy = member.findNonRepeatingOverriddenDescriptors { overriddenDescriptors } + val memberToCopy = member.findNonRepeatingOverriddenDescriptors({ overriddenDescriptors }, { original }) .filter { it.hasOrInheritsParametersWithDefaultValue() } .singleOrNull() ?: return null @@ -183,20 +183,22 @@ class ClassModelGenerator(val context: StaticContext) { } private fun T.findNonRepeatingOverriddenDescriptors( - getTypedOverriddenDescriptors: T.() -> Collection + getTypedOverriddenDescriptors: T.() -> Collection, + getOriginalDescriptor: T.() -> T ): List { val allDescriptors = mutableSetOf() val repeatedDescriptors = mutableSetOf() fun walk(descriptor: T) { - if (!allDescriptors.add(descriptor)) return - val overridden = descriptor.getTypedOverriddenDescriptors() + val original = descriptor.getOriginalDescriptor() + if (!allDescriptors.add(original)) return + val overridden = original.getTypedOverriddenDescriptors().map { it.getOriginalDescriptor() } repeatedDescriptors += overridden overridden.forEach { walk(it) } } val directOverriddenDescriptors = getTypedOverriddenDescriptors() directOverriddenDescriptors.forEach { walk(it) } - return directOverriddenDescriptors.filter { it !in repeatedDescriptors } + return directOverriddenDescriptors.filter { it.getOriginalDescriptor() !in repeatedDescriptors } } private fun generateBridgeMethods(descriptor: ClassDescriptor, model: JsClassModel) {