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
This commit is contained in:
Denis Zharkov
2015-11-12 14:08:18 +03:00
parent abf7ae547e
commit f5a086140e
4 changed files with 86 additions and 16 deletions
@@ -19,15 +19,10 @@ package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.backend.common.bridges.DescriptorBasedFunctionHandle 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.*
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.load.java.*
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature.getSpecialSignatureInfo import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature.getSpecialSignatureInfo
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor 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.KtElement
import org.jetbrains.kotlin.psi.KtPsiUtil import org.jetbrains.kotlin.psi.KtPsiUtil
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
@@ -63,7 +58,6 @@ object BuiltinSpecialBridgesUtil {
val needGenerateSpecialBridge = needGenerateSpecialBridge( val needGenerateSpecialBridge = needGenerateSpecialBridge(
function, reachableDeclarations, overriddenBuiltin, signatureByDescriptor, overriddenBuiltinSignature) function, reachableDeclarations, overriddenBuiltin, signatureByDescriptor, overriddenBuiltinSignature)
&& methodItself != overriddenBuiltinSignature
val specialBridge = if (needGenerateSpecialBridge) val specialBridge = if (needGenerateSpecialBridge)
BridgeForBuiltinSpecial(overriddenBuiltinSignature, methodItself, isSpecial = true) BridgeForBuiltinSpecial(overriddenBuiltinSignature, methodItself, isSpecial = true)
@@ -115,13 +109,24 @@ private fun <Signature> needGenerateSpecialBridge(
signatureByDescriptor: (FunctionDescriptor) -> Signature, signatureByDescriptor: (FunctionDescriptor) -> Signature,
overriddenBuiltinSignature: Signature overriddenBuiltinSignature: Signature
): Boolean { ): Boolean {
val classDescriptor = functionDescriptor.containingDeclaration as ClassDescriptor if (signatureByDescriptor(functionDescriptor) == overriddenBuiltinSignature) return false
return !classDescriptor.hasRealKotlinSuperClassWithOverrideOf(specialCallableDescriptor) if (specialCallableDescriptor.modality == Modality.FINAL) return false
&& specialCallableDescriptor.modality != Modality.FINAL
&& reachableDeclarations.none { // Is there Kotlin superclass that already has generated special bridge
it.modality == Modality.FINAL if (functionDescriptor.firstOverridden { overridden ->
&& signatureByDescriptor(it) == overriddenBuiltinSignature 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( public fun isValueArgumentForCallToMethodWithTypeCheckBarrier(
@@ -0,0 +1,59 @@
var result = ""
public abstract class AbstractFoo<K, V> : Map<K, V> {
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<K>
get() = throw UnsupportedOperationException()
override val values: Collection<V>
get() = throw UnsupportedOperationException()
override val entries: Set<Map.Entry<K, V>>
get() = throw UnsupportedOperationException()
}
public open class StringFoo<E> : AbstractFoo<String, E>() {
override operator fun get(key: String): E? {
result = "StringFoo"
return null
}
}
public class IntFoo<E> : AbstractFoo<Int, E>() {
override operator fun get(key: Int): E? {
result = "IntFoo"
return null
}
}
public class AnyFoo<E> : AbstractFoo<Any?, E>() {}
fun box(): String {
StringFoo<String>().get("")
if (result != "StringFoo") return "fail 1: $result"
IntFoo<String>().get(1)
if (result != "IntFoo") return "fail 2: $result"
AnyFoo<String>().get(null)
if (result != "AbstractFoo") return "fail 3: $result"
return "OK"
}
@@ -7351,6 +7351,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName); 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") @TestMetadata("throwable.kt")
public void testThrowable() throws Exception { public void testThrowable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/specialBuiltins/throwable.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/specialBuiltins/throwable.kt");
@@ -270,7 +270,7 @@ private val CallableMemberDescriptor.propertyIfAccessor: CallableMemberDescripto
private fun CallableDescriptor.fqNameOrNull(): FqName? = fqNameUnsafe.check { it.isSafe }?.toSafe() private fun CallableDescriptor.fqNameOrNull(): FqName? = fqNameUnsafe.check { it.isSafe }?.toSafe()
private fun CallableMemberDescriptor.firstOverridden( public fun CallableMemberDescriptor.firstOverridden(
predicate: (CallableMemberDescriptor) -> Boolean predicate: (CallableMemberDescriptor) -> Boolean
): CallableMemberDescriptor? { ): CallableMemberDescriptor? {
var result: CallableMemberDescriptor? = null var result: CallableMemberDescriptor? = null