From f5a086140e1d1253617b9fa11fffb698aa85fb2e Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Thu, 12 Nov 2015 14:08:18 +0300 Subject: [PATCH] Refine special bridge generating rule Generate special bridge even in case current class has Kotlin superclass implementing this builtin method, but that super class was generated without special bridge (e.g. because it would have the same signature) #KT-9901 Fixed --- .../kotlin/codegen/builtinSpecialBridges.kt | 35 ++++++----- .../noSpecialBridgeInSuperClass.kt | 59 +++++++++++++++++++ .../BlackBoxCodegenTestGenerated.java | 6 ++ .../kotlin/load/java/specialBuiltinMembers.kt | 2 +- 4 files changed, 86 insertions(+), 16 deletions(-) create mode 100644 compiler/testData/codegen/box/specialBuiltins/noSpecialBridgeInSuperClass.kt 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