JVM_IR KT-36994 don't generate stub if present in superclass

This commit is contained in:
Dmitry Petrov
2020-09-24 16:49:36 +03:00
parent 1adce11257
commit cfd62c15bf
10 changed files with 147 additions and 17 deletions
@@ -294,25 +294,32 @@ internal class CollectionStubMethodLowering(val context: JvmBackendContext) : Cl
// Compute stubs that should be generated, compare based on signature
private fun generateRelevantStubMethods(irClass: IrClass): List<IrSimpleFunction> {
val ourStubsForCollectionClasses = collectionStubComputer.stubsForCollectionClasses(irClass)
val superStubClasses = irClass.superClass?.superClassChain?.map { superClass ->
collectionStubComputer.stubsForCollectionClasses(superClass).map { it.readOnlyClass }
}?.fold(emptySet<IrClassSymbol>(), { a, b -> a union b }) ?: emptySet()
// do a second filtering to ensure only most relevant classes are included.
val redundantClasses = ourStubsForCollectionClasses.filter { (readOnlyClass) ->
ourStubsForCollectionClasses.any { readOnlyClass != it.readOnlyClass && it.readOnlyClass.isSubtypeOfClass(readOnlyClass) }
}.map { it.readOnlyClass }
// perform type substitution and type erasure here
return ourStubsForCollectionClasses.filter { (readOnlyClass) ->
readOnlyClass !in redundantClasses && readOnlyClass !in superStubClasses
}.flatMap { (readOnlyClass, mutableClass, mutableOnlyMethods) ->
fun createStubFuns(stubs: CollectionStubComputer.StubsForCollectionClass): List<IrSimpleFunction> {
val (readOnlyClass, mutableClass, mutableOnlyMethods) = stubs
val substitutionMap = computeSubstitutionMap(readOnlyClass.owner, mutableClass.owner, irClass)
mutableOnlyMethods.map { function ->
return mutableOnlyMethods.map { function ->
createStubMethod(function, irClass, substitutionMap)
}
}
val classStubs = collectionStubComputer.stubsForCollectionClasses(irClass)
val superClassesStubs = irClass.superClass?.run {
superClassChain.flatMap { superClass ->
collectionStubComputer.stubsForCollectionClasses(superClass)
}.toList()
} ?: emptyList()
val relevantStubs =
classStubs.filter { (readOnlyClass) ->
classStubs.none { readOnlyClass != it.readOnlyClass && it.readOnlyClass.isSubtypeOfClass(readOnlyClass) } &&
superClassesStubs.none { it.readOnlyClass == readOnlyClass }
}
val classStubFuns = relevantStubs.flatMap { createStubFuns(it) }
val superClassStubSignatures = superClassesStubs.flatMap { createStubFuns(it) }.mapTo(HashSet()) { it.toJvmSignature() }
return classStubFuns.filter { it.toJvmSignature() !in superClassStubSignatures }
}
private fun Collection<IrType>.findMostSpecificTypeForClass(classifier: IrClassSymbol): IrType {
@@ -0,0 +1,3 @@
abstract class AC<X> : Collection<X>
abstract class ASet<T> : AC<T>(), Set<T>
@@ -0,0 +1,23 @@
@kotlin.Metadata
public abstract class AC {
// source: 'extendingAbstractCollection.kt'
public method <init>(): void
public method add(p0: java.lang.Object): boolean
public method addAll(p0: java.util.Collection): boolean
public method clear(): void
public abstract method contains(p0: java.lang.Object): boolean
public abstract method getSize(): int
public method iterator(): java.util.Iterator
public method remove(p0: java.lang.Object): boolean
public method removeAll(p0: java.util.Collection): boolean
public method retainAll(p0: java.util.Collection): boolean
public bridge final method size(): int
public method toArray(): java.lang.Object[]
public method toArray(p0: java.lang.Object[]): java.lang.Object[]
}
@kotlin.Metadata
public abstract class ASet {
// source: 'extendingAbstractCollection.kt'
public method <init>(): void
}
@@ -0,0 +1,22 @@
@kotlin.Metadata
public abstract class AC {
// source: 'extendingAbstractCollection.kt'
public method <init>(): void
public method add(p0: java.lang.Object): boolean
public method addAll(p0: java.util.Collection): boolean
public method clear(): void
public abstract method getSize(): int
public method iterator(): java.util.Iterator
public method remove(p0: java.lang.Object): boolean
public method removeAll(p0: java.util.Collection): boolean
public method retainAll(p0: java.util.Collection): boolean
public bridge final method size(): int
public method toArray(): java.lang.Object[]
public method toArray(p0: java.lang.Object[]): java.lang.Object[]
}
@kotlin.Metadata
public abstract class ASet {
// source: 'extendingAbstractCollection.kt'
public method <init>(): void
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// WITH_RUNTIME
// FILE: test/B.java
@@ -0,0 +1,18 @@
// WITH_RUNTIME
// IGNORE_BACKEND: JVM
// ^ see KT-42179
// FILE: test/JC.java
package test;
import java.util.Collection;
public abstract class JC<E> implements Collection<E> {
}
// FILE: noStubsInJavaSuperClass2.kt
package test
abstract class KSet<E> : JC<E>(), Set<E>
abstract class KList<E> : JC<E>(), List<E>
@@ -0,0 +1,39 @@
@kotlin.Metadata
public abstract class test/KList {
// source: 'noStubsInJavaSuperClass2.kt'
public method <init>(): void
public method add(p0: int, p1: java.lang.Object): void
public method add(p0: java.lang.Object): boolean
public method addAll(p0: int, p1: java.util.Collection): boolean
public method addAll(p0: java.util.Collection): boolean
public method clear(): void
public abstract method getSize(): int
public method listIterator(): java.util.ListIterator
public method listIterator(p0: int): java.util.ListIterator
public method remove(p0: int): java.lang.Object
public method remove(p0: java.lang.Object): boolean
public method removeAll(p0: java.util.Collection): boolean
public method retainAll(p0: java.util.Collection): boolean
public method set(p0: int, p1: java.lang.Object): java.lang.Object
public bridge final method size(): int
public method subList(p0: int, p1: int): java.util.List
public method toArray(): java.lang.Object[]
public method toArray(p0: java.lang.Object[]): java.lang.Object[]
}
@kotlin.Metadata
public abstract class test/KSet {
// source: 'noStubsInJavaSuperClass2.kt'
public method <init>(): void
public method add(p0: java.lang.Object): boolean
public method addAll(p0: java.util.Collection): boolean
public method clear(): void
public abstract method getSize(): int
public method iterator(): java.util.Iterator
public method remove(p0: java.lang.Object): boolean
public method removeAll(p0: java.util.Collection): boolean
public method retainAll(p0: java.util.Collection): boolean
public bridge final method size(): int
public method toArray(): java.lang.Object[]
public method toArray(p0: java.lang.Object[]): java.lang.Object[]
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// WITH_RUNTIME
open class A<T> : Collection<T> {
@@ -254,6 +254,11 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/emptyList.kt");
}
@TestMetadata("extendingAbstractCollection.kt")
public void testExtendingAbstractCollection() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/extendingAbstractCollection.kt");
}
@TestMetadata("noStubsForCollection.kt")
public void testNoStubsForCollection() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsForCollection.kt");
@@ -284,6 +289,11 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsInJavaSuperClass.kt");
}
@TestMetadata("noStubsInJavaSuperClass2.kt")
public void testNoStubsInJavaSuperClass2() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsInJavaSuperClass2.kt");
}
@TestMetadata("noStubsInMutableIterable.kt")
public void testNoStubsInMutableIterable() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsInMutableIterable.kt");
@@ -254,6 +254,11 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes
runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/emptyList.kt");
}
@TestMetadata("extendingAbstractCollection.kt")
public void testExtendingAbstractCollection() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/extendingAbstractCollection.kt");
}
@TestMetadata("noStubsForCollection.kt")
public void testNoStubsForCollection() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsForCollection.kt");
@@ -284,6 +289,11 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes
runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsInJavaSuperClass.kt");
}
@TestMetadata("noStubsInJavaSuperClass2.kt")
public void testNoStubsInJavaSuperClass2() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsInJavaSuperClass2.kt");
}
@TestMetadata("noStubsInMutableIterable.kt")
public void testNoStubsInMutableIterable() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsInMutableIterable.kt");