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:
Denis Zharkov
2016-06-29 19:50:26 +03:00
parent 5c34b27ea9
commit 84eb009c29
6 changed files with 111 additions and 7 deletions
@@ -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"
}
@@ -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.
}
}
@@ -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");