Refine stubs generation for special built-ins
Do not generate stub if declaration has the same signature #KT-12909 Fixed
This commit is contained in:
@@ -78,7 +78,6 @@ object BuiltinSpecialBridgesUtil {
|
||||
val commonBridges = reachableDeclarations.mapTo(LinkedHashSet<Signature>(), signatureByDescriptor)
|
||||
commonBridges.removeAll(specialBridgesSignaturesInSuperClass + specialBridge?.from.singletonOrEmptyList())
|
||||
|
||||
|
||||
if (fake) {
|
||||
for (overridden in function.overriddenDescriptors.map { it.original }) {
|
||||
if (!DescriptorBasedFunctionHandle(overridden, isBodyOwner).isAbstract) {
|
||||
@@ -89,11 +88,9 @@ object BuiltinSpecialBridgesUtil {
|
||||
|
||||
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 =
|
||||
if (specialBridge != null)
|
||||
findSuperImplementationForStubDelegation(function, fake, isBodyOwner)
|
||||
findSuperImplementationForStubDelegation(function, fake, isBodyOwner, signatureByDescriptor)
|
||||
else
|
||||
null
|
||||
|
||||
@@ -127,16 +124,33 @@ object BuiltinSpecialBridgesUtil {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun findSuperImplementationForStubDelegation(
|
||||
/**
|
||||
* Stub is a method having signature from Kotlin built-ins that we generate for non-abstract declarations,
|
||||
* it's bytecode consists of INVOKESPECIAL-call to real declaration in super class.
|
||||
*
|
||||
* Note that stub is needed only for first Kotlin class in the hierarchy.
|
||||
*
|
||||
* For example:
|
||||
* class A : HashMap<String, Any>
|
||||
*
|
||||
* Here we generate `entrySet()` special bridge with INVOKEVIRTUAL getEntries(),
|
||||
* But the latter does not exists yet, so we create a stub for it with delegation to super-class
|
||||
*
|
||||
* Also note that there is no special bridges for final declarations, thus no stubs either
|
||||
*/
|
||||
private fun <Signature> findSuperImplementationForStubDelegation(
|
||||
function: FunctionDescriptor,
|
||||
fake: Boolean,
|
||||
isBodyOwner: (DeclarationDescriptor) -> Boolean
|
||||
isBodyOwner: (DeclarationDescriptor) -> Boolean,
|
||||
signatureByDescriptor: (FunctionDescriptor) -> Signature
|
||||
): FunctionDescriptor? {
|
||||
if (function.modality != Modality.OPEN || !fake) return null
|
||||
val implementation = findConcreteSuperDeclaration(DescriptorBasedFunctionHandle(function, isBodyOwner)).descriptor
|
||||
if (DescriptorUtils.isInterface(implementation.containingDeclaration)) return null
|
||||
|
||||
// Implementation in super-class already has proper signature
|
||||
if (signatureByDescriptor(function) == signatureByDescriptor(implementation)) return null
|
||||
|
||||
return implementation
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
open class A1 {
|
||||
open val size: Int = 56
|
||||
}
|
||||
|
||||
class A2 : A1(), Collection<String> {
|
||||
// No 'getSize()' method should be generated in A2
|
||||
|
||||
override fun contains(element: String): Boolean {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun containsAll(elements: Collection<String>): Boolean {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun isEmpty(): Boolean {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun iterator(): Iterator<String> {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
if (A2().size != 56) return "fail 1"
|
||||
return "OK"
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
open class A1 {
|
||||
open val size: Int = 56
|
||||
}
|
||||
|
||||
class A2 : A1(), Collection<String> {
|
||||
// No 'getSize()' method should be generated in A2
|
||||
|
||||
override fun contains(element: String): Boolean {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun containsAll(elements: Collection<String>): Boolean {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun isEmpty(): Boolean {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun iterator(): Iterator<String> {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
@kotlin.Metadata
|
||||
public class A1 {
|
||||
private final field size: int
|
||||
public method <init>(): void
|
||||
public method getSize(): int
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class A2 {
|
||||
public method <init>(): void
|
||||
public synthetic method add(p0: java.lang.Object): boolean
|
||||
public method add(p0: java.lang.String): boolean
|
||||
public method addAll(p0: java.util.Collection): boolean
|
||||
public method clear(): void
|
||||
public method contains(@org.jetbrains.annotations.NotNull p0: java.lang.String): boolean
|
||||
public final method contains(p0: java.lang.Object): boolean
|
||||
public method containsAll(@org.jetbrains.annotations.NotNull p0: java.util.Collection): boolean
|
||||
public method isEmpty(): boolean
|
||||
public @org.jetbrains.annotations.NotNull method iterator(): java.util.Iterator
|
||||
public method remove(p0: java.lang.Object): boolean
|
||||
public method remove(p0: java.lang.String): boolean
|
||||
public method removeAll(p0: java.util.Collection): boolean
|
||||
public method retainAll(p0: java.util.Collection): boolean
|
||||
public final method size(): int
|
||||
public method toArray(): java.lang.Object[]
|
||||
public method toArray(p0: java.lang.Object[]): java.lang.Object[]
|
||||
}
|
||||
@@ -13687,6 +13687,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("redundantStubForSize.kt")
|
||||
public void testRedundantStubForSize() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/specialBuiltins/redundantStubForSize.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("removeAtTwoSpecialBridges.kt")
|
||||
public void testRemoveAtTwoSpecialBridges() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/specialBuiltins/removeAtTwoSpecialBridges.kt");
|
||||
|
||||
@@ -142,6 +142,12 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("redundantStubForSize.kt")
|
||||
public void testRedundantStubForSize() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeListing/specialBridges/redundantStubForSize.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("removeAtTwoSpecialBridges.kt")
|
||||
public void testRemoveAtTwoSpecialBridges() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeListing/specialBridges/removeAtTwoSpecialBridges.kt");
|
||||
|
||||
Reference in New Issue
Block a user