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)
|
val commonBridges = reachableDeclarations.mapTo(LinkedHashSet<Signature>(), signatureByDescriptor)
|
||||||
commonBridges.removeAll(specialBridgesSignaturesInSuperClass + specialBridge?.from.singletonOrEmptyList())
|
commonBridges.removeAll(specialBridgesSignaturesInSuperClass + specialBridge?.from.singletonOrEmptyList())
|
||||||
|
|
||||||
|
|
||||||
if (fake) {
|
if (fake) {
|
||||||
for (overridden in function.overriddenDescriptors.map { it.original }) {
|
for (overridden in function.overriddenDescriptors.map { it.original }) {
|
||||||
if (!DescriptorBasedFunctionHandle(overridden, isBodyOwner).isAbstract) {
|
if (!DescriptorBasedFunctionHandle(overridden, isBodyOwner).isAbstract) {
|
||||||
@@ -89,11 +88,9 @@ object BuiltinSpecialBridgesUtil {
|
|||||||
|
|
||||||
val bridges: MutableSet<BridgeForBuiltinSpecial<Signature>> = mutableSetOf()
|
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 =
|
val superImplementationDescriptor =
|
||||||
if (specialBridge != null)
|
if (specialBridge != null)
|
||||||
findSuperImplementationForStubDelegation(function, fake, isBodyOwner)
|
findSuperImplementationForStubDelegation(function, fake, isBodyOwner, signatureByDescriptor)
|
||||||
else
|
else
|
||||||
null
|
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,
|
function: FunctionDescriptor,
|
||||||
fake: Boolean,
|
fake: Boolean,
|
||||||
isBodyOwner: (DeclarationDescriptor) -> Boolean
|
isBodyOwner: (DeclarationDescriptor) -> Boolean,
|
||||||
|
signatureByDescriptor: (FunctionDescriptor) -> Signature
|
||||||
): FunctionDescriptor? {
|
): FunctionDescriptor? {
|
||||||
if (function.modality != Modality.OPEN || !fake) return null
|
if (function.modality != Modality.OPEN || !fake) return null
|
||||||
val implementation = findConcreteSuperDeclaration(DescriptorBasedFunctionHandle(function, isBodyOwner)).descriptor
|
val implementation = findConcreteSuperDeclaration(DescriptorBasedFunctionHandle(function, isBodyOwner)).descriptor
|
||||||
if (DescriptorUtils.isInterface(implementation.containingDeclaration)) return null
|
if (DescriptorUtils.isInterface(implementation.containingDeclaration)) return null
|
||||||
|
|
||||||
|
// Implementation in super-class already has proper signature
|
||||||
|
if (signatureByDescriptor(function) == signatureByDescriptor(implementation)) return null
|
||||||
|
|
||||||
return implementation
|
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);
|
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")
|
@TestMetadata("removeAtTwoSpecialBridges.kt")
|
||||||
public void testRemoveAtTwoSpecialBridges() throws Exception {
|
public void testRemoveAtTwoSpecialBridges() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/specialBuiltins/removeAtTwoSpecialBridges.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/specialBuiltins/removeAtTwoSpecialBridges.kt");
|
||||||
|
|||||||
@@ -142,6 +142,12 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("removeAtTwoSpecialBridges.kt")
|
||||||
public void testRemoveAtTwoSpecialBridges() throws Exception {
|
public void testRemoveAtTwoSpecialBridges() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeListing/specialBridges/removeAtTwoSpecialBridges.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeListing/specialBridges/removeAtTwoSpecialBridges.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user