diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt index fbae8ae6c38..a488b037c10 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt @@ -156,6 +156,7 @@ fun IrSimpleFunction.isCompiledToJvmDefault(jvmDefaultMode: JvmDefaultMode): Boo assert(!isFakeOverride && parentAsClass.isInterface && modality != Modality.ABSTRACT) { "`isCompiledToJvmDefault` should be called on non-fakeoverrides and non-abstract methods from interfaces ${ir2string(this)}" } + if (origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB) return false if (hasJvmDefault()) return true val parentDescriptor = propertyIfAccessor.parentAsClass.descriptor if (parentDescriptor !is DeserializedClassDescriptor) return jvmDefaultMode.forAllMethodsWithBody diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InheritedDefaultMethodsOnClassesLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InheritedDefaultMethodsOnClassesLowering.kt index 83fac0e447a..4e15f8f7e21 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InheritedDefaultMethodsOnClassesLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InheritedDefaultMethodsOnClassesLowering.kt @@ -171,19 +171,21 @@ private class InterfaceDefaultCallsLowering(val context: JvmBackendContext) : Ir } } -private fun IrSimpleFunction.isDefinitelyNotDefaultImplsMethod(jvmDefaultMode: JvmDefaultMode): Boolean { - if (resolveFakeOverride()?.run { - origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB || isCompiledToJvmDefault( - jvmDefaultMode - ) - } != false) return true - - return origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER || +internal fun IrSimpleFunction.isDefinitelyNotDefaultImplsMethod( + jvmDefaultMode: JvmDefaultMode, + implementation: IrSimpleFunction? = resolveFakeOverride() +): Boolean = + implementation == null || + implementation.origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB || + implementation.isCompiledToJvmDefault(jvmDefaultMode) || + origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER || hasAnnotation(PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME) || - (name.asString() == "clone" && - parent.safeAs()?.fqNameWhenAvailable?.asString() == "kotlin.Cloneable" && - valueParameters.isEmpty()) -} + isCloneableClone() + +private fun IrSimpleFunction.isCloneableClone(): Boolean = + name.asString() == "clone" && + parent.safeAs()?.fqNameWhenAvailable?.asString() == "kotlin.Cloneable" && + valueParameters.isEmpty() internal val interfaceObjectCallsPhase = makeIrFilePhase( lowering = ::InterfaceObjectCallsLowering, diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceLowering.kt index bf76cc2213e..5e53baf0f9f 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceLowering.kt @@ -105,18 +105,17 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran when { Visibilities.isPrivate(implementation.visibility) || implementation.isMethodOfAny() -> continue@loop - !implementation.isCompiledToJvmDefault(jvmDefaultMode) -> { + !function.isDefinitelyNotDefaultImplsMethod(jvmDefaultMode, implementation) -> { val defaultImpl = createDefaultImpl(function) val superImpl = firstSuperMethodFromKotlin(function, implementation) context.declarationFactory.getDefaultImplsFunction(superImpl.owner).also { defaultImpl.bridgeToStatic(it) } } - jvmDefaultMode.isCompatibility -> { + jvmDefaultMode.isCompatibility && implementation.isCompiledToJvmDefault(jvmDefaultMode) -> { val defaultImpl = createDefaultImpl(function) defaultImpl.bridgeViaAccessorTo(function) } - // else -> Do nothing. } } diff --git a/compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/noDefaultImplsOnEmptySubInterface.kt b/compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/noDefaultImplsOnEmptySubInterface.kt new file mode 100644 index 00000000000..f9be1f3cf58 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/noDefaultImplsOnEmptySubInterface.kt @@ -0,0 +1,18 @@ +// !JVM_DEFAULT_MODE: all-compatibility +// JVM_TARGET: 1.8 +// FULL_JDK +// FILE: J.java + +public interface J { + default void foo() {} +} + +// FILE: K.kt + +interface K : J + +interface MyList : MutableList +interface MySet : MutableSet +interface MyMap : MutableMap + +interface MyMap2 : MyMap diff --git a/compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/noDefaultImplsOnEmptySubInterface.txt b/compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/noDefaultImplsOnEmptySubInterface.txt new file mode 100644 index 00000000000..105681415e2 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/noDefaultImplsOnEmptySubInterface.txt @@ -0,0 +1,14 @@ +@kotlin.Metadata +public interface K + +@kotlin.Metadata +public interface MyList + +@kotlin.Metadata +public interface MyMap + +@kotlin.Metadata +public interface MyMap2 + +@kotlin.Metadata +public interface MySet diff --git a/compiler/testData/codegen/bytecodeListing/specialBridges/noDefaultImplsOnEmptySubInterface.kt b/compiler/testData/codegen/bytecodeListing/specialBridges/noDefaultImplsOnEmptySubInterface.kt new file mode 100644 index 00000000000..ac6b8f0d3fd --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/specialBridges/noDefaultImplsOnEmptySubInterface.kt @@ -0,0 +1,17 @@ +// JVM_TARGET: 1.8 +// FULL_JDK +// FILE: J.java + +public interface J { + default void foo() {} +} + +// FILE: K.kt + +interface K : J + +interface MyList : MutableList +interface MySet : MutableSet +interface MyMap : MutableMap + +interface MyMap2 : MyMap diff --git a/compiler/testData/codegen/bytecodeListing/specialBridges/noDefaultImplsOnEmptySubInterface.txt b/compiler/testData/codegen/bytecodeListing/specialBridges/noDefaultImplsOnEmptySubInterface.txt new file mode 100644 index 00000000000..105681415e2 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/specialBridges/noDefaultImplsOnEmptySubInterface.txt @@ -0,0 +1,14 @@ +@kotlin.Metadata +public interface K + +@kotlin.Metadata +public interface MyList + +@kotlin.Metadata +public interface MyMap + +@kotlin.Metadata +public interface MyMap2 + +@kotlin.Metadata +public interface MySet diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java index 43e000337a7..6dbe086f617 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java @@ -433,6 +433,50 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest { } } + @TestMetadata("compiler/testData/codegen/bytecodeListing/jvm8") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Jvm8 extends AbstractBytecodeListingTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInJvm8() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/jvm8"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @TestMetadata("compiler/testData/codegen/bytecodeListing/jvm8/defaults") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Defaults extends AbstractBytecodeListingTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInDefaults() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/jvm8/defaults"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @TestMetadata("compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class AllCompatibility extends AbstractBytecodeListingTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInAllCompatibility() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @TestMetadata("noDefaultImplsOnEmptySubInterface.kt") + public void testNoDefaultImplsOnEmptySubInterface() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/noDefaultImplsOnEmptySubInterface.kt"); + } + } + } + } + @TestMetadata("compiler/testData/codegen/bytecodeListing/main") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -506,6 +550,11 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest { runTest("compiler/testData/codegen/bytecodeListing/specialBridges/contains.kt"); } + @TestMetadata("noDefaultImplsOnEmptySubInterface.kt") + public void testNoDefaultImplsOnEmptySubInterface() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/specialBridges/noDefaultImplsOnEmptySubInterface.kt"); + } + @TestMetadata("noSpecialBridgeIfPresentInSuperClass.kt") public void testNoSpecialBridgeIfPresentInSuperClass() throws Exception { runTest("compiler/testData/codegen/bytecodeListing/specialBridges/noSpecialBridgeIfPresentInSuperClass.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java index 0ade53844bb..115d9edd9bc 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java @@ -403,6 +403,50 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes } } + @TestMetadata("compiler/testData/codegen/bytecodeListing/jvm8") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Jvm8 extends AbstractIrBytecodeListingTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath); + } + + public void testAllFilesPresentInJvm8() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/jvm8"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @TestMetadata("compiler/testData/codegen/bytecodeListing/jvm8/defaults") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Defaults extends AbstractIrBytecodeListingTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath); + } + + public void testAllFilesPresentInDefaults() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/jvm8/defaults"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @TestMetadata("compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class AllCompatibility extends AbstractIrBytecodeListingTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath); + } + + public void testAllFilesPresentInAllCompatibility() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @TestMetadata("noDefaultImplsOnEmptySubInterface.kt") + public void testNoDefaultImplsOnEmptySubInterface() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/noDefaultImplsOnEmptySubInterface.kt"); + } + } + } + } + @TestMetadata("compiler/testData/codegen/bytecodeListing/main") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -476,6 +520,11 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes runTest("compiler/testData/codegen/bytecodeListing/specialBridges/contains.kt"); } + @TestMetadata("noDefaultImplsOnEmptySubInterface.kt") + public void testNoDefaultImplsOnEmptySubInterface() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/specialBridges/noDefaultImplsOnEmptySubInterface.kt"); + } + @TestMetadata("noSpecialBridgeIfPresentInSuperClass.kt") public void testNoSpecialBridgeIfPresentInSuperClass() throws Exception { runTest("compiler/testData/codegen/bytecodeListing/specialBridges/noSpecialBridgeIfPresentInSuperClass.kt");