Fix bridge generation for special builtin override
Use method itself signature as common bridge delegate #KT-11285 Fixed
This commit is contained in:
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getParentCall
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.overriddenTreeAsSequence
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.singletonOrEmptyList
|
||||
import java.util.*
|
||||
|
||||
@@ -75,10 +76,6 @@ object BuiltinSpecialBridgesUtil {
|
||||
val commonBridges = reachableDeclarations.mapTo(LinkedHashSet<Signature>(), signatureByDescriptor)
|
||||
commonBridges.removeAll(specialBridgesSignaturesInSuperClass + specialBridge?.from.singletonOrEmptyList())
|
||||
|
||||
val superImplementationDescriptor = findSuperImplementationForStubDelegation(function, fake)
|
||||
if (superImplementationDescriptor != null || !fake || functionHandle.isAbstract) {
|
||||
commonBridges.remove(methodItself)
|
||||
}
|
||||
|
||||
if (fake) {
|
||||
for (overridden in function.overriddenDescriptors.map { it.original }) {
|
||||
@@ -88,13 +85,28 @@ object BuiltinSpecialBridgesUtil {
|
||||
}
|
||||
}
|
||||
|
||||
val bridges: MutableSet<BridgeForBuiltinSpecial<Signature>> =
|
||||
(commonBridges.map { BridgeForBuiltinSpecial(it, specialBridgeSignature) } + specialBridge.singletonOrEmptyList()).toMutableSet()
|
||||
val bridges: MutableSet<BridgeForBuiltinSpecial<Signature>> = mutableSetOf()
|
||||
|
||||
// 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)
|
||||
if (superImplementationDescriptor != null) {
|
||||
bridges.add(BridgeForBuiltinSpecial(methodItself, signatureByDescriptor(superImplementationDescriptor), isDelegateToSuper = true))
|
||||
}
|
||||
|
||||
if (commonBridges.remove(methodItself)) {
|
||||
if (superImplementationDescriptor == null && fake && !functionHandle.isAbstract && methodItself != specialBridgeSignature) {
|
||||
// The only case when superImplementationDescriptor, but method is fake and not abstract is enum members
|
||||
// They have superImplementationDescriptor null because they are final
|
||||
|
||||
// generate non-synthetic bridge 'getOrdinal()' to 'ordinal()' (see test enumAsOrdinaled.kt)
|
||||
bridges.add(BridgeForBuiltinSpecial(methodItself, specialBridgeSignature, isSpecial = false, isDelegateToSuper = false))
|
||||
}
|
||||
}
|
||||
|
||||
bridges.addAll(commonBridges.map { BridgeForBuiltinSpecial(it, methodItself) })
|
||||
bridges.addIfNotNull(specialBridge)
|
||||
|
||||
return bridges
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import java.util.*
|
||||
|
||||
open class Base<Target : DatabaseEntity>() : HashSet<Target>() {
|
||||
override fun remove(element: Target): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
class Derived : Base<Issue>() {
|
||||
// common "synthetic bridge override fun remove(element: DatabaseEntity): Boolean" should call
|
||||
// `INVOKEVIRTUAL remove(Issue)`
|
||||
// instead of `INVOKEVIRTUAL remove(OBJECT)`
|
||||
override fun remove(element: Issue): Boolean {
|
||||
return super.remove(element)
|
||||
}
|
||||
}
|
||||
|
||||
open class DatabaseEntity
|
||||
class Issue: DatabaseEntity()
|
||||
|
||||
fun box(): String {
|
||||
val sprintIssues = Derived()
|
||||
if (!sprintIssues.remove(Issue())) return "Fail"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -90,18 +90,18 @@ fun box(
|
||||
}
|
||||
|
||||
/*
|
||||
9 INVOKEVIRTUAL A[0-9]+.removeAt \(I\) -> calls in bridges with signature `public final bridge remove\(I\)`
|
||||
16 INVOKEVIRTUAL A[0-9]+\.remove \(I\) -> calls to A1-A9.removeAt + 7 calls from `public synthetic bridge remove\(I\)Ljava/lang/Object;`
|
||||
16 INVOKEVIRTUAL A[0-9]+.removeAt \(I\) -> calls in bridges with signature `public final bridge remove\(I\)` + 7 calls from `public synthetic bridge remove\(I\)Ljava/lang/Object;`
|
||||
9 INVOKEVIRTUAL A[0-9]+\.remove \(I\) -> calls to A1-A9.removeAt
|
||||
1 INVOKEINTERFACE A9\.remove \(I\) -> call A9.removeAt
|
||||
1 INVOKEINTERFACE A9\.remove \(Ljava/lang/Object;\) -> call A9.remove
|
||||
2 INVOKEVIRTUAL A10\.remove \(I\) -> one call in function and one from `public synthetic bridge remove(I)Ljava/lang/Object;` bridge in A10
|
||||
1 INVOKEVIRTUAL A10\.remove \(I\) -> one call in 'box' function
|
||||
*/
|
||||
|
||||
// 9 INVOKEVIRTUAL A[0-9]+.removeAt \(I\)
|
||||
// 16 INVOKEVIRTUAL A[0-9]+\.remove \(I\)
|
||||
// 16 INVOKEVIRTUAL A[0-9]+.removeAt \(I\)
|
||||
// 9 INVOKEVIRTUAL A[0-9]+\.remove \(I\)
|
||||
// 1 INVOKEINTERFACE A9\.remove \(I\)
|
||||
// 1 INVOKEINTERFACE A9\.remove \(Ljava/lang/Object;\)
|
||||
// 2 INVOKEVIRTUAL A10\.remove \(I\)
|
||||
// 1 INVOKEVIRTUAL A10\.remove \(I\)
|
||||
// 2 INVOKEINTERFACE java\/util\/List.remove \(I\)
|
||||
// 2 INVOKEINTERFACE java\/util\/List.remove \(Ljava/lang/Object;\)
|
||||
|
||||
|
||||
@@ -7585,6 +7585,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("commonBridgesTarget.kt")
|
||||
public void testCommonBridgesTarget() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/specialBuiltins/commonBridgesTarget.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("emptyList.kt")
|
||||
public void testEmptyList() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/specialBuiltins/emptyList.kt");
|
||||
|
||||
Reference in New Issue
Block a user