Fix copying of non-abstract functions of interfaces in JS BE
Fix copying of non-abstract functions of interfaces to implementing classes when implementing class inherits interface via 2+ paths. See KT-18187
This commit is contained in:
@@ -0,0 +1,29 @@
|
|||||||
|
interface I {
|
||||||
|
fun foo(): String = "foo"
|
||||||
|
|
||||||
|
fun bar(x: String = "default") = "bar:$x"
|
||||||
|
}
|
||||||
|
|
||||||
|
interface J : I
|
||||||
|
|
||||||
|
interface K : J
|
||||||
|
|
||||||
|
class A : I, J
|
||||||
|
|
||||||
|
class B : K, I
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val foo = A().foo()
|
||||||
|
if (foo != "foo") return "fail1: $foo"
|
||||||
|
|
||||||
|
val bar1 = A().bar()
|
||||||
|
if (bar1 != "bar:default") return "fail2: $bar1"
|
||||||
|
|
||||||
|
val bar2 = A().bar("q")
|
||||||
|
if (bar2 != "bar:q") return "fail3: $bar1"
|
||||||
|
|
||||||
|
val foo2 = B().foo()
|
||||||
|
if (foo2 != "foo") return "fail4: $foo2"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -1,6 +1,3 @@
|
|||||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
|
||||||
// IGNORE_BACKEND: JS
|
|
||||||
|
|
||||||
interface BK {
|
interface BK {
|
||||||
fun foo(): String = 10.toString()
|
fun foo(): String = 10.toString()
|
||||||
}
|
}
|
||||||
|
|||||||
+6
@@ -18044,6 +18044,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("interfaceWithNonAbstractFunIndirect.kt")
|
||||||
|
public void testInterfaceWithNonAbstractFunIndirect() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/traits/interfaceWithNonAbstractFunIndirect.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt1936.kt")
|
@TestMetadata("kt1936.kt")
|
||||||
public void testKt1936() throws Exception {
|
public void testKt1936() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/traits/kt1936.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/traits/kt1936.kt");
|
||||||
|
|||||||
@@ -18044,6 +18044,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("interfaceWithNonAbstractFunIndirect.kt")
|
||||||
|
public void testInterfaceWithNonAbstractFunIndirect() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/traits/interfaceWithNonAbstractFunIndirect.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt1936.kt")
|
@TestMetadata("kt1936.kt")
|
||||||
public void testKt1936() throws Exception {
|
public void testKt1936() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/traits/kt1936.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/traits/kt1936.kt");
|
||||||
|
|||||||
@@ -18044,6 +18044,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("interfaceWithNonAbstractFunIndirect.kt")
|
||||||
|
public void testInterfaceWithNonAbstractFunIndirect() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/traits/interfaceWithNonAbstractFunIndirect.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt1936.kt")
|
@TestMetadata("kt1936.kt")
|
||||||
public void testKt1936() throws Exception {
|
public void testKt1936() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/traits/kt1936.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/traits/kt1936.kt");
|
||||||
|
|||||||
+7
-7
@@ -22148,6 +22148,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("interfaceWithNonAbstractFunIndirect.kt")
|
||||||
|
public void testInterfaceWithNonAbstractFunIndirect() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/traits/interfaceWithNonAbstractFunIndirect.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt1936.kt")
|
@TestMetadata("kt1936.kt")
|
||||||
public void testKt1936() throws Exception {
|
public void testKt1936() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/traits/kt1936.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/traits/kt1936.kt");
|
||||||
@@ -22193,13 +22199,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
@TestMetadata("kt3500.kt")
|
@TestMetadata("kt3500.kt")
|
||||||
public void testKt3500() throws Exception {
|
public void testKt3500() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/traits/kt3500.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/traits/kt3500.kt");
|
||||||
try {
|
doTest(fileName);
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
catch (Throwable ignore) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("kt3579.kt")
|
@TestMetadata("kt3579.kt")
|
||||||
|
|||||||
+19
-2
@@ -156,7 +156,7 @@ class ClassModelGenerator(val context: StaticContext) {
|
|||||||
// If one of overridden members is non-abstract, copy it.
|
// If one of overridden members is non-abstract, copy it.
|
||||||
// When none found, we have nothing to copy, ignore.
|
// When none found, we have nothing to copy, ignore.
|
||||||
// When multiple found, our current class should provide implementation, ignore.
|
// When multiple found, our current class should provide implementation, ignore.
|
||||||
val memberToCopy = member.overriddenDescriptors
|
val memberToCopy = member.findNonRepeatingOverriddenDescriptors { overriddenDescriptors }
|
||||||
.filter { it.modality != Modality.ABSTRACT }
|
.filter { it.modality != Modality.ABSTRACT }
|
||||||
.singleOrNull() ?: return null
|
.singleOrNull() ?: return null
|
||||||
|
|
||||||
@@ -171,7 +171,7 @@ class ClassModelGenerator(val context: StaticContext) {
|
|||||||
// If one of overridden members has parameters with default value, copy it.
|
// If one of overridden members has parameters with default value, copy it.
|
||||||
// When non found, we have nothing to copy, ignore.
|
// When non found, we have nothing to copy, ignore.
|
||||||
// When multiple found, our current class should provide implementation, ignore.
|
// When multiple found, our current class should provide implementation, ignore.
|
||||||
val memberToCopy = member.overriddenDescriptors
|
val memberToCopy = member.findNonRepeatingOverriddenDescriptors { overriddenDescriptors }
|
||||||
.filter { it.hasOrInheritsParametersWithDefaultValue() }
|
.filter { it.hasOrInheritsParametersWithDefaultValue() }
|
||||||
.singleOrNull() ?: return null
|
.singleOrNull() ?: return null
|
||||||
|
|
||||||
@@ -182,6 +182,23 @@ class ClassModelGenerator(val context: StaticContext) {
|
|||||||
return if (!memberToCopy.kind.isReal) findOptionalArgsMemberToCopy(memberToCopy) else memberToCopy
|
return if (!memberToCopy.kind.isReal) findOptionalArgsMemberToCopy(memberToCopy) else memberToCopy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun <T : CallableMemberDescriptor> T.findNonRepeatingOverriddenDescriptors(
|
||||||
|
getTypedOverriddenDescriptors: T.() -> Collection<T>
|
||||||
|
): List<T> {
|
||||||
|
val allDescriptors = mutableSetOf<T>()
|
||||||
|
val repeatedDescriptors = mutableSetOf<T>()
|
||||||
|
fun walk(descriptor: T) {
|
||||||
|
if (!allDescriptors.add(descriptor)) return
|
||||||
|
val overridden = descriptor.getTypedOverriddenDescriptors()
|
||||||
|
repeatedDescriptors += overridden
|
||||||
|
overridden.forEach { walk(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
val directOverriddenDescriptors = getTypedOverriddenDescriptors()
|
||||||
|
directOverriddenDescriptors.forEach { walk(it) }
|
||||||
|
return directOverriddenDescriptors.filter { it !in repeatedDescriptors }
|
||||||
|
}
|
||||||
|
|
||||||
private fun generateBridgeMethods(descriptor: ClassDescriptor, model: JsClassModel) {
|
private fun generateBridgeMethods(descriptor: ClassDescriptor, model: JsClassModel) {
|
||||||
generateBridgesToTraitImpl(descriptor, model)
|
generateBridgesToTraitImpl(descriptor, model)
|
||||||
generateOtherBridges(descriptor, model)
|
generateOtherBridges(descriptor, model)
|
||||||
|
|||||||
Reference in New Issue
Block a user