diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt index 31f2605bdf8..552557361e4 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt @@ -107,6 +107,16 @@ class JvmBackendContext( internal val hiddenConstructors = mutableMapOf() internal val collectionStubComputer = CollectionStubComputer(this) + + private val overridesWithoutStubs = HashMap>() + + fun recordOverridesWithoutStubs(function: IrSimpleFunction) { + overridesWithoutStubs[function] = function.overriddenSymbols.toList() + } + + fun getOverridesWithoutStubs(function: IrSimpleFunction): List = + overridesWithoutStubs.getOrElse(function) { function.overriddenSymbols } + internal val bridgeLoweringCache = BridgeLowering.BridgeLoweringCache(this) internal val functionsWithSpecialBridges: MutableSet = HashSet() diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt index 31e3a2d918c..5ad6d6c6fd8 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.codegen.state.JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_N import org.jetbrains.kotlin.codegen.state.extractTypeMappingModeFromAnnotation import org.jetbrains.kotlin.codegen.state.isMethodWithDeclarationSiteWildcardsFqName import org.jetbrains.kotlin.descriptors.DescriptorVisibilities +import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyClass import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyFunction @@ -257,7 +258,9 @@ class MethodSignatureMapper(private val context: JvmBackendContext) { val signature = sw.makeJvmMethodSignature(mapFunctionName(function, skipSpecial)) val specialSignatureInfo = - with(BuiltinMethodsWithSpecialGenericSignature) { function.toIrBasedDescriptor().getSpecialSignatureInfo() } + with(BuiltinMethodsWithSpecialGenericSignature) { + function.toIrBasedDescriptorWithOriginalOverrides().getSpecialSignatureInfo() + } // Old back-end doesn't patch generic signatures if corresponding function had special bridges. // See org.jetbrains.kotlin.codegen.FunctionCodegen#hasSpecialBridgeMethod and its usage. @@ -272,6 +275,29 @@ class MethodSignatureMapper(private val context: JvmBackendContext) { return signature } + private fun IrFunction.toIrBasedDescriptorWithOriginalOverrides(): FunctionDescriptor = + when (this) { + is IrConstructor -> + toIrBasedDescriptor() + is IrSimpleFunction -> + if (isPropertyAccessor) + toIrBasedDescriptor() + else + IrBasedSimpleFunctionDescriptorWithOriginalOverrides(this, context) + else -> + throw AssertionError("Unexpected function kind: $this") + } + + private class IrBasedSimpleFunctionDescriptorWithOriginalOverrides( + owner: IrSimpleFunction, + private val context: JvmBackendContext + ) : IrBasedSimpleFunctionDescriptor(owner) { + override fun getOverriddenDescriptors(): List = + context.getOverridesWithoutStubs(owner).map { + IrBasedSimpleFunctionDescriptorWithOriginalOverrides(it.owner, context) + } + } + // Boxing is only necessary for 'remove(E): Boolean' of a MutableCollection implementation. // Otherwise this method might clash with 'remove(I): E' defined in the java.util.List JDK interface (mapped to kotlin 'removeAt'). internal fun shouldBoxSingleValueParameterForSpecialCaseOfRemove(irFunction: IrFunction): Boolean { 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 ec3f60ba481..66a88db287d 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 @@ -69,10 +69,16 @@ internal class CollectionStubMethodLowering(val context: JvmBackendContext) : Cl val existingOverrides = relevantMembers.filter { isEffectivelyOverriddenBy(stub, it) } if (existingOverrides.isNotEmpty()) { - // In the case that we find a defined method that matches the stub signature, - // we add the overridden symbols to that defined method, - // so that bridge lowering can still generate correct bridge for that method. - existingOverrides.forEach { it.overriddenSymbols += stub.overriddenSymbols } + existingOverrides.forEach { + // In the case that we find a defined method that matches the stub signature, + // we add the overridden symbols to that defined method, + // so that bridge lowering can still generate correct bridge for that method. + // However, we still need to keep track of the original overrides + // so that special built-in signature mapping doesn't confuse it with a method + // that actually requires signature patching. + context.recordOverridesWithoutStubs(it) + it.overriddenSymbols += stub.overriddenSymbols + } // We don't add a throwing stub if it's effectively overridden by an existing function. continue } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrBasedDescriptors.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrBasedDescriptors.kt index f4fd06ee9bf..2134fcf7ac5 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrBasedDescriptors.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrBasedDescriptors.kt @@ -10,14 +10,15 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor -import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyFunction import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyProperty import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol +import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* @@ -363,9 +364,9 @@ open class IrBasedVariableDescriptorWithAccessor(owner: IrLocalDelegatedProperty override fun isLateInit(): Boolean = false override val getter: VariableAccessorDescriptor? - get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates. + get() = TODO("not implemented") override val setter: VariableAccessorDescriptor? - get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates. + get() = TODO("not implemented") override val isDelegated: Boolean = true } @@ -416,11 +417,11 @@ open class IrBasedSimpleFunctionDescriptor(owner: IrSimpleFunction) : SimpleFunc else CallableMemberDescriptor.Kind.SYNTHESIZED override fun copy( - newOwner: DeclarationDescriptor?, - modality: Modality?, - visibility: DescriptorVisibility?, - kind: CallableMemberDescriptor.Kind?, - copyOverrides: Boolean + newOwner: DeclarationDescriptor?, + modality: Modality?, + visibility: DescriptorVisibility?, + kind: CallableMemberDescriptor.Kind?, + copyOverrides: Boolean ): Nothing { TODO("not implemented") } @@ -484,11 +485,11 @@ open class IrBasedClassConstructorDescriptor(owner: IrConstructor) : ClassConstr } override fun copy( - newOwner: DeclarationDescriptor, - modality: Modality, - visibility: DescriptorVisibility, - kind: CallableMemberDescriptor.Kind, - copyOverrides: Boolean + newOwner: DeclarationDescriptor, + modality: Modality, + visibility: DescriptorVisibility, + kind: CallableMemberDescriptor.Kind, + copyOverrides: Boolean ): ClassConstructorDescriptor { throw UnsupportedOperationException() } @@ -556,11 +557,12 @@ open class IrBasedClassConstructorDescriptor(owner: IrConstructor) : ClassConstr fun IrConstructor.toIrBasedDescriptor() = IrBasedClassConstructorDescriptor(this) -fun IrFunction.toIrBasedDescriptor(): FunctionDescriptor = when(this) { - is IrSimpleFunction -> toIrBasedDescriptor() - is IrConstructor -> toIrBasedDescriptor() - else -> error("Unknown function kind") -} +fun IrFunction.toIrBasedDescriptor(): FunctionDescriptor = + when (this) { + is IrSimpleFunction -> toIrBasedDescriptor() + is IrConstructor -> toIrBasedDescriptor() + else -> error("Unknown function kind") + } open class IrBasedClassDescriptor(owner: IrClass) : ClassDescriptor, IrBasedDeclarationDescriptor(owner) { override fun getName() = owner.name @@ -590,7 +592,8 @@ open class IrBasedClassDescriptor(owner: IrClass) : ClassDescriptor, IrBasedDecl override fun getModality() = owner.modality - override fun getCompanionObjectDescriptor() = owner.declarations.filterIsInstance().firstOrNull { it.isCompanion }?.toIrBasedDescriptor() + override fun getCompanionObjectDescriptor() = + owner.declarations.filterIsInstance().firstOrNull { it.isCompanion }?.toIrBasedDescriptor() override fun getVisibility() = owner.visibility @@ -778,11 +781,11 @@ open class IrBasedPropertyDescriptor(owner: IrProperty) : PropertyDescriptor, Ir override fun getOverriddenDescriptors(): MutableCollection = mutableListOf() override fun copy( - newOwner: DeclarationDescriptor?, - modality: Modality?, - visibility: DescriptorVisibility?, - kind: CallableMemberDescriptor.Kind?, - copyOverrides: Boolean + newOwner: DeclarationDescriptor?, + modality: Modality?, + visibility: DescriptorVisibility?, + kind: CallableMemberDescriptor.Kind?, + copyOverrides: Boolean ): CallableMemberDescriptor { TODO("not implemented") } @@ -822,13 +825,15 @@ open class IrBasedPropertyDescriptor(owner: IrProperty) : PropertyDescriptor, Ir override fun isVar() = owner.isVar - override fun getDispatchReceiverParameter() = owner.getter?.dispatchReceiverParameter?.toIrBasedDescriptor() as? ReceiverParameterDescriptor + override fun getDispatchReceiverParameter() = + owner.getter?.dispatchReceiverParameter?.toIrBasedDescriptor() as? ReceiverParameterDescriptor override fun isConst() = owner.isConst override fun isLateInit() = owner.isLateinit - override fun getExtensionReceiverParameter() = owner.getter?.extensionReceiverParameter?.toIrBasedDescriptor() as? ReceiverParameterDescriptor + override fun getExtensionReceiverParameter() = + owner.getter?.extensionReceiverParameter?.toIrBasedDescriptor() as? ReceiverParameterDescriptor override fun isExternal() = owner.isExternal @@ -973,11 +978,11 @@ open class IrBasedFieldDescriptor(owner: IrField) : PropertyDescriptor, IrBasedD override fun getOverriddenDescriptors(): MutableCollection = mutableListOf() override fun copy( - newOwner: DeclarationDescriptor?, - modality: Modality?, - visibility: DescriptorVisibility?, - kind: CallableMemberDescriptor.Kind?, - copyOverrides: Boolean + newOwner: DeclarationDescriptor?, + modality: Modality?, + visibility: DescriptorVisibility?, + kind: CallableMemberDescriptor.Kind?, + copyOverrides: Boolean ): CallableMemberDescriptor { TODO("not implemented") } diff --git a/compiler/testData/codegen/bytecodeListing/collectionStubs/stubLikeMethodSignatures.kt b/compiler/testData/codegen/bytecodeListing/collectionStubs/stubLikeMethodSignatures.kt new file mode 100644 index 00000000000..c0c0db5053a --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/collectionStubs/stubLikeMethodSignatures.kt @@ -0,0 +1,28 @@ +// WITH_SIGNATURES + +class MyList(val v: T): List { + override val size: Int get() = 0 + override fun isEmpty(): Boolean = true + override fun contains(o: T): Boolean = false + override fun iterator(): Iterator = throw Error() + override fun containsAll(c: Collection): Boolean = false + override fun get(index: Int): T = v + override fun indexOf(o: T): Int = -1 + override fun lastIndexOf(o: T): Int = -1 + override fun listIterator(): ListIterator = throw Error() + override fun listIterator(index: Int): ListIterator = throw Error() + override fun subList(fromIndex: Int, toIndex: Int): List = throw Error() + override fun hashCode(): Int = 0 + override fun equals(other: Any?): Boolean = false + + public fun add(e: T): Boolean = true + public fun remove(o: T): Boolean = true + public fun addAll(c: Collection): Boolean = true + public fun addAll(index: Int, c: Collection): Boolean = true + public fun removeAll(c: Collection): Boolean = true + public fun retainAll(c: Collection): Boolean = true + public fun clear() {} + public fun set(index: Int, element: T): T = element + public fun add(index: Int, element: T) {} + public fun removeAt(index: Int): T = v +} \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeListing/collectionStubs/stubLikeMethodSignatures.txt b/compiler/testData/codegen/bytecodeListing/collectionStubs/stubLikeMethodSignatures.txt new file mode 100644 index 00000000000..1895c74c7ca --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/collectionStubs/stubLikeMethodSignatures.txt @@ -0,0 +1,34 @@ +@kotlin.Metadata +public final class<Ljava/lang/Object;Ljava/util/List;Lkotlin/jvm/internal/markers/KMappedMarker;> MyList { + // source: 'stubLikeMethodSignatures.kt' + public @org.jetbrains.annotations.NotNull <()Ljava/util/Iterator;> method iterator(): java.util.Iterator + public @org.jetbrains.annotations.NotNull <()Ljava/util/ListIterator;> method listIterator(): java.util.ListIterator + public final <()TT;> method getV(): java.lang.Object + public @org.jetbrains.annotations.NotNull <(I)Ljava/util/ListIterator;> method listIterator(p0: int): java.util.ListIterator + public <(I)TT;> method get(p0: int): java.lang.Object + public bridge final <(I)TT;> method remove(p0: int): java.lang.Object + public final <(I)TT;> method removeAt(p0: int): java.lang.Object + public @org.jetbrains.annotations.NotNull <(II)Ljava/util/List;> method subList(p0: int, p1: int): java.util.List + public final <(ILjava/util/Collection<+TT;>;)Z> method addAll(p0: int, @org.jetbrains.annotations.NotNull p1: java.util.Collection): boolean + public final <(ITT;)TT;> method set(p0: int, p1: java.lang.Object): java.lang.Object + public final <(ITT;)V> method add(p0: int, p1: java.lang.Object): void + public <(Ljava/util/Collection<+Ljava/lang/Object;>;)Z> method containsAll(@org.jetbrains.annotations.NotNull p0: java.util.Collection): boolean + public final <(Ljava/util/Collection<+TT;>;)Z> method addAll(@org.jetbrains.annotations.NotNull p0: java.util.Collection): boolean + public final <(Ljava/util/Collection<+TT;>;)Z> method removeAll(@org.jetbrains.annotations.NotNull p0: java.util.Collection): boolean + public final <(Ljava/util/Collection<+TT;>;)Z> method retainAll(@org.jetbrains.annotations.NotNull p0: java.util.Collection): boolean + public <(TT;)V> method (p0: java.lang.Object): void + public final <(TT;)Z> method add(p0: java.lang.Object): boolean + public final <(TT;)Z> method remove(p0: java.lang.Object): boolean + public <([TT;)[TT;> method toArray(p0: java.lang.Object[]): java.lang.Object[] + public final method clear(): void + public method contains(p0: java.lang.Object): boolean + public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean + public method getSize(): int + public method hashCode(): int + public method indexOf(p0: java.lang.Object): int + public method isEmpty(): boolean + public method lastIndexOf(p0: java.lang.Object): int + public bridge final method size(): int + public method toArray(): java.lang.Object[] + private final field v: java.lang.Object +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java index 7bd91930ad2..d3dd1be808d 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java @@ -419,6 +419,11 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest { runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/stubForAbstractFunWithCovariantOverride.kt"); } + @TestMetadata("stubLikeMethodSignatures.kt") + public void testStubLikeMethodSignatures() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/stubLikeMethodSignatures.kt"); + } + @TestMetadata("stubsFromSuperclass.kt") public void testStubsFromSuperclass() throws Exception { runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/stubsFromSuperclass.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java index 429e304a2db..a2f7ee35ff7 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java @@ -419,6 +419,11 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/stubForAbstractFunWithCovariantOverride.kt"); } + @TestMetadata("stubLikeMethodSignatures.kt") + public void testStubLikeMethodSignatures() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/stubLikeMethodSignatures.kt"); + } + @TestMetadata("stubsFromSuperclass.kt") public void testStubsFromSuperclass() throws Exception { runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/stubsFromSuperclass.kt");