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
) {
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;
@@ -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)
@@ -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() =
@@ -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)
}
@@ -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);
}
@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");
@@ -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");