Support bridges in interfaces. Fix for KT-12416: Missed bridges in js backend
#KT-12416 Fixed
This commit is contained in:
@@ -17,7 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.backend.common.bridges
|
package org.jetbrains.kotlin.backend.common.bridges
|
||||||
|
|
||||||
import org.jetbrains.kotlin.utils.DFS
|
import org.jetbrains.kotlin.utils.DFS
|
||||||
import java.util.HashSet
|
import java.util.*
|
||||||
|
|
||||||
interface FunctionHandle {
|
interface FunctionHandle {
|
||||||
val isDeclaration: Boolean
|
val isDeclaration: Boolean
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.backend.common.bridges
|
package org.jetbrains.kotlin.backend.common.bridges
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
@@ -25,9 +26,10 @@ import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isOrOverridesSynthesi
|
|||||||
|
|
||||||
fun <Signature> generateBridgesForFunctionDescriptor(
|
fun <Signature> generateBridgesForFunctionDescriptor(
|
||||||
descriptor: FunctionDescriptor,
|
descriptor: FunctionDescriptor,
|
||||||
signature: (FunctionDescriptor) -> Signature
|
signature: (FunctionDescriptor) -> Signature,
|
||||||
|
isBodyOwner: (DeclarationDescriptor) -> Boolean
|
||||||
): Set<Bridge<Signature>> {
|
): Set<Bridge<Signature>> {
|
||||||
return generateBridges(DescriptorBasedFunctionHandle(descriptor), { signature(it.descriptor) })
|
return generateBridges(DescriptorBasedFunctionHandle(descriptor, isBodyOwner), { signature(it.descriptor) })
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,8 +49,19 @@ fun <Signature> generateBridgesForFunctionDescriptor(
|
|||||||
* can generate a bridge near an implementation (of course, in case it has a super-declaration with a different signature). Ultimately this
|
* 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.
|
* 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 {
|
class DescriptorBasedFunctionHandle(
|
||||||
private val overridden = descriptor.overriddenDescriptors.map { DescriptorBasedFunctionHandle(it.original) }
|
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 =
|
override val isDeclaration: Boolean =
|
||||||
descriptor.kind.isReal ||
|
descriptor.kind.isReal ||
|
||||||
@@ -56,9 +69,17 @@ data class DescriptorBasedFunctionHandle(val descriptor: FunctionDescriptor) : F
|
|||||||
|
|
||||||
override val isAbstract: Boolean =
|
override val isAbstract: Boolean =
|
||||||
descriptor.modality == Modality.ABSTRACT ||
|
descriptor.modality == Modality.ABSTRACT ||
|
||||||
DescriptorUtils.isInterface(descriptor.containingDeclaration)
|
isBodyOwner(descriptor.containingDeclaration)
|
||||||
|
|
||||||
override fun getOverridden() = overridden
|
override fun getOverridden() = overridden
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return descriptor.hashCode()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
return other is DescriptorBasedFunctionHandle && descriptor == other.descriptor
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -77,6 +77,8 @@ import java.util.Set;
|
|||||||
|
|
||||||
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isNullableAny;
|
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isNullableAny;
|
||||||
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
|
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.codegen.serialization.JvmSerializationBindings.METHOD_FOR_FUNCTION;
|
||||||
import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DECLARATION;
|
import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DECLARATION;
|
||||||
import static org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.*;
|
import static org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.*;
|
||||||
@@ -95,6 +97,13 @@ public class FunctionCodegen {
|
|||||||
private final ClassBuilder v;
|
private final ClassBuilder v;
|
||||||
private final MemberCodegen<?> memberCodegen;
|
private final MemberCodegen<?> memberCodegen;
|
||||||
|
|
||||||
|
private final Function1<DeclarationDescriptor, Boolean> IS_PURE_INTERFACE_CHECKER = new Function1<DeclarationDescriptor, Boolean>() {
|
||||||
|
@Override
|
||||||
|
public Boolean invoke(DeclarationDescriptor descriptor) {
|
||||||
|
return JvmCodegenUtil.isAnnotationOrJvm6Interface(descriptor, state);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public FunctionCodegen(
|
public FunctionCodegen(
|
||||||
@NotNull CodegenContext owner,
|
@NotNull CodegenContext owner,
|
||||||
@NotNull ClassBuilder v,
|
@NotNull ClassBuilder v,
|
||||||
@@ -565,7 +574,7 @@ public class FunctionCodegen {
|
|||||||
public void generateBridges(@NotNull FunctionDescriptor descriptor) {
|
public void generateBridges(@NotNull FunctionDescriptor descriptor) {
|
||||||
if (descriptor instanceof ConstructorDescriptor) return;
|
if (descriptor instanceof ConstructorDescriptor) return;
|
||||||
if (owner.getContextKind() == OwnerKind.DEFAULT_IMPLS) 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
|
// equals(Any?), hashCode(), toString() never need bridges
|
||||||
if (isMethodOfAny(descriptor)) return;
|
if (isMethodOfAny(descriptor)) return;
|
||||||
@@ -579,7 +588,8 @@ public class FunctionCodegen {
|
|||||||
if (!isSpecial) {
|
if (!isSpecial) {
|
||||||
bridgesToGenerate = ImplKt.generateBridgesForFunctionDescriptor(
|
bridgesToGenerate = ImplKt.generateBridgesForFunctionDescriptor(
|
||||||
descriptor,
|
descriptor,
|
||||||
getSignatureMapper(typeMapper)
|
getSignatureMapper(typeMapper),
|
||||||
|
IS_PURE_INTERFACE_CHECKER
|
||||||
);
|
);
|
||||||
if (!bridgesToGenerate.isEmpty()) {
|
if (!bridgesToGenerate.isEmpty()) {
|
||||||
PsiElement origin = descriptor.getKind() == DECLARATION ? getSourceFromDescriptor(descriptor) : null;
|
PsiElement origin = descriptor.getKind() == DECLARATION ? getSourceFromDescriptor(descriptor) : null;
|
||||||
@@ -594,7 +604,8 @@ public class FunctionCodegen {
|
|||||||
else {
|
else {
|
||||||
Set<BridgeForBuiltinSpecial<Method>> specials = BuiltinSpecialBridgesUtil.generateBridgesForBuiltinSpecial(
|
Set<BridgeForBuiltinSpecial<Method>> specials = BuiltinSpecialBridgesUtil.generateBridgesForBuiltinSpecial(
|
||||||
descriptor,
|
descriptor,
|
||||||
getSignatureMapper(typeMapper)
|
getSignatureMapper(typeMapper),
|
||||||
|
IS_PURE_INTERFACE_CHECKER
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!specials.isEmpty()) {
|
if (!specials.isEmpty()) {
|
||||||
@@ -914,7 +925,12 @@ public class FunctionCodegen {
|
|||||||
iv.invokespecial(parentInternalName, delegateTo.getName(), delegateTo.getDescriptor());
|
iv.invokespecial(parentInternalName, delegateTo.getName(), delegateTo.getDescriptor());
|
||||||
}
|
}
|
||||||
else {
|
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);
|
StackValue.coerce(delegateTo.getReturnType(), bridge.getReturnType(), iv);
|
||||||
|
|||||||
@@ -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.findAllReachableDeclarations
|
||||||
import org.jetbrains.kotlin.backend.common.bridges.findConcreteSuperDeclaration
|
import org.jetbrains.kotlin.backend.common.bridges.findConcreteSuperDeclaration
|
||||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
|
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
|
||||||
@@ -46,14 +47,15 @@ class BridgeForBuiltinSpecial<out Signature : Any>(
|
|||||||
object BuiltinSpecialBridgesUtil {
|
object BuiltinSpecialBridgesUtil {
|
||||||
@JvmStatic fun <Signature : Any> generateBridgesForBuiltinSpecial(
|
@JvmStatic fun <Signature : Any> generateBridgesForBuiltinSpecial(
|
||||||
function: FunctionDescriptor,
|
function: FunctionDescriptor,
|
||||||
signatureByDescriptor: (FunctionDescriptor) -> Signature
|
signatureByDescriptor: (FunctionDescriptor) -> Signature,
|
||||||
|
isBodyOwner: (DeclarationDescriptor) -> Boolean
|
||||||
): Set<BridgeForBuiltinSpecial<Signature>> {
|
): Set<BridgeForBuiltinSpecial<Signature>> {
|
||||||
|
|
||||||
val functionHandle = DescriptorBasedFunctionHandle(function)
|
val functionHandle = DescriptorBasedFunctionHandle(function, isBodyOwner)
|
||||||
val fake = !functionHandle.isDeclaration
|
val fake = !functionHandle.isDeclaration
|
||||||
val overriddenBuiltin = function.getOverriddenBuiltinReflectingJvmDescriptor()!!
|
val overriddenBuiltin = function.getOverriddenBuiltinReflectingJvmDescriptor()!!
|
||||||
|
|
||||||
val reachableDeclarations = findAllReachableDeclarations(function)
|
val reachableDeclarations = findAllReachableDeclarations(function, isBodyOwner)
|
||||||
|
|
||||||
// e.g. `getSize()I`
|
// e.g. `getSize()I`
|
||||||
val methodItself = signatureByDescriptor(function)
|
val methodItself = signatureByDescriptor(function)
|
||||||
@@ -79,8 +81,8 @@ object BuiltinSpecialBridgesUtil {
|
|||||||
|
|
||||||
if (fake) {
|
if (fake) {
|
||||||
for (overridden in function.overriddenDescriptors.map { it.original }) {
|
for (overridden in function.overriddenDescriptors.map { it.original }) {
|
||||||
if (!DescriptorBasedFunctionHandle(overridden).isAbstract) {
|
if (!DescriptorBasedFunctionHandle(overridden, isBodyOwner).isAbstract) {
|
||||||
commonBridges.removeAll(findAllReachableDeclarations(overridden).map(signatureByDescriptor))
|
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)
|
// Can be null if special builtin is final (e.g. 'name' in Enum)
|
||||||
// because there should be no stubs for override in subclasses
|
// because there should be no stubs for override in subclasses
|
||||||
val superImplementationDescriptor = findSuperImplementationForStubDelegation(function, fake)
|
val superImplementationDescriptor = findSuperImplementationForStubDelegation(function, fake, isBodyOwner)
|
||||||
if (superImplementationDescriptor != null) {
|
if (superImplementationDescriptor != null) {
|
||||||
bridges.add(BridgeForBuiltinSpecial(methodItself, signatureByDescriptor(superImplementationDescriptor), isDelegateToSuper = true))
|
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
|
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
|
if (DescriptorUtils.isInterface(implementation.containingDeclaration)) return null
|
||||||
|
|
||||||
return implementation
|
return implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findAllReachableDeclarations(functionDescriptor: FunctionDescriptor): MutableSet<FunctionDescriptor> =
|
private fun findAllReachableDeclarations(
|
||||||
findAllReachableDeclarations(DescriptorBasedFunctionHandle(functionDescriptor)).map { it.descriptor }.toMutableSet()
|
functionDescriptor: FunctionDescriptor,
|
||||||
|
isBodyOwner: (DeclarationDescriptor) -> Boolean
|
||||||
|
): MutableSet<FunctionDescriptor> =
|
||||||
|
findAllReachableDeclarations(DescriptorBasedFunctionHandle(functionDescriptor, isBodyOwner)).map { it.descriptor }.toMutableSet()
|
||||||
|
|
||||||
private fun <Signature> CallableMemberDescriptor.getSpecialBridgeSignatureIfExists(
|
private fun <Signature> CallableMemberDescriptor.getSpecialBridgeSignatureIfExists(
|
||||||
signatureByDescriptor: (FunctionDescriptor) -> Signature
|
signatureByDescriptor: (FunctionDescriptor) -> Signature
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
interface A<T> {
|
||||||
|
fun foo(t: T, u: Int) = "A"
|
||||||
|
}
|
||||||
|
|
||||||
|
interface B<T, U> {
|
||||||
|
fun foo(t: T, u: U) = "B"
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Z1 : A<String>, B<String, Int> {
|
||||||
|
override fun foo(t: String, u: Int) = "Z1"
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Z2 : B<String, Int>, A<String> {
|
||||||
|
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<String> = z1
|
||||||
|
val z1b: B<String, Int> = z1
|
||||||
|
val z2a: A<String> = z2
|
||||||
|
val z2b: B<String, Int> = 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
interface A<T> {
|
||||||
|
fun foo(t: T, u: Int) = "A"
|
||||||
|
}
|
||||||
|
|
||||||
|
interface B<T, U> {
|
||||||
|
fun foo(t: T, u: U) = "B"
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Z1 : A<String>, B<String, Int> {
|
||||||
|
override fun foo(t: String, u: Int) = "Z1"
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Z2 : B<String, Int>, A<String> {
|
||||||
|
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<String> = z1
|
||||||
|
val z1b: B<String, Int> = z1
|
||||||
|
val z2a: A<String> = z2
|
||||||
|
val z2b: B<String, Int> = 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// KOTLIN_CONFIGURATION_FLAGS: +JVM.JVM_8_TARGET
|
||||||
|
interface Test<T> {
|
||||||
|
fun test(p: T): T {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestClass : Test<String> {
|
||||||
|
override fun test(p: String): String {
|
||||||
|
return p + "K"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> execute(t: Test<T>, p: T): T {
|
||||||
|
return t.test(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
return execute(TestClass(), "O")
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
// KOTLIN_CONFIGURATION_FLAGS: +JVM.JVM_8_TARGET
|
||||||
|
interface Test<T> {
|
||||||
|
fun test(p: T): T {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Test2: Test<String> {
|
||||||
|
override fun test(p: String): String {
|
||||||
|
return p + "K"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestClass : Test2 {
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> execute(t: Test<T>, p: T): T {
|
||||||
|
return t.test(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
return execute(TestClass(), "O")
|
||||||
|
}
|
||||||
|
|
||||||
+12
@@ -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);
|
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")
|
@TestMetadata("simpleCall.kt")
|
||||||
public void testSimpleCall() throws Exception {
|
public void testSimpleCall() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/box/jvm8/simpleCall.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/box/jvm8/simpleCall.kt");
|
||||||
|
|||||||
@@ -994,6 +994,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("kt1939.kt")
|
||||||
public void testKt1939() throws Exception {
|
public void testKt1939() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/bridges/kt1939.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/bridges/kt1939.kt");
|
||||||
@@ -1162,6 +1168,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("twoParentsWithTheSameMethodOneBridge.kt")
|
||||||
public void testTwoParentsWithTheSameMethodOneBridge() throws Exception {
|
public void testTwoParentsWithTheSameMethodOneBridge() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/bridges/twoParentsWithTheSameMethodOneBridge.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/bridges/twoParentsWithTheSameMethodOneBridge.kt");
|
||||||
|
|||||||
@@ -125,6 +125,12 @@ public class BridgeTestGenerated extends AbstractBridgeTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("kt1939.kt")
|
||||||
public void testKt1939() throws Exception {
|
public void testKt1939() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/bridges/kt1939.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/bridges/kt1939.kt");
|
||||||
@@ -287,6 +293,12 @@ public class BridgeTestGenerated extends AbstractBridgeTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("twoParentsWithTheSameMethodOneBridge.kt")
|
||||||
public void testTwoParentsWithTheSameMethodOneBridge() throws Exception {
|
public void testTwoParentsWithTheSameMethodOneBridge() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/bridges/twoParentsWithTheSameMethodOneBridge.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/bridges/twoParentsWithTheSameMethodOneBridge.kt");
|
||||||
|
|||||||
+7
-2
@@ -77,6 +77,8 @@ class ClassTranslator private constructor(
|
|||||||
|
|
||||||
private fun isTrait(): Boolean = descriptor.kind == ClassKind.INTERFACE
|
private fun isTrait(): Boolean = descriptor.kind == ClassKind.INTERFACE
|
||||||
|
|
||||||
|
private fun isAnnotation(): Boolean = descriptor.kind == ClassKind.ANNOTATION_CLASS
|
||||||
|
|
||||||
private fun generateClassCreateInvocationArguments() {
|
private fun generateClassCreateInvocationArguments() {
|
||||||
val properties = SmartList<JsPropertyInitializer>()
|
val properties = SmartList<JsPropertyInitializer>()
|
||||||
val staticProperties = SmartList<JsPropertyInitializer>()
|
val staticProperties = SmartList<JsPropertyInitializer>()
|
||||||
@@ -369,7 +371,7 @@ class ClassTranslator private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun generatedBridgeMethods(properties: MutableList<JsPropertyInitializer>) {
|
private fun generatedBridgeMethods(properties: MutableList<JsPropertyInitializer>) {
|
||||||
if (isTrait()) return
|
if (isAnnotation()) return
|
||||||
|
|
||||||
generateBridgesToTraitImpl(properties)
|
generateBridgesToTraitImpl(properties)
|
||||||
|
|
||||||
@@ -387,7 +389,10 @@ class ClassTranslator private constructor(
|
|||||||
private fun generateOtherBridges(properties: MutableList<JsPropertyInitializer>) {
|
private fun generateOtherBridges(properties: MutableList<JsPropertyInitializer>) {
|
||||||
for (memberDescriptor in descriptor.defaultType.memberScope.getContributedDescriptors()) {
|
for (memberDescriptor in descriptor.defaultType.memberScope.getContributedDescriptors()) {
|
||||||
if (memberDescriptor is FunctionDescriptor) {
|
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) {
|
for (bridge in bridgesToGenerate) {
|
||||||
generateBridge(bridge, properties)
|
generateBridge(bridge, properties)
|
||||||
|
|||||||
Reference in New Issue
Block a user