diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CollectionStubMethodLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CollectionStubMethodLowering.kt index 0e95b83175f..ec3f60ba481 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CollectionStubMethodLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CollectionStubMethodLowering.kt @@ -66,7 +66,7 @@ internal class CollectionStubMethodLowering(val context: JvmBackendContext) : Cl for (stub in methodStubsToGenerate) { val stubNameAndArity = stub.nameAndArity val relevantMembers = nonAbstractMethodsByNameAndArity[stubNameAndArity].orEmpty() - val existingOverrides = relevantMembers.filter { isOverriddenBy(stub, it) } + val existingOverrides = relevantMembers.filter { isEffectivelyOverriddenBy(stub, it) } if (existingOverrides.isNotEmpty()) { // In the case that we find a defined method that matches the stub signature, @@ -78,7 +78,8 @@ internal class CollectionStubMethodLowering(val context: JvmBackendContext) : Cl } // Generated stub might still override some abstract member(s), which affects resulting method signature. - val overriddenAbstractMethods = abstractMethodsByNameAndArity[stubNameAndArity].orEmpty().filter { isOverriddenBy(it, stub) } + val overriddenAbstractMethods = abstractMethodsByNameAndArity[stubNameAndArity].orEmpty() + .filter { isEffectivelyOverriddenBy(it, stub) } stub.overriddenSymbols += overriddenAbstractMethods.map { it.symbol } // Some stub members require special handling. @@ -121,8 +122,6 @@ internal class CollectionStubMethodLowering(val context: JvmBackendContext) : Cl else -> irClass.declarations.add(stub) } - - } } @@ -196,7 +195,7 @@ internal class CollectionStubMethodLowering(val context: JvmBackendContext) : Cl } } - private fun isOverriddenBy(superFun: IrSimpleFunction, overridingFun: IrSimpleFunction): Boolean { + private fun isEffectivelyOverriddenBy(superFun: IrSimpleFunction, overridingFun: IrSimpleFunction): Boolean { // Function 'f0' is overridden by function 'f1' if all of the following conditions are met, // assuming type parameter Ti of 'f1' is "equal" to type parameter Si of 'f0': // - names are same; @@ -301,34 +300,69 @@ internal class CollectionStubMethodLowering(val context: JvmBackendContext) : Cl // Compute stubs that should be generated, compare based on signature private fun generateRelevantStubMethods(irClass: IrClass): List { - fun createStubFuns(stubs: StubsForCollectionClass): List { - val (readOnlyClass, mutableClass, candidatesForStubs) = stubs - val substitutionMap = computeSubstitutionMap(readOnlyClass.owner, mutableClass.owner, irClass) - return candidatesForStubs.map { function -> - createStubMethod(function, irClass, substitutionMap) - } - } + val classStubFuns = collectionStubComputer.stubsForCollectionClasses(irClass) + .flatMap { createStubFuns(irClass, it) } - 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() } + val superClassStubSignatures = computeStubsForSuperClasses(irClass) + .flatMap { createStubFuns(irClass, it) } + .mapTo(HashSet()) { it.toJvmSignature() } return classStubFuns.filter { it.toJvmSignature() !in superClassStubSignatures } } + private fun createStubFuns(irClass: IrClass, stubs: StubsForCollectionClass): List { + val (readOnlyClass, mutableClass, candidatesForStubs) = stubs + val substitutionMap = computeSubstitutionMap(readOnlyClass.owner, mutableClass.owner, irClass) + return candidatesForStubs.map { function -> + createStubMethod(function, irClass, substitutionMap) + } + } + + private fun computeStubsForSuperClasses(irClass: IrClass): List { + val immediateSuperClass = irClass.superClass ?: return emptyList() + return immediateSuperClass.superClassChain + .flatMap { superClass -> computeStubsForSuperClass(superClass) } + .toList() + } + + private class FilteredStubsForCollectionClass( + override val readOnlyClass: IrClassSymbol, + override val mutableClass: IrClassSymbol, + override val candidatesForStubs: Collection + ) : StubsForCollectionClass + + private fun computeStubsForSuperClass(superClass: IrClass): List { + val superClassStubs = collectionStubComputer.stubsForCollectionClasses(superClass) + + if (superClass.modality != Modality.ABSTRACT) return superClassStubs + + // An abstract superclass might contain an abstract function declaration that effectively overrides a stub to be generated, + // and thus have no non-abstract stub. + // This calculation happens for each abstract class multiple times. TODO memoize. + + val abstractFunsByNameAndArity = superClass.functions + .filter { !it.isFakeOverride && it.modality == Modality.ABSTRACT } + .groupBy { it.nameAndArity } + + if (abstractFunsByNameAndArity.isEmpty()) return superClassStubs + + return superClassStubs.map { + val (readOnlyClass, mutableClass, candidatesForStubs) = it + // NB here we should build a stub in substitution context of the given superclass. + // Resulting stub can be different from a stub created in substitution context of the "current" class + // in case of (partially) specialized generic superclass. + val substitutionMap = computeSubstitutionMap(readOnlyClass.owner, mutableClass.owner, superClass) + val filteredCandidates = candidatesForStubs.filter { candidateFun -> + val stubMethod = createStubMethod(candidateFun, superClass, substitutionMap) + val stubNameAndArity = stubMethod.nameAndArity + abstractFunsByNameAndArity[stubNameAndArity].orEmpty().none { abstractFun -> + isEffectivelyOverriddenBy(stubMethod, abstractFun) + } + } + FilteredStubsForCollectionClass(readOnlyClass, mutableClass, filteredCandidates) + } + } + private fun Collection.findMostSpecificTypeForClass(classifier: IrClassSymbol): IrType { val types = this.filter { it.classifierOrNull == classifier } if (types.isEmpty()) error("No supertype of $classifier in $this") @@ -346,85 +380,95 @@ internal class CollectionStubMethodLowering(val context: JvmBackendContext) : Cl get() = generateSequence(this) { it.superClass } } - -internal class StubsForCollectionClass( - val readOnlyClass: IrClassSymbol, +internal interface StubsForCollectionClass { + val readOnlyClass: IrClassSymbol val mutableClass: IrClassSymbol -) { - // Old back-end generates stubs for 'class A : C', where - // 'C' is some "read-only collection" interface from kotlin.collections, - // 'MC' is a corresponding "mutable collection" interface from kotlin.collections, - // by building fake overrides for a special 'class X : A(), MC' - // and taking fake overrides that override members from 'MC'. - // - // Here we are looking at this problem from a slightly different angle: - // we select suitable member functions 'f' in 'MC' that might potentially require stubs (we are here!), - // and then we generate stubs for functions 'f' that are not effectively overridden by members of 'A' - // (this happens in the lowering itself). - // - // In order for this to be equivalent to the old back-end approach, - // we should take 'f' in 'MC' such that any of the following conditions is true: - // - 'f' is declared in 'MC' - that is, 'f' itself is not a fake override; - // - 'f' is abstract and doesn't override anything from 'C'. - // - // NB1 it also covers default methods from JDK collection classes case - // (since that's the only way a member function in 'MC' might be non-abstract). - // - // NB2 the scheme of stub method generation in the old back-end depends too much on - // which particular declarations are present in 'MC'. - // Some of these declarations are redundant from the stub generation point of view - - // for example, 'kotlin.collections.MutableListIterator' contains the following (redundant) declarations: - // override fun next(): T - // override fun hasNext(): Boolean - // which cause stubs for 'next' and 'hasNext' to be generated in a 'abstract class A : ListIterator'. - // See https://youtrack.jetbrains.com/issue/KT-36724. - // In the ideal world, it should be enough to check that - // the given member function 'f' from 'MC' doesn't override anything from 'C'. - val candidatesForStubs: Collection by lazy { - mutableClass.functions - .map { it.owner } - .filter { memberFun -> - !memberFun.isFakeOverride || - (memberFun.modality == Modality.ABSTRACT && memberFun.overriddenSymbols.none { overriddenFun -> - overriddenFun.owner.parentAsClass.symbol == readOnlyClass - }) - } - .toHashSet() - } - - operator fun component1() = readOnlyClass - operator fun component2() = mutableClass - operator fun component3() = candidatesForStubs + val candidatesForStubs: Collection } +internal operator fun StubsForCollectionClass.component1() = readOnlyClass +internal operator fun StubsForCollectionClass.component2() = mutableClass +internal operator fun StubsForCollectionClass.component3() = candidatesForStubs internal class CollectionStubComputer(val context: JvmBackendContext) { + private class LazyStubsForCollectionClass( + override val readOnlyClass: IrClassSymbol, + override val mutableClass: IrClassSymbol + ) : StubsForCollectionClass { + override val candidatesForStubs: Collection by lazy { + // Old back-end generates stubs for 'class A : C', where + // 'C' is some "read-only collection" interface from kotlin.collections, + // 'MC' is a corresponding "mutable collection" interface from kotlin.collections, + // by building fake overrides for a special 'class X : A(), MC' + // and taking fake overrides that override members from 'MC'. + // + // Here we are looking at this problem from a slightly different angle: + // we select suitable member functions 'f' in 'MC' that might potentially require stubs (we are here!), + // and then we generate stubs for functions 'f' that are not effectively overridden by members of 'A' + // (this happens in the lowering itself). + // + // In order for this to be equivalent to the old back-end approach, + // we should take 'f' in 'MC' such that any of the following conditions is true: + // - 'f' is declared in 'MC' - that is, 'f' itself is not a fake override; + // - 'f' is abstract and doesn't override anything from 'C'. + // + // NB1 it also covers default methods from JDK collection classes case + // (since that's the only way a member function in 'MC' might be non-abstract). + // + // NB2 the scheme of stub method generation in the old back-end depends too much on + // which particular declarations are present in 'MC'. + // Some of these declarations are redundant from the stub generation point of view - + // for example, 'kotlin.collections.MutableListIterator' contains the following (redundant) declarations: + // override fun next(): T + // override fun hasNext(): Boolean + // which cause stubs for 'next' and 'hasNext' to be generated in a 'abstract class A : ListIterator'. + // See https://youtrack.jetbrains.com/issue/KT-36724. + // In the ideal world, it should be enough to check that + // the given member function 'f' from 'MC' doesn't override anything from 'C'. + + mutableClass.functions + .map { it.owner } + .filter { memberFun -> + !memberFun.isFakeOverride || + (memberFun.modality == Modality.ABSTRACT && memberFun.overriddenSymbols.none { overriddenFun -> + overriddenFun.owner.parentAsClass.symbol == readOnlyClass + }) + } + .toHashSet() + } + } + private val preComputedStubs: Collection by lazy { with(context.ir.symbols) { listOf( - collection to mutableCollection, - set to mutableSet, - list to mutableList, - map to mutableMap, - mapEntry to mutableMapEntry, - iterable to mutableIterable, - iterator to mutableIterator, - listIterator to mutableListIterator - ).map { (readOnlyClass, mutableClass) -> - StubsForCollectionClass(readOnlyClass, mutableClass) - } + LazyStubsForCollectionClass(collection, mutableCollection), + LazyStubsForCollectionClass(set, mutableSet), + LazyStubsForCollectionClass(list, mutableList), + LazyStubsForCollectionClass(map, mutableMap), + LazyStubsForCollectionClass(mapEntry, mutableMapEntry), + LazyStubsForCollectionClass(iterable, mutableIterable), + LazyStubsForCollectionClass(iterator, mutableIterator), + LazyStubsForCollectionClass(listIterator, mutableListIterator) + ) } } - private val stubsCache = mutableMapOf>() + private val stubsCache = mutableMapOf>() - fun stubsForCollectionClasses(irClass: IrClass): Collection = + fun stubsForCollectionClasses(irClass: IrClass): List = stubsCache.getOrPut(irClass) { - if (irClass.isFromJava()) emptySet() - else preComputedStubs.filter { (readOnlyClass, mutableClass) -> - !irClass.symbol.isSubtypeOfClass(mutableClass) && - irClass.superTypes.any { it.isSubtypeOfClass(readOnlyClass) } - } + computeStubsForCollectionClasses(irClass) } + + private fun computeStubsForCollectionClasses(irClass: IrClass): List { + if (irClass.isFromJava()) return emptyList() + val stubs = preComputedStubs.filter { (readOnlyClass, mutableClass) -> + !irClass.symbol.isSubtypeOfClass(mutableClass) && + irClass.superTypes.any { it.isSubtypeOfClass(readOnlyClass) } + } + return stubs.filter { (readOnlyClass) -> + stubs.none { readOnlyClass != it.readOnlyClass && it.readOnlyClass.isSubtypeOfClass(readOnlyClass) } + } + } } \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractCollections.kt b/compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractCollections.kt new file mode 100644 index 00000000000..a3e90dca181 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractCollections.kt @@ -0,0 +1,14 @@ +// WITH_RUNTIME + +abstract class AIterD : AbstractIterator() + +abstract class ACollD : AbstractCollection() + +abstract class AMCollD : AbstractMutableCollection() + +abstract class ASetD : AbstractSet() + +abstract class AMSetD : AbstractMutableSet() + +abstract class AListD : AbstractList() + diff --git a/compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractCollections.txt b/compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractCollections.txt new file mode 100644 index 00000000000..5c006aa336b --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractCollections.txt @@ -0,0 +1,54 @@ +@kotlin.Metadata +public abstract class ACollD { + // source: 'inheritingFromAbstractCollections.kt' + public method (): void + public bridge method contains(p0: double): boolean + public bridge final method contains(p0: java.lang.Object): boolean + public method iterator(): java.util.Iterator +} + +@kotlin.Metadata +public abstract class AIterD { + // source: 'inheritingFromAbstractCollections.kt' + public method (): void +} + +@kotlin.Metadata +public abstract class AListD { + // source: 'inheritingFromAbstractCollections.kt' + public method (): void + public bridge method contains(p0: double): boolean + public bridge final method contains(p0: java.lang.Object): boolean + public bridge method indexOf(p0: double): int + public bridge final method indexOf(p0: java.lang.Object): int + public bridge method lastIndexOf(p0: double): int + public bridge final method lastIndexOf(p0: java.lang.Object): int +} + +@kotlin.Metadata +public abstract class AMCollD { + // source: 'inheritingFromAbstractCollections.kt' + public method (): void + public bridge method contains(p0: double): boolean + public bridge final method contains(p0: java.lang.Object): boolean + public bridge method remove(p0: double): boolean + public bridge final method remove(p0: java.lang.Object): boolean +} + +@kotlin.Metadata +public abstract class AMSetD { + // source: 'inheritingFromAbstractCollections.kt' + public method (): void + public bridge method contains(p0: double): boolean + public bridge final method contains(p0: java.lang.Object): boolean + public bridge method remove(p0: double): boolean + public bridge final method remove(p0: java.lang.Object): boolean +} + +@kotlin.Metadata +public abstract class ASetD { + // source: 'inheritingFromAbstractCollections.kt' + public method (): void + public bridge method contains(p0: double): boolean + public bridge final method contains(p0: java.lang.Object): boolean +} diff --git a/compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractMap.kt b/compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractMap.kt new file mode 100644 index 00000000000..42477cbfc77 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractMap.kt @@ -0,0 +1,5 @@ +// WITH_RUNTIME + +abstract class AMapSD : AbstractMap() + +abstract class AMMapSD : AbstractMutableMap() \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractMap.txt b/compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractMap.txt new file mode 100644 index 00000000000..b1f248a0427 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractMap.txt @@ -0,0 +1,25 @@ +@kotlin.Metadata +public abstract class AMMapSD { + // source: 'inheritingFromAbstractMap.kt' + public method (): void + public bridge final method containsKey(p0: java.lang.Object): boolean + public bridge method containsKey(p0: java.lang.String): boolean + public bridge method containsValue(p0: double): boolean + public bridge final method containsValue(p0: java.lang.Object): boolean + public bridge final method get(p0: java.lang.Object): java.lang.Object + public bridge method get(p0: java.lang.String): java.lang.Double + public bridge final method remove(p0: java.lang.Object): java.lang.Object + public bridge method remove(p0: java.lang.String): java.lang.Double +} + +@kotlin.Metadata +public abstract class AMapSD { + // source: 'inheritingFromAbstractMap.kt' + public method (): void + public bridge final method containsKey(p0: java.lang.Object): boolean + public bridge method containsKey(p0: java.lang.String): boolean + public bridge method containsValue(p0: double): boolean + public bridge final method containsValue(p0: java.lang.Object): boolean + public bridge final method get(p0: java.lang.Object): java.lang.Object + public bridge method get(p0: java.lang.String): java.lang.Double +} diff --git a/compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractMap_ir.txt b/compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractMap_ir.txt new file mode 100644 index 00000000000..b9b79d2fef4 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractMap_ir.txt @@ -0,0 +1,25 @@ +@kotlin.Metadata +public abstract class AMMapSD { + // source: 'inheritingFromAbstractMap.kt' + public method (): void + public bridge final method containsKey(p0: java.lang.Object): boolean + public bridge method containsKey(p0: java.lang.String): boolean + public bridge method containsValue(p0: double): boolean + public bridge final method containsValue(p0: java.lang.Object): boolean + public bridge final method get(p0: java.lang.Object): java.lang.Double + public bridge method get(p0: java.lang.String): java.lang.Double + public bridge final method remove(p0: java.lang.Object): java.lang.Double + public bridge method remove(p0: java.lang.String): java.lang.Double +} + +@kotlin.Metadata +public abstract class AMapSD { + // source: 'inheritingFromAbstractMap.kt' + public method (): void + public bridge final method containsKey(p0: java.lang.Object): boolean + public bridge method containsKey(p0: java.lang.String): boolean + public bridge method containsValue(p0: double): boolean + public bridge final method containsValue(p0: java.lang.Object): boolean + public bridge final method get(p0: java.lang.Object): java.lang.Double + public bridge method get(p0: java.lang.String): java.lang.Double +} diff --git a/compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractMutableList.kt b/compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractMutableList.kt new file mode 100644 index 00000000000..23ef37cb5fa --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractMutableList.kt @@ -0,0 +1,3 @@ +// WITH_RUNTIME + +abstract class AMListD : AbstractMutableList() diff --git a/compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractMutableList.txt b/compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractMutableList.txt new file mode 100644 index 00000000000..5d105afc626 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractMutableList.txt @@ -0,0 +1,15 @@ +@kotlin.Metadata +public abstract class AMListD { + // source: 'inheritingFromAbstractMutableList.kt' + public method (): void + public bridge method contains(p0: double): boolean + public bridge final method contains(p0: java.lang.Object): boolean + public bridge method indexOf(p0: double): int + public bridge final method indexOf(p0: java.lang.Object): int + public bridge method lastIndexOf(p0: double): int + public bridge final method lastIndexOf(p0: java.lang.Object): int + public bridge method remove(p0: double): boolean + public bridge final method remove(p0: int): double + public bridge final method remove(p0: java.lang.Object): boolean + public synthetic bridge method removeAt(p0: int): java.lang.Object +} diff --git a/compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractMutableList_ir.txt b/compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractMutableList_ir.txt new file mode 100644 index 00000000000..c51fc23b2d5 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractMutableList_ir.txt @@ -0,0 +1,16 @@ +@kotlin.Metadata +public abstract class AMListD { + // source: 'inheritingFromAbstractMutableList.kt' + public method (): void + public bridge method contains(p0: double): boolean + public bridge final method contains(p0: java.lang.Object): boolean + public bridge method indexOf(p0: double): int + public bridge final method indexOf(p0: java.lang.Object): int + public bridge method lastIndexOf(p0: double): int + public bridge final method lastIndexOf(p0: java.lang.Object): int + public bridge method remove(p0: double): boolean + public bridge final method remove(p0: int): double + public bridge final method remove(p0: java.lang.Object): boolean + public abstract method removeAt(p0: int): java.lang.Double + public synthetic bridge method removeAt(p0: int): java.lang.Object +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java index cd4e6763474..7bd91930ad2 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java @@ -339,6 +339,21 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest { runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/extendingAbstractCollection.kt"); } + @TestMetadata("inheritingFromAbstractCollections.kt") + public void testInheritingFromAbstractCollections() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractCollections.kt"); + } + + @TestMetadata("inheritingFromAbstractMap.kt") + public void testInheritingFromAbstractMap() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractMap.kt"); + } + + @TestMetadata("inheritingFromAbstractMutableList.kt") + public void testInheritingFromAbstractMutableList() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractMutableList.kt"); + } + @TestMetadata("mapOfPrimitivesFullJdk.kt") public void testMapOfPrimitivesFullJdk() throws Exception { runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/mapOfPrimitivesFullJdk.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java index 9db0cc1f2a7..429e304a2db 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java @@ -339,6 +339,21 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/extendingAbstractCollection.kt"); } + @TestMetadata("inheritingFromAbstractCollections.kt") + public void testInheritingFromAbstractCollections() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractCollections.kt"); + } + + @TestMetadata("inheritingFromAbstractMap.kt") + public void testInheritingFromAbstractMap() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractMap.kt"); + } + + @TestMetadata("inheritingFromAbstractMutableList.kt") + public void testInheritingFromAbstractMutableList() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/inheritingFromAbstractMutableList.kt"); + } + @TestMetadata("mapOfPrimitivesFullJdk.kt") public void testMapOfPrimitivesFullJdk() throws Exception { runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/mapOfPrimitivesFullJdk.kt");