From ea58c858d1f5ba78e5b9dde718bfd03b23c932a8 Mon Sep 17 00:00:00 2001 From: Mikhael Bogdanov Date: Thu, 2 Dec 2021 16:04:08 +0100 Subject: [PATCH] JvmDefault. Support @JvmDefaultWithCompatibility annotation #KT-48217 Fixed --- .../serialization/JvmSerializerExtension.kt | 5 ++- .../FirBlackBoxCodegenTestGenerated.java | 22 ++++++++++++ .../jvm/annotations/jvmAnnotationUtil.kt | 3 ++ .../backend/jvm/lower/InterfaceLowering.kt | 4 ++- .../kotlin/backend/jvm/ir/JvmIrUtils.kt | 2 ++ .../withCompatibility/defaultArgs.kt | 22 ++++++++++++ .../withCompatibility/defaultArgs.txt | 29 +++++++++++++++ .../withCompatibility/simple.kt | 33 +++++++++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 22 ++++++++++++ .../IrBlackBoxCodegenTestGenerated.java | 22 ++++++++++++ .../LightAnalysisModeTestGenerated.java | 23 ++++++++++++ .../src/org/jetbrains/kotlin/name/JvmNames.kt | 1 + .../metadata/jvm/deserialization/JvmFlags.kt | 4 +-- .../js/test/JsCodegenBoxTestGenerated.java | 10 ++++++ .../test/ir/IrJsCodegenBoxTestGenerated.java | 10 ++++++ .../IrCodegenBoxWasmTestGenerated.java | 13 +++++++ .../stdlib/jvm/src/kotlin/jvm/JvmDefault.kt | 10 ++++++ .../kotlin-stdlib-runtime-merged.txt | 3 ++ .../kotlinp/test/KotlinpTestGenerated.java | 10 ++++++ .../testData/jvmDefault/withCompatibility.kt | 8 +++++ .../testData/jvmDefault/withCompatibility.txt | 35 +++++++++++++++++++ .../jvmDefault/withoutCompatibility.kt | 7 ++++ .../jvmDefault/withoutCompatibility.txt | 28 +++++++++++++++ .../NativeExtBlackBoxTestGenerated.java | 23 ++++++++++++ 24 files changed, 345 insertions(+), 4 deletions(-) create mode 100644 compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility/defaultArgs.kt create mode 100644 compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility/defaultArgs.txt create mode 100644 compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility/simple.kt create mode 100644 libraries/tools/kotlinp/testData/jvmDefault/withCompatibility.kt create mode 100644 libraries/tools/kotlinp/testData/jvmDefault/withCompatibility.txt create mode 100644 libraries/tools/kotlinp/testData/jvmDefault/withoutCompatibility.kt create mode 100644 libraries/tools/kotlinp/testData/jvmDefault/withoutCompatibility.txt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/serialization/JvmSerializerExtension.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/serialization/JvmSerializerExtension.kt index 5962bff3c23..5c41ac33cc7 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/serialization/JvmSerializerExtension.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/serialization/JvmSerializerExtension.kt @@ -31,6 +31,8 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils.isInterface import org.jetbrains.kotlin.resolve.descriptorUtil.classId import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyPrivateApi import org.jetbrains.kotlin.resolve.descriptorUtil.nonSourceAnnotations +import org.jetbrains.kotlin.resolve.jvm.annotations.hasJvmDefaultNoCompatibilityAnnotation +import org.jetbrains.kotlin.resolve.jvm.annotations.hasJvmDefaultWithCompatibilityAnnotation import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForParameterTypes import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForReturnType import org.jetbrains.kotlin.serialization.DescriptorSerializer @@ -98,7 +100,8 @@ class JvmSerializerExtension @JvmOverloads constructor( JvmProtoBuf.jvmClassFlags, JvmFlags.getClassFlags( jvmDefaultMode.forAllMethodsWithBody, - JvmDefaultMode.ALL_COMPATIBILITY == jvmDefaultMode + (JvmDefaultMode.ALL_COMPATIBILITY == jvmDefaultMode && !descriptor.hasJvmDefaultNoCompatibilityAnnotation()) || + (JvmDefaultMode.ALL_INCOMPATIBLE == jvmDefaultMode && descriptor.hasJvmDefaultWithCompatibilityAnnotation()) ) ) } diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index a6c116f87bb..b1259d246d9 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -25729,6 +25729,28 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/specialization/basic.kt"); } } + + @Nested + @TestMetadata("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility") + @TestDataPath("$PROJECT_ROOT") + public class WithCompatibility { + @Test + public void testAllFilesPresentInWithCompatibility() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @Test + @TestMetadata("defaultArgs.kt") + public void testDefaultArgs() throws Exception { + runTest("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility/defaultArgs.kt"); + } + + @Test + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility/simple.kt"); + } + } } @Nested diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/annotations/jvmAnnotationUtil.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/annotations/jvmAnnotationUtil.kt index c0b9bdc1a7a..aab332d09e8 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/annotations/jvmAnnotationUtil.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/annotations/jvmAnnotationUtil.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.util.findImplementationFromInterface val JVM_DEFAULT_FQ_NAME = FqName("kotlin.jvm.JvmDefault") val JVM_DEFAULT_NO_COMPATIBILITY_FQ_NAME = FqName("kotlin.jvm.JvmDefaultWithoutCompatibility") +val JVM_DEFAULT_WITH_COMPATIBILITY_FQ_NAME = FqName("kotlin.jvm.JvmDefaultWithCompatibility") val JVM_OVERLOADS_FQ_NAME = FqName("kotlin.jvm.JvmOverloads") @JvmField @@ -77,6 +78,8 @@ fun CallableMemberDescriptor.hasJvmDefaultAnnotation(): Boolean = fun DeclarationDescriptor.hasJvmDefaultNoCompatibilityAnnotation(): Boolean = this.annotations.hasAnnotation(JVM_DEFAULT_NO_COMPATIBILITY_FQ_NAME) +fun DeclarationDescriptor.hasJvmDefaultWithCompatibilityAnnotation(): Boolean = + this.annotations.hasAnnotation(JVM_DEFAULT_WITH_COMPATIBILITY_FQ_NAME) fun CallableMemberDescriptor.hasPlatformDependentAnnotation(): Boolean = DescriptorUtils.getDirectMember(this).annotations.hasAnnotation(PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME) diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceLowering.kt index b457c614b49..a36da7c132a 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceLowering.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceLowering.kt @@ -65,7 +65,9 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran private fun handleInterface(irClass: IrClass) { val jvmDefaultMode = context.state.jvmDefaultMode - val isCompatibilityMode = jvmDefaultMode.isCompatibility && !irClass.hasJvmDefaultNoCompatibilityAnnotation() + val isCompatibilityMode = + (jvmDefaultMode.isCompatibility && !irClass.hasJvmDefaultNoCompatibilityAnnotation()) || + (jvmDefaultMode == JvmDefaultMode.ALL_INCOMPATIBLE && irClass.hasJvmDefaultWithCompatibilityAnnotation()) // There are 6 cases for functions on interfaces: for (function in irClass.functions) { when { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/JvmIrUtils.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/JvmIrUtils.kt index 8fc7091f770..56baa06036e 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/JvmIrUtils.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/JvmIrUtils.kt @@ -52,6 +52,7 @@ import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil import org.jetbrains.kotlin.name.JvmNames.JVM_DEFAULT_FQ_NAME import org.jetbrains.kotlin.name.JvmNames.JVM_DEFAULT_NO_COMPATIBILITY_FQ_NAME +import org.jetbrains.kotlin.name.JvmNames.JVM_DEFAULT_WITH_COMPATIBILITY_FQ_NAME import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.DescriptorUtils @@ -94,6 +95,7 @@ fun IrSimpleFunction.isCompiledToJvmDefault(jvmDefaultMode: JvmDefaultMode): Boo fun IrFunction.hasJvmDefault(): Boolean = propertyIfAccessor.hasAnnotation(JVM_DEFAULT_FQ_NAME) fun IrClass.hasJvmDefaultNoCompatibilityAnnotation(): Boolean = hasAnnotation(JVM_DEFAULT_NO_COMPATIBILITY_FQ_NAME) +fun IrClass.hasJvmDefaultWithCompatibilityAnnotation(): Boolean = hasAnnotation(JVM_DEFAULT_WITH_COMPATIBILITY_FQ_NAME) fun IrFunction.hasPlatformDependent(): Boolean = propertyIfAccessor.hasAnnotation(PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME) fun IrFunction.getJvmVisibilityOfDefaultArgumentStub() = diff --git a/compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility/defaultArgs.kt b/compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility/defaultArgs.kt new file mode 100644 index 00000000000..be440c80e13 --- /dev/null +++ b/compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility/defaultArgs.kt @@ -0,0 +1,22 @@ +// !JVM_DEFAULT_MODE: all +// TARGET_BACKEND: JVM +// IGNORE_BACKEND: JVM +// JVM_TARGET: 1.8 +// WITH_RUNTIME +// FULL_JDK +// CHECK_BYTECODE_LISTING + +@JvmDefaultWithCompatibility +interface Test { + fun test(s: String ="OK"): String { + return s + } +} + +class TestClass : Test { + +} + +fun box(): String { + return TestClass().test() +} diff --git a/compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility/defaultArgs.txt b/compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility/defaultArgs.txt new file mode 100644 index 00000000000..08cf9dc4570 --- /dev/null +++ b/compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility/defaultArgs.txt @@ -0,0 +1,29 @@ +@kotlin.Metadata +public final class DefaultArgsKt { + // source: 'defaultArgs.kt' + public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String +} + +@kotlin.Metadata +public final class Test$DefaultImpls { + // source: 'defaultArgs.kt' + public synthetic static method test$default(p0: Test, p1: java.lang.String, p2: int, p3: java.lang.Object): java.lang.String + public deprecated static @java.lang.Deprecated @org.jetbrains.annotations.NotNull method test(@org.jetbrains.annotations.NotNull p0: Test, @org.jetbrains.annotations.NotNull p1: java.lang.String): java.lang.String + public final inner class Test$DefaultImpls +} + +@kotlin.jvm.JvmDefaultWithCompatibility +@kotlin.Metadata +public interface Test { + // source: 'defaultArgs.kt' + public synthetic static method access$test$jd(p0: Test, p1: java.lang.String): java.lang.String + public synthetic static method test$default(p0: Test, p1: java.lang.String, p2: int, p3: java.lang.Object): java.lang.String + public @org.jetbrains.annotations.NotNull method test(@org.jetbrains.annotations.NotNull p0: java.lang.String): java.lang.String + public final inner class Test$DefaultImpls +} + +@kotlin.Metadata +public final class TestClass { + // source: 'defaultArgs.kt' + public method (): void +} diff --git a/compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility/simple.kt b/compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility/simple.kt new file mode 100644 index 00000000000..092399e3c0c --- /dev/null +++ b/compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility/simple.kt @@ -0,0 +1,33 @@ +// !JVM_DEFAULT_MODE: all +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +// IGNORE_BACKEND: JVM +// WITH_RUNTIME +// FILE: Simple.java + +public interface Simple extends KInterface { + default String test() { + return KInterface.DefaultImpls.test2(this); + } +} + +// FILE: Foo.java +public class Foo implements Simple { + +} + +// FILE: main.kt +@JvmDefaultWithCompatibility +interface KInterface { + fun test2(): String { + return "OK" + } +} + + +fun box(): String { + val result = Foo().test() + if (result != "OK") return "fail 1: ${result}" + + return Foo().test2() +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index acebe1ad929..aad0a31df26 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -25357,6 +25357,28 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/specialization/basic.kt"); } } + + @Nested + @TestMetadata("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility") + @TestDataPath("$PROJECT_ROOT") + public class WithCompatibility { + @Test + public void testAllFilesPresentInWithCompatibility() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); + } + + @Test + @TestMetadata("defaultArgs.kt") + public void testDefaultArgs() throws Exception { + runTest("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility/defaultArgs.kt"); + } + + @Test + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility/simple.kt"); + } + } } @Nested diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 9892426fef8..f1e234dcfe8 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -25729,6 +25729,28 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/specialization/basic.kt"); } } + + @Nested + @TestMetadata("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility") + @TestDataPath("$PROJECT_ROOT") + public class WithCompatibility { + @Test + public void testAllFilesPresentInWithCompatibility() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @Test + @TestMetadata("defaultArgs.kt") + public void testDefaultArgs() throws Exception { + runTest("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility/defaultArgs.kt"); + } + + @Test + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility/simple.kt"); + } + } } @Nested diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 4cd6d8c05cb..8868580ba07 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -21385,6 +21385,29 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/specialization/basic.kt"); } } + + @TestMetadata("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class WithCompatibility extends AbstractLightAnalysisModeTest { + @TestMetadata("defaultArgs.kt") + public void ignoreDefaultArgs() throws Exception { + runTest("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility/defaultArgs.kt"); + } + + @TestMetadata("simple.kt") + public void ignoreSimple() throws Exception { + runTest("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility/simple.kt"); + } + + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); + } + + public void testAllFilesPresentInWithCompatibility() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); + } + } } @TestMetadata("compiler/testData/codegen/box/jvm8/defaults/noDelegation") diff --git a/core/compiler.common.jvm/src/org/jetbrains/kotlin/name/JvmNames.kt b/core/compiler.common.jvm/src/org/jetbrains/kotlin/name/JvmNames.kt index adcc8739539..8ad334d4923 100644 --- a/core/compiler.common.jvm/src/org/jetbrains/kotlin/name/JvmNames.kt +++ b/core/compiler.common.jvm/src/org/jetbrains/kotlin/name/JvmNames.kt @@ -19,6 +19,7 @@ object JvmNames { val JVM_DEFAULT_FQ_NAME = FqName("kotlin.jvm.JvmDefault") val JVM_DEFAULT_CLASS_ID = ClassId.topLevel(JVM_DEFAULT_FQ_NAME) val JVM_DEFAULT_NO_COMPATIBILITY_FQ_NAME = FqName("kotlin.jvm.JvmDefaultWithoutCompatibility") + val JVM_DEFAULT_WITH_COMPATIBILITY_FQ_NAME = FqName("kotlin.jvm.JvmDefaultWithCompatibility") val JVM_DEFAULT_NO_COMPATIBILITY_CLASS_ID = ClassId.topLevel(JVM_DEFAULT_NO_COMPATIBILITY_FQ_NAME) val JVM_OVERLOADS_FQ_NAME = FqName("kotlin.jvm.JvmOverloads") val JVM_OVERLOADS_CLASS_ID = ClassId.topLevel(JVM_OVERLOADS_FQ_NAME) diff --git a/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/JvmFlags.kt b/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/JvmFlags.kt index c1471b4cc1a..7581d806f04 100644 --- a/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/JvmFlags.kt +++ b/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/JvmFlags.kt @@ -21,7 +21,7 @@ object JvmFlags { fun getPropertyFlags(isMovedFromInterfaceCompanion: Boolean): Int = IS_MOVED_FROM_INTERFACE_COMPANION.toFlags(isMovedFromInterfaceCompanion) - fun getClassFlags(isAllInterfaceBodiesInside: Boolean, isAllCompatibilityMode: Boolean): Int = - ARE_INTERFACE_METHOD_BODIES_INSIDE.toFlags(isAllInterfaceBodiesInside) or IS_ALL_COMPATIBILITY_MODE.toFlags(isAllCompatibilityMode) + fun getClassFlags(isAllInterfaceBodiesInside: Boolean, isCompatibilityMode: Boolean): Int = + ARE_INTERFACE_METHOD_BODIES_INSIDE.toFlags(isAllInterfaceBodiesInside) or IS_ALL_COMPATIBILITY_MODE.toFlags(isCompatibilityMode) } diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java index 70d16b981fc..ed9a76c7e8e 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java @@ -18411,6 +18411,16 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/specialization"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true); } } + + @Nested + @TestMetadata("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility") + @TestDataPath("$PROJECT_ROOT") + public class WithCompatibility { + @Test + public void testAllFilesPresentInWithCompatibility() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true); + } + } } @Nested diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java index 5a917e038a1..40b96108d06 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java @@ -18375,6 +18375,16 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/specialization"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true); } } + + @Nested + @TestMetadata("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility") + @TestDataPath("$PROJECT_ROOT") + public class WithCompatibility { + @Test + public void testAllFilesPresentInWithCompatibility() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true); + } + } } @Nested diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java index 4e763cc285a..1b3f9b1fb48 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java @@ -15712,6 +15712,19 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/specialization"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true); } } + + @TestMetadata("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class WithCompatibility extends AbstractIrCodegenBoxWasmTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath); + } + + public void testAllFilesPresentInWithCompatibility() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true); + } + } } @TestMetadata("compiler/testData/codegen/box/jvm8/defaults/noDelegation") diff --git a/libraries/stdlib/jvm/src/kotlin/jvm/JvmDefault.kt b/libraries/stdlib/jvm/src/kotlin/jvm/JvmDefault.kt index aaf5d2772f5..bf513b1e7fa 100644 --- a/libraries/stdlib/jvm/src/kotlin/jvm/JvmDefault.kt +++ b/libraries/stdlib/jvm/src/kotlin/jvm/JvmDefault.kt @@ -48,3 +48,13 @@ annotation class JvmDefault @RequireKotlin("1.4", versionKind = RequireKotlinVersionKind.COMPILER_VERSION) @Target(AnnotationTarget.CLASS) annotation class JvmDefaultWithoutCompatibility + +/** + * Forces the compiler to generate compatibility accessors for the annotated interface in the `DefaultImpls` class. + * + * Used only with `-Xjvm-default=all`. For more details refer to `-Xjvm-default` documentation. + */ +@SinceKotlin("1.6") +@RequireKotlin("1.6", versionKind = RequireKotlinVersionKind.COMPILER_VERSION) +@Target(AnnotationTarget.CLASS) +annotation class JvmDefaultWithCompatibility \ No newline at end of file diff --git a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt index 8eb86926e6a..563293fce54 100644 --- a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt +++ b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt @@ -3227,6 +3227,9 @@ public final class kotlin/jvm/JvmClassMappingKt { public abstract interface annotation class kotlin/jvm/JvmDefault : java/lang/annotation/Annotation { } +public abstract interface annotation class kotlin/jvm/JvmDefaultWithCompatibility : java/lang/annotation/Annotation { +} + public abstract interface annotation class kotlin/jvm/JvmDefaultWithoutCompatibility : java/lang/annotation/Annotation { } diff --git a/libraries/tools/kotlinp/test/org/jetbrains/kotlin/kotlinp/test/KotlinpTestGenerated.java b/libraries/tools/kotlinp/test/org/jetbrains/kotlin/kotlinp/test/KotlinpTestGenerated.java index 8918c9d6d40..0e014f4950f 100644 --- a/libraries/tools/kotlinp/test/org/jetbrains/kotlin/kotlinp/test/KotlinpTestGenerated.java +++ b/libraries/tools/kotlinp/test/org/jetbrains/kotlin/kotlinp/test/KotlinpTestGenerated.java @@ -140,5 +140,15 @@ public class KotlinpTestGenerated extends AbstractKotlinpTest { public void testAllFilesPresentInJvmDefault() throws Exception { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("libraries/tools/kotlinp/testData/jvmDefault"), Pattern.compile("^(.+)\\.kt$"), null, true); } + + @TestMetadata("withCompatibility.kt") + public void testWithCompatibility() throws Exception { + runTest("libraries/tools/kotlinp/testData/jvmDefault/withCompatibility.kt"); + } + + @TestMetadata("withoutCompatibility.kt") + public void testWithoutCompatibility() throws Exception { + runTest("libraries/tools/kotlinp/testData/jvmDefault/withoutCompatibility.kt"); + } } } diff --git a/libraries/tools/kotlinp/testData/jvmDefault/withCompatibility.kt b/libraries/tools/kotlinp/testData/jvmDefault/withCompatibility.kt new file mode 100644 index 00000000000..8976f226d38 --- /dev/null +++ b/libraries/tools/kotlinp/testData/jvmDefault/withCompatibility.kt @@ -0,0 +1,8 @@ +// !JVM_DEFAULT_MODE: all +@JvmDefaultWithCompatibility +interface A { + fun f() {} +} + +@JvmDefaultWithCompatibility +interface B : A \ No newline at end of file diff --git a/libraries/tools/kotlinp/testData/jvmDefault/withCompatibility.txt b/libraries/tools/kotlinp/testData/jvmDefault/withCompatibility.txt new file mode 100644 index 00000000000..ea6caa9f6a7 --- /dev/null +++ b/libraries/tools/kotlinp/testData/jvmDefault/withCompatibility.txt @@ -0,0 +1,35 @@ +// A.class +// ------------------------------------------ +// requires compiler version 1.4.0 (level=ERROR) +public abstract interface A : kotlin/Any { + + // signature: f()V + public open fun f(): kotlin/Unit + + // module name: test-module + + // has method bodies in interface + + // is compiled in compatibility mode +} +// A$DefaultImpls.class +// ------------------------------------------ +synthetic class +// B.class +// ------------------------------------------ +// requires compiler version 1.4.0 (level=ERROR) +public abstract interface B : A { + + // module name: test-module + + // has method bodies in interface + + // is compiled in compatibility mode +} +// B$DefaultImpls.class +// ------------------------------------------ +synthetic class +// META-INF/test-module.kotlin_module +// ------------------------------------------ +module { +} diff --git a/libraries/tools/kotlinp/testData/jvmDefault/withoutCompatibility.kt b/libraries/tools/kotlinp/testData/jvmDefault/withoutCompatibility.kt new file mode 100644 index 00000000000..64506de2330 --- /dev/null +++ b/libraries/tools/kotlinp/testData/jvmDefault/withoutCompatibility.kt @@ -0,0 +1,7 @@ +// !JVM_DEFAULT_MODE: all-compatibility +@JvmDefaultWithoutCompatibility +interface A { + fun f() {} +} + +interface B : A \ No newline at end of file diff --git a/libraries/tools/kotlinp/testData/jvmDefault/withoutCompatibility.txt b/libraries/tools/kotlinp/testData/jvmDefault/withoutCompatibility.txt new file mode 100644 index 00000000000..5f68d01a435 --- /dev/null +++ b/libraries/tools/kotlinp/testData/jvmDefault/withoutCompatibility.txt @@ -0,0 +1,28 @@ +// A.class +// ------------------------------------------ +public abstract interface A : kotlin/Any { + + // signature: f()V + public open fun f(): kotlin/Unit + + // module name: test-module + + // has method bodies in interface +} +// B.class +// ------------------------------------------ +public abstract interface B : A { + + // module name: test-module + + // has method bodies in interface + + // is compiled in compatibility mode +} +// B$DefaultImpls.class +// ------------------------------------------ +synthetic class +// META-INF/test-module.kotlin_module +// ------------------------------------------ +module { +} diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeExtBlackBoxTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeExtBlackBoxTestGenerated.java index 0e5c1a45bfd..cf006589a5c 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeExtBlackBoxTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeExtBlackBoxTestGenerated.java @@ -26040,6 +26040,29 @@ public class NativeExtBlackBoxTestGenerated extends AbstractNativeBlackBoxTest { runTest("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/specialization/basic.kt"); } } + + @Nested + @TestMetadata("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility") + @TestDataPath("$PROJECT_ROOT") + @NativeBlackBoxTestCaseGroupProvider(ExtTestCaseGroupProvider.class) + public class WithCompatibility { + @Test + public void testAllFilesPresentInWithCompatibility() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("defaultArgs.kt") + public void testDefaultArgs() throws Exception { + runTest("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility/defaultArgs.kt"); + } + + @Test + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/withCompatibility/simple.kt"); + } + } } @Nested