From bb59638039ce0426151cf0f4fa1ef911116fcedb Mon Sep 17 00:00:00 2001 From: Mikhael Bogdanov Date: Thu, 19 May 2016 15:55:18 +0300 Subject: [PATCH] Support bridges in interfaces. Fix for KT-12416: Missed bridges in js backend #KT-12416 Fixed --- .../kotlin/backend/common/bridges/bridges.kt | 2 +- .../kotlin/backend/common/bridges/impl.kt | 31 +++++++++++--- .../kotlin/codegen/FunctionCodegen.java | 24 +++++++++-- .../kotlin/codegen/builtinSpecialBridges.kt | 29 ++++++++----- .../testData/codegen/box/bridges/kt12416.kt | 41 +++++++++++++++++++ ...oParentsWithDifferentMethodsTwoBridges2.kt | 40 ++++++++++++++++++ .../codegen/java8/box/jvm8/bridgeInClass.kt | 21 ++++++++++ .../java8/box/jvm8/bridgeInInterface.kt | 24 +++++++++++ ...BlackBoxWithJava8CodegenTestGenerated.java | 12 ++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 12 ++++++ .../test/semantics/BridgeTestGenerated.java | 12 ++++++ .../translate/declaration/ClassTranslator.kt | 9 +++- 12 files changed, 235 insertions(+), 22 deletions(-) create mode 100644 compiler/testData/codegen/box/bridges/kt12416.kt create mode 100644 compiler/testData/codegen/box/bridges/twoParentsWithDifferentMethodsTwoBridges2.kt create mode 100644 compiler/testData/codegen/java8/box/jvm8/bridgeInClass.kt create mode 100644 compiler/testData/codegen/java8/box/jvm8/bridgeInInterface.kt diff --git a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/bridges/bridges.kt b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/bridges/bridges.kt index 4de90a130fd..e2a5a0b0962 100644 --- a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/bridges/bridges.kt +++ b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/bridges/bridges.kt @@ -17,7 +17,7 @@ package org.jetbrains.kotlin.backend.common.bridges import org.jetbrains.kotlin.utils.DFS -import java.util.HashSet +import java.util.* interface FunctionHandle { val isDeclaration: Boolean diff --git a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/bridges/impl.kt b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/bridges/impl.kt index e8631bd8877..1a6146e63ea 100644 --- a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/bridges/impl.kt +++ b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/bridges/impl.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.backend.common.bridges import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.resolve.DescriptorUtils @@ -25,9 +26,10 @@ import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isOrOverridesSynthesi fun generateBridgesForFunctionDescriptor( descriptor: FunctionDescriptor, - signature: (FunctionDescriptor) -> Signature + signature: (FunctionDescriptor) -> Signature, + isBodyOwner: (DeclarationDescriptor) -> Boolean ): Set> { - return generateBridges(DescriptorBasedFunctionHandle(descriptor), { signature(it.descriptor) }) + return generateBridges(DescriptorBasedFunctionHandle(descriptor, isBodyOwner), { signature(it.descriptor) }) } /** @@ -47,8 +49,19 @@ fun generateBridgesForFunctionDescriptor( * can generate a bridge near an implementation (of course, in case it has a super-declaration with a different signature). Ultimately this * eases the process of determining what bridges are already generated in our supertypes and need to be inherited, not regenerated. */ -data class DescriptorBasedFunctionHandle(val descriptor: FunctionDescriptor) : FunctionHandle { - private val overridden = descriptor.overriddenDescriptors.map { DescriptorBasedFunctionHandle(it.original) } +class DescriptorBasedFunctionHandle( + val descriptor: FunctionDescriptor, + /* + To generate proper bridges for non-abstract function + we should know if the function declaration and its definition in the target platform are the same or not. + For JS and JVM8 they are placed in interface classes and we need generate bridge for such function ('isAbstract' will return false). + For JVM6 target function body generated in separate place (DefaultImpl) and method in interface is abstract + For JVM6 target function body is generated in a separate place (DefaultImpls) and + the method in the interface is abstract so we must not generate bridges for such cases. + */ + isBodyOwner: (DeclarationDescriptor) -> Boolean +) : FunctionHandle { + private val overridden = descriptor.overriddenDescriptors.map { DescriptorBasedFunctionHandle(it.original, isBodyOwner) } override val isDeclaration: Boolean = descriptor.kind.isReal || @@ -56,9 +69,17 @@ data class DescriptorBasedFunctionHandle(val descriptor: FunctionDescriptor) : F override val isAbstract: Boolean = descriptor.modality == Modality.ABSTRACT || - DescriptorUtils.isInterface(descriptor.containingDeclaration) + isBodyOwner(descriptor.containingDeclaration) override fun getOverridden() = overridden + + override fun hashCode(): Int { + return descriptor.hashCode() + } + + override fun equals(other: Any?): Boolean { + return other is DescriptorBasedFunctionHandle && descriptor == other.descriptor + } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index d06a75c199f..85dfb71ec8a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -77,6 +77,8 @@ import java.util.Set; import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isNullableAny; import static org.jetbrains.kotlin.codegen.AsmUtil.*; +import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isAnnotationOrJvm6Interface; +import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvm8InterfaceMember; import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.METHOD_FOR_FUNCTION; import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DECLARATION; import static org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.*; @@ -95,6 +97,13 @@ public class FunctionCodegen { private final ClassBuilder v; private final MemberCodegen memberCodegen; + private final Function1 IS_PURE_INTERFACE_CHECKER = new Function1() { + @Override + public Boolean invoke(DeclarationDescriptor descriptor) { + return JvmCodegenUtil.isAnnotationOrJvm6Interface(descriptor, state); + } + }; + public FunctionCodegen( @NotNull CodegenContext owner, @NotNull ClassBuilder v, @@ -565,7 +574,7 @@ public class FunctionCodegen { public void generateBridges(@NotNull FunctionDescriptor descriptor) { if (descriptor instanceof ConstructorDescriptor) return; if (owner.getContextKind() == OwnerKind.DEFAULT_IMPLS) return; - if (isInterface(descriptor.getContainingDeclaration())) return; + if (isAnnotationOrJvm6Interface(descriptor.getContainingDeclaration(), state)) return; // equals(Any?), hashCode(), toString() never need bridges if (isMethodOfAny(descriptor)) return; @@ -579,7 +588,8 @@ public class FunctionCodegen { if (!isSpecial) { bridgesToGenerate = ImplKt.generateBridgesForFunctionDescriptor( descriptor, - getSignatureMapper(typeMapper) + getSignatureMapper(typeMapper), + IS_PURE_INTERFACE_CHECKER ); if (!bridgesToGenerate.isEmpty()) { PsiElement origin = descriptor.getKind() == DECLARATION ? getSourceFromDescriptor(descriptor) : null; @@ -594,7 +604,8 @@ public class FunctionCodegen { else { Set> specials = BuiltinSpecialBridgesUtil.generateBridgesForBuiltinSpecial( descriptor, - getSignatureMapper(typeMapper) + getSignatureMapper(typeMapper), + IS_PURE_INTERFACE_CHECKER ); if (!specials.isEmpty()) { @@ -914,7 +925,12 @@ public class FunctionCodegen { iv.invokespecial(parentInternalName, delegateTo.getName(), delegateTo.getDescriptor()); } else { - iv.invokevirtual(v.getThisName(), delegateTo.getName(), delegateTo.getDescriptor()); + if (isJvm8InterfaceMember(descriptor, state)) { + iv.invokeinterface(v.getThisName(), delegateTo.getName(), delegateTo.getDescriptor()); + } + else { + iv.invokevirtual(v.getThisName(), delegateTo.getName(), delegateTo.getDescriptor()); + } } StackValue.coerce(delegateTo.getReturnType(), bridge.getReturnType(), iv); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/builtinSpecialBridges.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/builtinSpecialBridges.kt index 5f47fa5f6d4..10918edcb00 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/builtinSpecialBridges.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/builtinSpecialBridges.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.backend.common.bridges.DescriptorBasedFunctionHandle import org.jetbrains.kotlin.backend.common.bridges.findAllReachableDeclarations import org.jetbrains.kotlin.backend.common.bridges.findConcreteSuperDeclaration import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature @@ -46,14 +47,15 @@ class BridgeForBuiltinSpecial( object BuiltinSpecialBridgesUtil { @JvmStatic fun generateBridgesForBuiltinSpecial( function: FunctionDescriptor, - signatureByDescriptor: (FunctionDescriptor) -> Signature + signatureByDescriptor: (FunctionDescriptor) -> Signature, + isBodyOwner: (DeclarationDescriptor) -> Boolean ): Set> { - val functionHandle = DescriptorBasedFunctionHandle(function) + val functionHandle = DescriptorBasedFunctionHandle(function, isBodyOwner) val fake = !functionHandle.isDeclaration val overriddenBuiltin = function.getOverriddenBuiltinReflectingJvmDescriptor()!! - val reachableDeclarations = findAllReachableDeclarations(function) + val reachableDeclarations = findAllReachableDeclarations(function, isBodyOwner) // e.g. `getSize()I` val methodItself = signatureByDescriptor(function) @@ -79,8 +81,8 @@ object BuiltinSpecialBridgesUtil { if (fake) { for (overridden in function.overriddenDescriptors.map { it.original }) { - if (!DescriptorBasedFunctionHandle(overridden).isAbstract) { - commonBridges.removeAll(findAllReachableDeclarations(overridden).map(signatureByDescriptor)) + if (!DescriptorBasedFunctionHandle(overridden, isBodyOwner).isAbstract) { + commonBridges.removeAll(findAllReachableDeclarations(overridden, isBodyOwner).map(signatureByDescriptor)) } } } @@ -89,7 +91,7 @@ object BuiltinSpecialBridgesUtil { // Can be null if special builtin is final (e.g. 'name' in Enum) // because there should be no stubs for override in subclasses - val superImplementationDescriptor = findSuperImplementationForStubDelegation(function, fake) + val superImplementationDescriptor = findSuperImplementationForStubDelegation(function, fake, isBodyOwner) if (superImplementationDescriptor != null) { bridges.add(BridgeForBuiltinSpecial(methodItself, signatureByDescriptor(superImplementationDescriptor), isDelegateToSuper = true)) } @@ -121,16 +123,23 @@ object BuiltinSpecialBridgesUtil { } -private fun findSuperImplementationForStubDelegation(function: FunctionDescriptor, fake: Boolean): FunctionDescriptor? { +private fun findSuperImplementationForStubDelegation( + function: FunctionDescriptor, + fake: Boolean, + isBodyOwner: (DeclarationDescriptor) -> Boolean +): FunctionDescriptor? { if (function.modality != Modality.OPEN || !fake) return null - val implementation = findConcreteSuperDeclaration(DescriptorBasedFunctionHandle(function)).descriptor + val implementation = findConcreteSuperDeclaration(DescriptorBasedFunctionHandle(function, isBodyOwner)).descriptor if (DescriptorUtils.isInterface(implementation.containingDeclaration)) return null return implementation } -private fun findAllReachableDeclarations(functionDescriptor: FunctionDescriptor): MutableSet = - findAllReachableDeclarations(DescriptorBasedFunctionHandle(functionDescriptor)).map { it.descriptor }.toMutableSet() +private fun findAllReachableDeclarations( + functionDescriptor: FunctionDescriptor, + isBodyOwner: (DeclarationDescriptor) -> Boolean +): MutableSet = + findAllReachableDeclarations(DescriptorBasedFunctionHandle(functionDescriptor, isBodyOwner)).map { it.descriptor }.toMutableSet() private fun CallableMemberDescriptor.getSpecialBridgeSignatureIfExists( signatureByDescriptor: (FunctionDescriptor) -> Signature diff --git a/compiler/testData/codegen/box/bridges/kt12416.kt b/compiler/testData/codegen/box/bridges/kt12416.kt new file mode 100644 index 00000000000..c50c81671f5 --- /dev/null +++ b/compiler/testData/codegen/box/bridges/kt12416.kt @@ -0,0 +1,41 @@ +interface A { + fun foo(t: T, u: Int) = "A" +} + +interface B { + fun foo(t: T, u: U) = "B" +} + +interface Z1 : A, B { + override fun foo(t: String, u: Int) = "Z1" +} + +interface Z2 : B, A { + override fun foo(t: String, u: Int) = "Z2" +} + +class Z1C : Z1 { + +} + +class Z2C : Z2 { + +} + +fun box(): String { + val z1 = Z1C() + val z2 = Z2C() + val z1a: A = z1 + val z1b: B = z1 + val z2a: A = z2 + val z2b: B = z2 + return when { + z1.foo("", 0) != "Z1" -> "Fail #1" + z1a.foo("", 0) != "Z1" -> "Fail #2" + z1b.foo("", 0) != "Z1" -> "Fail #3" //FAIL + z2.foo("", 0) != "Z2" -> "Fail #4" + z2a.foo("", 0) != "Z2" -> "Fail #5" + z2b.foo("", 0) != "Z2" -> "Fail #6" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/box/bridges/twoParentsWithDifferentMethodsTwoBridges2.kt b/compiler/testData/codegen/box/bridges/twoParentsWithDifferentMethodsTwoBridges2.kt new file mode 100644 index 00000000000..07af5afaa4e --- /dev/null +++ b/compiler/testData/codegen/box/bridges/twoParentsWithDifferentMethodsTwoBridges2.kt @@ -0,0 +1,40 @@ +interface A { + fun foo(t: T, u: Int) = "A" +} + +interface B { + fun foo(t: T, u: U) = "B" +} + +interface Z1 : A, B { + override fun foo(t: String, u: Int) = "Z1" +} + +interface Z2 : B, A { + override fun foo(t: String, u: Int) = "Z2" +} + + +class Z1Class : Z1 { +} + +class Z2Class : Z2 { +} + +fun box(): String { + val z1 = Z1Class() + val z2 = Z2Class() + val z1a: A = z1 + val z1b: B = z1 + val z2a: A = z2 + val z2b: B = z2 + return when { + z1.foo("", 0) != "Z1" -> "Fail #1" + z1a.foo("", 0) != "Z1" -> "Fail #2" + z1b.foo("", 0) != "Z1" -> "Fail #3" //FAIL + z2.foo("", 0) != "Z2" -> "Fail #4" + z2a.foo("", 0) != "Z2" -> "Fail #5" + z2b.foo("", 0) != "Z2" -> "Fail #6" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/java8/box/jvm8/bridgeInClass.kt b/compiler/testData/codegen/java8/box/jvm8/bridgeInClass.kt new file mode 100644 index 00000000000..d2ffd39954d --- /dev/null +++ b/compiler/testData/codegen/java8/box/jvm8/bridgeInClass.kt @@ -0,0 +1,21 @@ +// KOTLIN_CONFIGURATION_FLAGS: +JVM.JVM_8_TARGET +interface Test { + fun test(p: T): T { + return p + } +} + +class TestClass : Test { + override fun test(p: String): String { + return p + "K" + } +} + +fun execute(t: Test, p: T): T { + return t.test(p) +} + +fun box(): String { + return execute(TestClass(), "O") +} + diff --git a/compiler/testData/codegen/java8/box/jvm8/bridgeInInterface.kt b/compiler/testData/codegen/java8/box/jvm8/bridgeInInterface.kt new file mode 100644 index 00000000000..2ef13a418a7 --- /dev/null +++ b/compiler/testData/codegen/java8/box/jvm8/bridgeInInterface.kt @@ -0,0 +1,24 @@ +// KOTLIN_CONFIGURATION_FLAGS: +JVM.JVM_8_TARGET +interface Test { + fun test(p: T): T { + return p + } +} + +interface Test2: Test { + override fun test(p: String): String { + return p + "K" + } +} + +class TestClass : Test2 { +} + +fun execute(t: Test, p: T): T { + return t.test(p) +} + +fun box(): String { + return execute(TestClass(), "O") +} + diff --git a/compiler/tests-java8/tests/org/jetbrains/kotlin/codegen/BlackBoxWithJava8CodegenTestGenerated.java b/compiler/tests-java8/tests/org/jetbrains/kotlin/codegen/BlackBoxWithJava8CodegenTestGenerated.java index fe45c0996d5..0cb18377821 100644 --- a/compiler/tests-java8/tests/org/jetbrains/kotlin/codegen/BlackBoxWithJava8CodegenTestGenerated.java +++ b/compiler/tests-java8/tests/org/jetbrains/kotlin/codegen/BlackBoxWithJava8CodegenTestGenerated.java @@ -127,6 +127,18 @@ public class BlackBoxWithJava8CodegenTestGenerated extends AbstractBlackBoxCodeg KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/java8/box/jvm8"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("bridgeInClass.kt") + public void testBridgeInClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/box/jvm8/bridgeInClass.kt"); + doTest(fileName); + } + + @TestMetadata("bridgeInInterface.kt") + public void testBridgeInInterface() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/box/jvm8/bridgeInInterface.kt"); + doTest(fileName); + } + @TestMetadata("simpleCall.kt") public void testSimpleCall() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/box/jvm8/simpleCall.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index c1a2fd12b9d..6b501f86ce4 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -994,6 +994,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("kt12416.kt") + public void testKt12416() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/bridges/kt12416.kt"); + doTest(fileName); + } + @TestMetadata("kt1939.kt") public void testKt1939() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/bridges/kt1939.kt"); @@ -1162,6 +1168,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("twoParentsWithDifferentMethodsTwoBridges2.kt") + public void testTwoParentsWithDifferentMethodsTwoBridges2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/bridges/twoParentsWithDifferentMethodsTwoBridges2.kt"); + doTest(fileName); + } + @TestMetadata("twoParentsWithTheSameMethodOneBridge.kt") public void testTwoParentsWithTheSameMethodOneBridge() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/bridges/twoParentsWithTheSameMethodOneBridge.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BridgeTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BridgeTestGenerated.java index faa21246424..894f438a921 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BridgeTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BridgeTestGenerated.java @@ -125,6 +125,12 @@ public class BridgeTestGenerated extends AbstractBridgeTest { doTest(fileName); } + @TestMetadata("kt12416.kt") + public void testKt12416() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/bridges/kt12416.kt"); + doTest(fileName); + } + @TestMetadata("kt1939.kt") public void testKt1939() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/bridges/kt1939.kt"); @@ -287,6 +293,12 @@ public class BridgeTestGenerated extends AbstractBridgeTest { doTest(fileName); } + @TestMetadata("twoParentsWithDifferentMethodsTwoBridges2.kt") + public void testTwoParentsWithDifferentMethodsTwoBridges2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/bridges/twoParentsWithDifferentMethodsTwoBridges2.kt"); + doTest(fileName); + } + @TestMetadata("twoParentsWithTheSameMethodOneBridge.kt") public void testTwoParentsWithTheSameMethodOneBridge() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/bridges/twoParentsWithTheSameMethodOneBridge.kt"); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt index 2c8394d058d..57156bfa0b1 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt @@ -77,6 +77,8 @@ class ClassTranslator private constructor( private fun isTrait(): Boolean = descriptor.kind == ClassKind.INTERFACE + private fun isAnnotation(): Boolean = descriptor.kind == ClassKind.ANNOTATION_CLASS + private fun generateClassCreateInvocationArguments() { val properties = SmartList() val staticProperties = SmartList() @@ -369,7 +371,7 @@ class ClassTranslator private constructor( } private fun generatedBridgeMethods(properties: MutableList) { - if (isTrait()) return + if (isAnnotation()) return generateBridgesToTraitImpl(properties) @@ -387,7 +389,10 @@ class ClassTranslator private constructor( private fun generateOtherBridges(properties: MutableList) { for (memberDescriptor in descriptor.defaultType.memberScope.getContributedDescriptors()) { if (memberDescriptor is FunctionDescriptor) { - val bridgesToGenerate = generateBridgesForFunctionDescriptor(memberDescriptor, identity()) + val bridgesToGenerate = generateBridgesForFunctionDescriptor(memberDescriptor, identity()) { + //There is no DefaultImpls in js backend so if method non-abstract it should be recognized as non-abstract on bridges calculation + false + } for (bridge in bridgesToGenerate) { generateBridge(bridge, properties)