Don't generate compatibility stubs for @JvmDefaultWithoutCompatibility

This commit is contained in:
Mikhail Bogdanov
2020-06-08 10:24:31 +02:00
parent 477cca3c99
commit 5bdf3d5757
8 changed files with 91 additions and 5 deletions
@@ -710,8 +710,7 @@ public class FunctionCodegen {
@NotNull JvmDefaultMode jvmDefaultMode @NotNull JvmDefaultMode jvmDefaultMode
) { ) {
return OwnerKind.DEFAULT_IMPLS == context.getContextKind() && return OwnerKind.DEFAULT_IMPLS == context.getContextKind() &&
JvmAnnotationUtilKt JvmAnnotationUtilKt.isCompiledToJvmDefault(DescriptorUtils.unwrapFakeOverrideToAnyDeclaration(functionDescriptor),
.isCompiledToJvmDefault(DescriptorUtils.unwrapFakeOverrideToAnyDeclaration(functionDescriptor),
jvmDefaultMode) && jvmDefaultMode) &&
jvmDefaultMode.isCompatibility(); jvmDefaultMode.isCompatibility();
} }
@@ -1656,7 +1655,9 @@ public class FunctionCodegen {
if (JvmAnnotationUtilKt.isCompiledToJvmDefault(memberDescriptor, mode)) { if (JvmAnnotationUtilKt.isCompiledToJvmDefault(memberDescriptor, mode)) {
return (kind != OwnerKind.DEFAULT_IMPLS && !isSynthetic) || 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 { } else {
switch (kind) { switch (kind) {
case DEFAULT_IMPLS: return true; case DEFAULT_IMPLS: return true;
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.resolve.jvm.annotations
import org.jetbrains.kotlin.config.JvmDefaultMode import org.jetbrains.kotlin.config.JvmDefaultMode
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotated 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 import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
val JVM_DEFAULT_FQ_NAME = FqName("kotlin.jvm.JvmDefault") 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_OVERLOADS_FQ_NAME = FqName("kotlin.jvm.JvmOverloads")
val JVM_SYNTHETIC_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmSynthetic") val JVM_SYNTHETIC_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmSynthetic")
@@ -64,6 +66,10 @@ fun CallableMemberDescriptor.isCompiledToJvmDefault(jvmDefault: JvmDefaultMode):
fun CallableMemberDescriptor.hasJvmDefaultAnnotation(): Boolean = fun CallableMemberDescriptor.hasJvmDefaultAnnotation(): Boolean =
DescriptorUtils.getDirectMember(this).annotations.hasAnnotation(JVM_DEFAULT_FQ_NAME) 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 = fun CallableMemberDescriptor.hasPlatformDependentAnnotation(): Boolean =
DescriptorUtils.getDirectMember(this).annotations.hasAnnotation(PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME) DescriptorUtils.getDirectMember(this).annotations.hasAnnotation(PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME)
@@ -44,6 +44,7 @@ import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
import org.jetbrains.kotlin.resolve.DescriptorUtils 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_FQ_NAME
import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_DEFAULT_NO_COMPATIBILITY_FQ_NAME
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor 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 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.hasPlatformDependent(): Boolean = propertyIfAccessor.hasAnnotation(PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME)
fun IrFunction.getJvmVisibilityOfDefaultArgumentStub() = fun IrFunction.getJvmVisibilityOfDefaultArgumentStub() =
@@ -62,6 +62,7 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran
private fun handleInterface(irClass: IrClass) { private fun handleInterface(irClass: IrClass) {
val jvmDefaultMode = context.state.jvmDefaultMode val jvmDefaultMode = context.state.jvmDefaultMode
val isCompatibilityMode = jvmDefaultMode.isCompatibility && !irClass.hasJvmDefaultNoCompatibilityAnnotation()
// There are 6 cases for functions on interfaces: // There are 6 cases for functions on interfaces:
loop@ for (function in irClass.functions) { loop@ for (function in irClass.functions) {
when { when {
@@ -112,7 +113,7 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran
defaultImpl.bridgeToStatic(it) defaultImpl.bridgeToStatic(it)
} }
} }
jvmDefaultMode.isCompatibility && implementation.isCompiledToJvmDefault(jvmDefaultMode) -> { isCompatibilityMode && implementation.isCompiledToJvmDefault(jvmDefaultMode) -> {
val defaultImpl = createDefaultImpl(function) val defaultImpl = createDefaultImpl(function)
defaultImpl.bridgeViaAccessorTo(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, ... * 5) JVM default declaration is bridged in DefaultImpls via accessor if in compatibility mode, ...
*/ */
jvmDefaultMode.isCompatibility -> { isCompatibilityMode -> {
val defaultImpl = createDefaultImpl(function) val defaultImpl = createDefaultImpl(function)
defaultImpl.bridgeViaAccessorTo(function) defaultImpl.bridgeViaAccessorTo(function)
} }
@@ -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
@@ -0,0 +1,42 @@
@kotlin.jvm.JvmDefaultWithoutCompatibility
@kotlin.Metadata
public final class KotlinClass {
public method <init>(): 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
}
@@ -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); 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") @TestMetadata("noDefaultImplsOnEmptySubInterface.kt")
public void testNoDefaultImplsOnEmptySubInterface() throws Exception { public void testNoDefaultImplsOnEmptySubInterface() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/noDefaultImplsOnEmptySubInterface.kt"); runTest("compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/noDefaultImplsOnEmptySubInterface.kt");
@@ -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); 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") @TestMetadata("noDefaultImplsOnEmptySubInterface.kt")
public void testNoDefaultImplsOnEmptySubInterface() throws Exception { public void testNoDefaultImplsOnEmptySubInterface() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/noDefaultImplsOnEmptySubInterface.kt"); runTest("compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/noDefaultImplsOnEmptySubInterface.kt");