diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/MemoizedInlineClassReplacements.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/MemoizedInlineClassReplacements.kt index 677b7260343..1407ef3875a 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/MemoizedInlineClassReplacements.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/MemoizedInlineClassReplacements.kt @@ -12,10 +12,11 @@ import org.jetbrains.kotlin.backend.common.ir.createDispatchReceiverParameter import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.codegen.classFileContainsMethod +import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface +import org.jetbrains.kotlin.backend.jvm.ir.isFromJava import org.jetbrains.kotlin.backend.jvm.ir.isStaticInlineClassReplacement import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi.mangledNameFor import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper -import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter @@ -70,6 +71,8 @@ class MemoizedInlineClassReplacements( when { it.isRemoveAtSpecialBuiltinStub() -> null + it.isInlineClassMemberFakeOverriddenFromDefaultJavaInterfaceMethod() -> + null it.origin == IrDeclarationOrigin.IR_BUILTINS_STUB -> createMethodReplacement(it) else -> @@ -94,6 +97,16 @@ class MemoizedInlineClassReplacements( valueParameters.size == 1 && valueParameters[0].type.isInt() + private fun IrFunction.isInlineClassMemberFakeOverriddenFromDefaultJavaInterfaceMethod(): Boolean { + if (this !is IrSimpleFunction) return false + if (!this.isFakeOverride) return false + val parentClass = parentClassOrNull ?: return false + if (!parentClass.isInline) return false + + val overridden = resolveFakeOverride() ?: return false + return overridden.isFromJava() && overridden.modality != Modality.ABSTRACT && overridden.parentAsClass.isJvmInterface + } + /** * Get the box function for an inline class. Concretely, this is a synthetic * static function named "box-impl" which takes an unboxed value and returns diff --git a/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollection/UIntArrayWithFullJdk.kt b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollection/UIntArrayWithFullJdk.kt new file mode 100644 index 00000000000..db0ce1f7989 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollection/UIntArrayWithFullJdk.kt @@ -0,0 +1,12 @@ +// FULL_JDK + +inline class UInt(val x: Int) + +inline class UIntArray(private val storage: IntArray) : Collection { + public override val size: Int get() = storage.size + + override operator fun iterator() = TODO() + override fun contains(element: UInt): Boolean = TODO() + override fun containsAll(elements: Collection): Boolean = TODO() + override fun isEmpty(): Boolean = TODO() +} \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollection/UIntArrayWithFullJdk.txt b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollection/UIntArrayWithFullJdk.txt new file mode 100644 index 00000000000..891268caf28 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollection/UIntArrayWithFullJdk.txt @@ -0,0 +1,57 @@ +@kotlin.Metadata +public final class UInt { + // source: 'UIntArrayWithFullJdk.kt' + private final field x: int + private synthetic method (p0: int): void + public synthetic final static method box-impl(p0: int): UInt + public static method constructor-impl(p0: int): int + public method equals(p0: java.lang.Object): boolean + public static method equals-impl(p0: int, p1: java.lang.Object): boolean + public final static method equals-impl0(p0: int, p1: int): boolean + public final method getX(): int + public method hashCode(): int + public static method hashCode-impl(p0: int): int + public method toString(): java.lang.String + public static method toString-impl(p0: int): java.lang.String + public synthetic final method unbox-impl(): int +} + +@kotlin.Metadata +public final class UIntArray { + // source: 'UIntArrayWithFullJdk.kt' + private final field storage: int[] + private synthetic method (p0: int[]): void + public synthetic method add(p0: java.lang.Object): boolean + public method add-fLmw4x8(p0: int): boolean + public method addAll(p0: java.util.Collection): boolean + public synthetic final static method box-impl(p0: int[]): UIntArray + public method clear(): void + public static @org.jetbrains.annotations.NotNull method constructor-impl(@org.jetbrains.annotations.NotNull p0: int[]): int[] + public bridge final method contains(p0: java.lang.Object): boolean + public method contains-fLmw4x8(p0: int): boolean + public static method contains-fLmw4x8(p0: int[], p1: int): boolean + public method containsAll(@org.jetbrains.annotations.NotNull p0: java.util.Collection): boolean + public static method containsAll-impl(p0: int[], @org.jetbrains.annotations.NotNull p1: java.util.Collection): boolean + public method equals(p0: java.lang.Object): boolean + public static method equals-impl(p0: int[], p1: java.lang.Object): boolean + public final static method equals-impl0(p0: int[], p1: int[]): boolean + public method getSize(): int + public static method getSize-impl(p0: int[]): int + public method hashCode(): int + public static method hashCode-impl(p0: int[]): int + public method isEmpty(): boolean + public static method isEmpty-impl(p0: int[]): boolean + public @org.jetbrains.annotations.NotNull method iterator(): java.lang.Void + public synthetic bridge method iterator(): java.util.Iterator + public static @org.jetbrains.annotations.NotNull method iterator-impl(p0: int[]): java.lang.Void + public method remove(p0: java.lang.Object): boolean + public method removeAll(p0: java.util.Collection): boolean + public method removeIf(p0: java.util.function.Predicate): 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[] + public method toString(): java.lang.String + public static method toString-impl(p0: int[]): java.lang.String + public synthetic final method unbox-impl(): int[] +} diff --git a/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollection/UIntArrayWithFullJdk_ir.txt b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollection/UIntArrayWithFullJdk_ir.txt new file mode 100644 index 00000000000..a455a1ff4a5 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollection/UIntArrayWithFullJdk_ir.txt @@ -0,0 +1,57 @@ +@kotlin.Metadata +public final class UInt { + // source: 'UIntArrayWithFullJdk.kt' + private final field x: int + private synthetic method (p0: int): void + public synthetic final static method box-impl(p0: int): UInt + public static method constructor-impl(p0: int): int + public method equals(p0: java.lang.Object): boolean + public static method equals-impl(p0: int, p1: java.lang.Object): boolean + public final static method equals-impl0(p0: int, p1: int): boolean + public final method getX(): int + public method hashCode(): int + public static method hashCode-impl(p0: int): int + public method toString(): java.lang.String + public static method toString-impl(p0: int): java.lang.String + public synthetic final method unbox-impl(): int +} + +@kotlin.Metadata +public final class UIntArray { + // source: 'UIntArrayWithFullJdk.kt' + private final @org.jetbrains.annotations.NotNull field storage: int[] + private synthetic method (p0: int[]): void + public synthetic bridge method add(p0: java.lang.Object): boolean + public method add-fLmw4x8(p0: int): boolean + public method addAll(p0: java.util.Collection): boolean + public synthetic final static method box-impl(p0: int[]): UIntArray + public method clear(): void + public static @org.jetbrains.annotations.NotNull method constructor-impl(@org.jetbrains.annotations.NotNull p0: int[]): int[] + public synthetic bridge method contains(p0: java.lang.Object): boolean + public static method contains-fLmw4x8(@org.jetbrains.annotations.NotNull p0: int[], p1: int): boolean + public method contains-fLmw4x8(p0: int): boolean + public method containsAll(@org.jetbrains.annotations.NotNull p0: java.util.Collection): boolean + public static method containsAll-impl(@org.jetbrains.annotations.NotNull p0: int[], @org.jetbrains.annotations.NotNull p1: java.util.Collection): boolean + public method equals(p0: java.lang.Object): boolean + public static method equals-impl(p0: int[], p1: java.lang.Object): boolean + public final static method equals-impl0(p0: int[], p1: int[]): boolean + public method getSize(): int + public static method getSize-impl(@org.jetbrains.annotations.NotNull p0: int[]): int + public method hashCode(): int + public static method hashCode-impl(p0: int[]): int + public method isEmpty(): boolean + public static method isEmpty-impl(@org.jetbrains.annotations.NotNull p0: int[]): boolean + public @org.jetbrains.annotations.NotNull method iterator(): java.lang.Void + public synthetic bridge method iterator(): java.util.Iterator + public static @org.jetbrains.annotations.NotNull method iterator-impl(@org.jetbrains.annotations.NotNull p0: int[]): java.lang.Void + public method remove(p0: java.lang.Object): boolean + public method removeAll(p0: java.util.Collection): boolean + public method removeIf(p0: java.util.function.Predicate): boolean + public method retainAll(p0: java.util.Collection): boolean + public synthetic bridge method size(): int + public method toArray(): java.lang.Object[] + public method toArray(p0: java.lang.Object[]): java.lang.Object[] + public method toString(): java.lang.String + public static method toString-impl(p0: int[]): java.lang.String + public synthetic final method unbox-impl(): int[] +} diff --git a/compiler/testData/codegen/bytecodeListing/inlineClasses/javaDefaultInterfaceMember.kt b/compiler/testData/codegen/bytecodeListing/inlineClasses/javaDefaultInterfaceMember.kt new file mode 100644 index 00000000000..adf140afc0e --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/inlineClasses/javaDefaultInterfaceMember.kt @@ -0,0 +1,22 @@ +// JVM_TARGET: 1.8 +// FILE: javaDefaultInterfaceMember.kt +interface KFoo2 : JIFoo + +interface KFooUnrelated { + fun foo() +} + +interface KFoo3 : KFoo2, KFooUnrelated { + override fun foo() {} +} + +inline class Test1(val x: Int) : JIFoo + +inline class Test2(val x: Int) : KFoo2 + +inline class Test3(val x: Int) : KFoo3 + +// FILE: JIFoo.java +public interface JIFoo { + default void foo() {} +} diff --git a/compiler/testData/codegen/bytecodeListing/inlineClasses/javaDefaultInterfaceMember.txt b/compiler/testData/codegen/bytecodeListing/inlineClasses/javaDefaultInterfaceMember.txt new file mode 100644 index 00000000000..daacfa6762a --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/inlineClasses/javaDefaultInterfaceMember.txt @@ -0,0 +1,80 @@ +@kotlin.Metadata +public interface KFoo2 { + // source: 'javaDefaultInterfaceMember.kt' +} + +@kotlin.Metadata +public final class KFoo3$DefaultImpls { + // source: 'javaDefaultInterfaceMember.kt' + public static method foo(@org.jetbrains.annotations.NotNull p0: KFoo3): void + public final inner class KFoo3$DefaultImpls +} + +@kotlin.Metadata +public interface KFoo3 { + // source: 'javaDefaultInterfaceMember.kt' + public abstract method foo(): void + public final inner class KFoo3$DefaultImpls +} + +@kotlin.Metadata +public interface KFooUnrelated { + // source: 'javaDefaultInterfaceMember.kt' + public abstract method foo(): void +} + +@kotlin.Metadata +public final class Test1 { + // source: 'javaDefaultInterfaceMember.kt' + private final field x: int + private synthetic method (p0: int): void + public synthetic final static method box-impl(p0: int): Test1 + public static method constructor-impl(p0: int): int + public method equals(p0: java.lang.Object): boolean + public static method equals-impl(p0: int, p1: java.lang.Object): boolean + public final static method equals-impl0(p0: int, p1: int): boolean + public final method getX(): int + public method hashCode(): int + public static method hashCode-impl(p0: int): int + public method toString(): java.lang.String + public static method toString-impl(p0: int): java.lang.String + public synthetic final method unbox-impl(): int +} + +@kotlin.Metadata +public final class Test2 { + // source: 'javaDefaultInterfaceMember.kt' + private final field x: int + private synthetic method (p0: int): void + public synthetic final static method box-impl(p0: int): Test2 + public static method constructor-impl(p0: int): int + public method equals(p0: java.lang.Object): boolean + public static method equals-impl(p0: int, p1: java.lang.Object): boolean + public final static method equals-impl0(p0: int, p1: int): boolean + public final method getX(): int + public method hashCode(): int + public static method hashCode-impl(p0: int): int + public method toString(): java.lang.String + public static method toString-impl(p0: int): java.lang.String + public synthetic final method unbox-impl(): int +} + +@kotlin.Metadata +public final class Test3 { + // source: 'javaDefaultInterfaceMember.kt' + private final field x: int + private synthetic method (p0: int): void + public synthetic final static method box-impl(p0: int): Test3 + public static method constructor-impl(p0: int): int + public method equals(p0: java.lang.Object): boolean + public static method equals-impl(p0: int, p1: java.lang.Object): boolean + public final static method equals-impl0(p0: int, p1: int): boolean + public method foo(): void + public static method foo-impl(p0: int): void + public final method getX(): int + public method hashCode(): int + public static method hashCode-impl(p0: int): int + public method toString(): java.lang.String + public static method toString-impl(p0: int): java.lang.String + public synthetic final method unbox-impl(): int +} diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java index 1a8ec1ca579..420cb96aec1 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java @@ -982,6 +982,11 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest { runTest("compiler/testData/codegen/bytecodeListing/inlineClasses/inlineClassWithManyKindsOfMembers.kt"); } + @TestMetadata("javaDefaultInterfaceMember.kt") + public void testJavaDefaultInterfaceMember() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/inlineClasses/javaDefaultInterfaceMember.kt"); + } + @TestMetadata("jvmName.kt") public void testJvmName() throws Exception { runTest("compiler/testData/codegen/bytecodeListing/inlineClasses/jvmName.kt"); @@ -1123,6 +1128,11 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest { public void testSet() throws Exception { runTest("compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollection/set.kt"); } + + @TestMetadata("UIntArrayWithFullJdk.kt") + public void testUIntArrayWithFullJdk() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollection/UIntArrayWithFullJdk.kt"); + } } @TestMetadata("compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass") diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java index 51cdf696c7d..fd3bfb6d9ca 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java @@ -952,6 +952,11 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes runTest("compiler/testData/codegen/bytecodeListing/inlineClasses/inlineClassWithManyKindsOfMembers.kt"); } + @TestMetadata("javaDefaultInterfaceMember.kt") + public void testJavaDefaultInterfaceMember() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/inlineClasses/javaDefaultInterfaceMember.kt"); + } + @TestMetadata("jvmName.kt") public void testJvmName() throws Exception { runTest("compiler/testData/codegen/bytecodeListing/inlineClasses/jvmName.kt"); @@ -1093,6 +1098,11 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes public void testSet() throws Exception { runTest("compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollection/set.kt"); } + + @TestMetadata("UIntArrayWithFullJdk.kt") + public void testUIntArrayWithFullJdk() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollection/UIntArrayWithFullJdk.kt"); + } } @TestMetadata("compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass")