From 5bdf3d57573f896f31797ede287d62fc46557436 Mon Sep 17 00:00:00 2001 From: Mikhail Bogdanov Date: Mon, 8 Jun 2020 10:24:31 +0200 Subject: [PATCH] Don't generate compatibility stubs for @JvmDefaultWithoutCompatibility --- .../kotlin/codegen/FunctionCodegen.java | 7 ++-- .../jvm/annotations/jvmAnnotationUtil.kt | 6 +++ .../kotlin/backend/jvm/ir/IrUtils.kt | 2 + .../backend/jvm/lower/InterfaceLowering.kt | 5 ++- .../jvmDefaultWithoutCompatibility.kt | 24 +++++++++++ .../jvmDefaultWithoutCompatibility.txt | 42 +++++++++++++++++++ .../codegen/BytecodeListingTestGenerated.java | 5 +++ .../ir/IrBytecodeListingTestGenerated.java | 5 +++ 8 files changed, 91 insertions(+), 5 deletions(-) create mode 100644 compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/jvmDefaultWithoutCompatibility.kt create mode 100644 compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/jvmDefaultWithoutCompatibility.txt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index e77a4781077..30bf91459bd 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -710,8 +710,7 @@ public class FunctionCodegen { @NotNull JvmDefaultMode jvmDefaultMode ) { return OwnerKind.DEFAULT_IMPLS == context.getContextKind() && - JvmAnnotationUtilKt - .isCompiledToJvmDefault(DescriptorUtils.unwrapFakeOverrideToAnyDeclaration(functionDescriptor), + JvmAnnotationUtilKt.isCompiledToJvmDefault(DescriptorUtils.unwrapFakeOverrideToAnyDeclaration(functionDescriptor), jvmDefaultMode) && jvmDefaultMode.isCompatibility(); } @@ -1656,7 +1655,9 @@ public class FunctionCodegen { if (JvmAnnotationUtilKt.isCompiledToJvmDefault(memberDescriptor, mode)) { return (kind != OwnerKind.DEFAULT_IMPLS && !isSynthetic) || - (kind == OwnerKind.DEFAULT_IMPLS && (isSynthetic || mode.isCompatibility())); + (kind == OwnerKind.DEFAULT_IMPLS && + (isSynthetic || //TODO: move synthetic method generation into interface + (mode.isCompatibility() && !JvmAnnotationUtilKt.hasJvmDefaultNoCompatibilityAnnotation(containingDeclaration)))); } else { switch (kind) { case DEFAULT_IMPLS: return true; 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 5bd87c8cb5a..9f8f69fd7c7 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 @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.resolve.jvm.annotations import org.jetbrains.kotlin.config.JvmDefaultMode import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor +import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotated @@ -19,6 +20,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor val JVM_DEFAULT_FQ_NAME = FqName("kotlin.jvm.JvmDefault") +val JVM_DEFAULT_NO_COMPATIBILITY_FQ_NAME = FqName("kotlin.jvm.JvmDefaultWithoutCompatibility") val JVM_OVERLOADS_FQ_NAME = FqName("kotlin.jvm.JvmOverloads") val JVM_SYNTHETIC_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmSynthetic") @@ -64,6 +66,10 @@ fun CallableMemberDescriptor.isCompiledToJvmDefault(jvmDefault: JvmDefaultMode): fun CallableMemberDescriptor.hasJvmDefaultAnnotation(): Boolean = DescriptorUtils.getDirectMember(this).annotations.hasAnnotation(JVM_DEFAULT_FQ_NAME) +fun DeclarationDescriptor.hasJvmDefaultNoCompatibilityAnnotation(): Boolean = + this.annotations.hasAnnotation(JVM_DEFAULT_NO_COMPATIBILITY_FQ_NAME) + + fun CallableMemberDescriptor.hasPlatformDependentAnnotation(): Boolean = DescriptorUtils.getDirectMember(this).annotations.hasAnnotation(PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME) 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 dbe295cc4a7..50ccde5e74c 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 @@ -44,6 +44,7 @@ import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_DEFAULT_FQ_NAME +import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_DEFAULT_NO_COMPATIBILITY_FQ_NAME import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor /** @@ -164,6 +165,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 IrFunction.hasPlatformDependent(): Boolean = propertyIfAccessor.hasAnnotation(PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME) fun IrFunction.getJvmVisibilityOfDefaultArgumentStub() = 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 5e53baf0f9f..bc1196eee19 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 @@ -62,6 +62,7 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran private fun handleInterface(irClass: IrClass) { val jvmDefaultMode = context.state.jvmDefaultMode + val isCompatibilityMode = jvmDefaultMode.isCompatibility && !irClass.hasJvmDefaultNoCompatibilityAnnotation() // There are 6 cases for functions on interfaces: loop@ for (function in irClass.functions) { when { @@ -112,7 +113,7 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran defaultImpl.bridgeToStatic(it) } } - jvmDefaultMode.isCompatibility && implementation.isCompiledToJvmDefault(jvmDefaultMode) -> { + isCompatibilityMode && implementation.isCompiledToJvmDefault(jvmDefaultMode) -> { val defaultImpl = createDefaultImpl(function) defaultImpl.bridgeViaAccessorTo(function) } @@ -145,7 +146,7 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran /** * 5) JVM default declaration is bridged in DefaultImpls via accessor if in compatibility mode, ... */ - jvmDefaultMode.isCompatibility -> { + isCompatibilityMode -> { val defaultImpl = createDefaultImpl(function) defaultImpl.bridgeViaAccessorTo(function) } diff --git a/compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/jvmDefaultWithoutCompatibility.kt b/compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/jvmDefaultWithoutCompatibility.kt new file mode 100644 index 00000000000..05700d347bf --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/jvmDefaultWithoutCompatibility.kt @@ -0,0 +1,24 @@ +// !JVM_DEFAULT_MODE: all-compatibility +// JVM_TARGET: 1.8 +// WITH_RUNTIME + +@JvmDefaultWithoutCompatibility +interface NoDefaultImpl { + fun test() {} +} + +interface WithDefaultImpl: NoDefaultImpl { + +} + +interface WithDefaultImplPure { + fun test() {} +} + +@JvmDefaultWithoutCompatibility +interface NoDefaultImpl2FromDefaultImpls : WithDefaultImplPure { + fun test2() {} +} + +@JvmDefaultWithoutCompatibility +class KotlinClass : NoDefaultImpl \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/jvmDefaultWithoutCompatibility.txt b/compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/jvmDefaultWithoutCompatibility.txt new file mode 100644 index 00000000000..8073d5cf0ad --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/jvmDefaultWithoutCompatibility.txt @@ -0,0 +1,42 @@ +@kotlin.jvm.JvmDefaultWithoutCompatibility +@kotlin.Metadata +public final class KotlinClass { + public method (): void +} + +@kotlin.jvm.JvmDefaultWithoutCompatibility +@kotlin.Metadata +public interface NoDefaultImpl { + public method test(): void +} + +@kotlin.jvm.JvmDefaultWithoutCompatibility +@kotlin.Metadata +public interface NoDefaultImpl2FromDefaultImpls { + public method test2(): void +} + +@kotlin.Metadata +public final class WithDefaultImpl$DefaultImpls { + inner class WithDefaultImpl$DefaultImpls + public static method test(@org.jetbrains.annotations.NotNull p0: WithDefaultImpl): void +} + +@kotlin.Metadata +public interface WithDefaultImpl { + inner class WithDefaultImpl$DefaultImpls + public synthetic static method access$test$jd(p0: WithDefaultImpl): void +} + +@kotlin.Metadata +public final class WithDefaultImplPure$DefaultImpls { + inner class WithDefaultImplPure$DefaultImpls + public static method test(@org.jetbrains.annotations.NotNull p0: WithDefaultImplPure): void +} + +@kotlin.Metadata +public interface WithDefaultImplPure { + inner class WithDefaultImplPure$DefaultImpls + public synthetic static method access$test$jd(p0: WithDefaultImplPure): void + public method test(): void +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java index 80f0c1a9587..3a97bd02c27 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java @@ -517,6 +517,11 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest { KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility"), Pattern.compile("^(.+)\\.kt$"), null, true); } + @TestMetadata("jvmDefaultWithoutCompatibility.kt") + public void testJvmDefaultWithoutCompatibility() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/jvmDefaultWithoutCompatibility.kt"); + } + @TestMetadata("noDefaultImplsOnEmptySubInterface.kt") public void testNoDefaultImplsOnEmptySubInterface() throws Exception { runTest("compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/noDefaultImplsOnEmptySubInterface.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java index 16aaa5cacaa..67b0af988e9 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java @@ -487,6 +487,11 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @TestMetadata("jvmDefaultWithoutCompatibility.kt") + public void testJvmDefaultWithoutCompatibility() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/jvmDefaultWithoutCompatibility.kt"); + } + @TestMetadata("noDefaultImplsOnEmptySubInterface.kt") public void testNoDefaultImplsOnEmptySubInterface() throws Exception { runTest("compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/noDefaultImplsOnEmptySubInterface.kt");