diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/builtinSpecialBridges.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/builtinSpecialBridges.kt index eb8e1a4c5d9..fdf05e31068 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/builtinSpecialBridges.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/builtinSpecialBridges.kt @@ -19,15 +19,10 @@ package org.jetbrains.kotlin.codegen 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.ClassDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.Modality -import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.load.java.* import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature.getSpecialSignatureInfo import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor -import org.jetbrains.kotlin.load.java.getOverriddenBuiltinWithDifferentJvmDescriptor -import org.jetbrains.kotlin.load.java.hasRealKotlinSuperClassWithOverrideOf import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtPsiUtil import org.jetbrains.kotlin.resolve.BindingContext @@ -63,7 +58,6 @@ object BuiltinSpecialBridgesUtil { val needGenerateSpecialBridge = needGenerateSpecialBridge( function, reachableDeclarations, overriddenBuiltin, signatureByDescriptor, overriddenBuiltinSignature) - && methodItself != overriddenBuiltinSignature val specialBridge = if (needGenerateSpecialBridge) BridgeForBuiltinSpecial(overriddenBuiltinSignature, methodItself, isSpecial = true) @@ -115,13 +109,24 @@ private fun needGenerateSpecialBridge( signatureByDescriptor: (FunctionDescriptor) -> Signature, overriddenBuiltinSignature: Signature ): Boolean { - val classDescriptor = functionDescriptor.containingDeclaration as ClassDescriptor - return !classDescriptor.hasRealKotlinSuperClassWithOverrideOf(specialCallableDescriptor) - && specialCallableDescriptor.modality != Modality.FINAL - && reachableDeclarations.none { - it.modality == Modality.FINAL - && signatureByDescriptor(it) == overriddenBuiltinSignature - } + if (signatureByDescriptor(functionDescriptor) == overriddenBuiltinSignature) return false + if (specialCallableDescriptor.modality == Modality.FINAL) return false + + // Is there Kotlin superclass that already has generated special bridge + if (functionDescriptor.firstOverridden { overridden -> + val originalOverridden = overridden.original + if (overridden === functionDescriptor + || originalOverridden !is FunctionDescriptor + || originalOverridden.containingDeclaration is JavaClassDescriptor + || DescriptorUtils.isInterface(originalOverridden.containingDeclaration)) return@firstOverridden false + + val overriddenSpecial = originalOverridden.getOverriddenBuiltinWithDifferentJvmDescriptor()?.original ?: return@firstOverridden false + + signatureByDescriptor(originalOverridden) != signatureByDescriptor(overriddenSpecial) + } != null) return false + + return reachableDeclarations.none { it.modality == Modality.FINAL + && signatureByDescriptor(it) == overriddenBuiltinSignature } } public fun isValueArgumentForCallToMethodWithTypeCheckBarrier( diff --git a/compiler/testData/codegen/box/specialBuiltins/noSpecialBridgeInSuperClass.kt b/compiler/testData/codegen/box/specialBuiltins/noSpecialBridgeInSuperClass.kt new file mode 100644 index 00000000000..df49fe5a5cb --- /dev/null +++ b/compiler/testData/codegen/box/specialBuiltins/noSpecialBridgeInSuperClass.kt @@ -0,0 +1,59 @@ +var result = "" + +public abstract class AbstractFoo : Map { + override operator fun get(key: K): V? { + result = "AbstractFoo" + return null + } + + override val size: Int + get() = throw UnsupportedOperationException() + + override fun isEmpty(): Boolean { + throw UnsupportedOperationException() + } + + override fun containsKey(key: K): Boolean { + throw UnsupportedOperationException() + } + + override fun containsValue(value: V): Boolean { + throw UnsupportedOperationException() + } + + override val keys: Set + get() = throw UnsupportedOperationException() + override val values: Collection + get() = throw UnsupportedOperationException() + override val entries: Set> + get() = throw UnsupportedOperationException() +} + +public open class StringFoo : AbstractFoo() { + override operator fun get(key: String): E? { + result = "StringFoo" + return null + } +} + +public class IntFoo : AbstractFoo() { + override operator fun get(key: Int): E? { + result = "IntFoo" + return null + } +} + +public class AnyFoo : AbstractFoo() {} + +fun box(): String { + StringFoo().get("") + if (result != "StringFoo") return "fail 1: $result" + + IntFoo().get(1) + if (result != "IntFoo") return "fail 2: $result" + + AnyFoo().get(null) + if (result != "AbstractFoo") return "fail 3: $result" + + return "OK" +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java index 3a6e76c0408..9b8015c4a1e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -7351,6 +7351,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("noSpecialBridgeInSuperClass.kt") + public void testNoSpecialBridgeInSuperClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/specialBuiltins/noSpecialBridgeInSuperClass.kt"); + doTest(fileName); + } + @TestMetadata("throwable.kt") public void testThrowable() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/specialBuiltins/throwable.kt"); diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/specialBuiltinMembers.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/specialBuiltinMembers.kt index 80b512ab0d4..94051062961 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/specialBuiltinMembers.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/specialBuiltinMembers.kt @@ -270,7 +270,7 @@ private val CallableMemberDescriptor.propertyIfAccessor: CallableMemberDescripto private fun CallableDescriptor.fqNameOrNull(): FqName? = fqNameUnsafe.check { it.isSafe }?.toSafe() -private fun CallableMemberDescriptor.firstOverridden( +public fun CallableMemberDescriptor.firstOverridden( predicate: (CallableMemberDescriptor) -> Boolean ): CallableMemberDescriptor? { var result: CallableMemberDescriptor? = null