diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt index 2d8949b2942..2117046a1bc 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt @@ -270,13 +270,31 @@ class K2JVMCompilerArguments : CommonCompilerArguments() { @Argument( value = "-Xjvm-default", - valueDescription = "{disable|enable|compatibility}", - description = "Allow to use '@JvmDefault' annotation for JVM default method support.\n" + - "-Xjvm-default=disable Prohibit usages of @JvmDefault\n" + - "-Xjvm-default=enable Allow usages of @JvmDefault; only generate the default method\n" + - " in the interface (annotating an existing method can break binary compatibility)\n" + - "-Xjvm-default=compatibility Allow usages of @JvmDefault; generate a compatibility accessor\n" + - " in the 'DefaultImpls' class in addition to the interface method" + valueDescription = "{all|all-compatibility|disable|enable|compatibility}", + description = """Emit JVM default methods for interface declarations with bodies. +-Xjvm-default=all-compatibility Generate both a default method in the interface, and a compatibility accessor + in the DefaultImpls class. + In case of inheritance from a Kotlin interface compiled in the old scheme + (DefaultImpls, no default methods), the compatibility accessor in DefaultImpls + will delegate to the DefaultImpls method of the superinterface. Otherwise the + compatibility accessor will invoke the default method on the interface, with + standard JVM runtime resolution semantics. + Note that if interface delegation is used, all interface methods are delegated. + The only exception are methods annotated with the deprecated @JvmDefault annotation. +-Xjvm-default=all Generate default methods for all interface declarations with bodies. + Do not generate DefaultImpls classes at all. + BREAKS BINARY COMPATIBILITY if some client code relies on the presence of + DefaultImpls classes. Also prohibits the produced binaries to be read by Kotlin + compilers earlier than 1.4. + Note that if interface delegation is used, all interface methods are delegated. + The only exception are methods annotated with the deprecated @JvmDefault annotation. +-Xjvm-default=disable Do not generate JVM default methods and prohibit @JvmDefault annotation usage. + The following modes are DEPRECATED: +-Xjvm-default=enable Allow usages of @JvmDefault; only generate the default method + for annotated method in the interface + (annotating an existing method can break binary compatibility) +-Xjvm-default=compatibility Allow usages of @JvmDefault; generate a compatibility accessor + in the 'DefaultImpls' class in addition to the default interface method""" ) var jvmDefault: String by FreezableVar(JvmDefaultMode.DEFAULT.description) @@ -337,12 +355,19 @@ class K2JVMCompilerArguments : CommonCompilerArguments() { supportCompatqualCheckerFrameworkAnnotations ) result[AnalysisFlags.ignoreDataFlowInAssert] = JVMAssertionsMode.fromString(assertionsMode) != JVMAssertionsMode.LEGACY - JvmDefaultMode.fromStringOrNull(jvmDefault)?.let { result[JvmAnalysisFlags.jvmDefaultMode] = it } - ?: collector.report( - CompilerMessageSeverity.ERROR, - "Unknown @JvmDefault mode: $jvmDefault, " + - "supported modes: ${JvmDefaultMode.values().map { it.description }}" - ) + JvmDefaultMode.fromStringOrNull(jvmDefault)?.let { + result[JvmAnalysisFlags.jvmDefaultMode] = it + if (it == JvmDefaultMode.ENABLE || it == JvmDefaultMode.ENABLE_WITH_DEFAULT_IMPLS) { + collector.report( + CompilerMessageSeverity.WARNING, + "'-Xjvm-default=$jvmDefault' mode is deprecated. Please considering to switch to new modes: 'all' and 'all-compatibility'" + ) + } + } ?: collector.report( + CompilerMessageSeverity.ERROR, + "Unknown @JvmDefault mode: $jvmDefault, " + + "supported modes: ${JvmDefaultMode.values().map { it.description }}" + ) result[JvmAnalysisFlags.inheritMultifileParts] = inheritMultifileParts result[JvmAnalysisFlags.sanitizeParentheses] = sanitizeParentheses result[JvmAnalysisFlags.suppressMissingBuiltinsError] = suppressMissingBuiltinsError diff --git a/compiler/config.jvm/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java b/compiler/config.jvm/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java index 1ef813a851b..28a3a108b44 100644 --- a/compiler/config.jvm/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java +++ b/compiler/config.jvm/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java @@ -108,9 +108,6 @@ public class JVMConfigurationKeys { public static final CompilerConfigurationKey> ADDITIONAL_JAVA_MODULES = CompilerConfigurationKey.create("additional Java modules"); - public static final CompilerConfigurationKey ENABLE_JVM_DEFAULT = - CompilerConfigurationKey.create("Allow to use '@JvmDefault'"); - public static final CompilerConfigurationKey EMIT_JVM_TYPE_ANNOTATIONS = CompilerConfigurationKey.create("Emit JVM type annotations in bytecode"); diff --git a/compiler/testData/cli/jvm/extraHelp.out b/compiler/testData/cli/jvm/extraHelp.out index 910136693d3..2ea9e607a74 100644 --- a/compiler/testData/cli/jvm/extraHelp.out +++ b/compiler/testData/cli/jvm/extraHelp.out @@ -38,13 +38,32 @@ where advanced options include: * ignore * strict (experimental; treat as other supported nullability annotations) * warn (report a warning) - -Xjvm-default={disable|enable|compatibility} - Allow to use '@JvmDefault' annotation for JVM default method support. - -Xjvm-default=disable Prohibit usages of @JvmDefault - -Xjvm-default=enable Allow usages of @JvmDefault; only generate the default method - in the interface (annotating an existing method can break binary compatibility) - -Xjvm-default=compatibility Allow usages of @JvmDefault; generate a compatibility accessor - in the 'DefaultImpls' class in addition to the interface method + -Xjvm-default={all|all-compatibility|disable|enable|compatibility} + Emit JVM default methods for interface declarations with bodies. + -Xjvm-default=all-compatibility Generate both a default method in the interface, and a compatibility accessor + in the DefaultImpls class. + In case of inheritance from a Kotlin interface compiled in the old scheme + (DefaultImpls, no default methods), the compatibility accessor in DefaultImpls + will delegate to the DefaultImpls method of the superinterface. Otherwise the + compatibility accessor will invoke the default method on the interface, with + standard JVM runtime resolution semantics. + Note that if interface delegation is used, all interface methods are delegated. + The only exception are methods annotated with the deprecated @JvmDefault annotation. + -Xjvm-default=all Generate default methods for all interface declarations with bodies. + Do not generate DefaultImpls classes at all. + BREAKS BINARY COMPATIBILITY if some client code relies on the presence of + DefaultImpls classes. Also prohibits the produced binaries to be read by Kotlin + compilers earlier than 1.4. + Note that if interface delegation is used, all interface methods are delegated. + The only exception are methods annotated with the deprecated @JvmDefault annotation. + -Xjvm-default=disable Do not generate JVM default methods and prohibit @JvmDefault annotation usage. + The following modes are DEPRECATED: + -Xjvm-default=enable Allow usages of @JvmDefault; only generate the default method + for annotated method in the interface + (annotating an existing method can break binary compatibility) + -Xjvm-default=compatibility Allow usages of @JvmDefault; generate a compatibility accessor + in the 'DefaultImpls' class in addition to the default interface method + -Xklib= Paths to cross-platform libraries in .klib format -Xno-call-assertions Don't generate not-null assertions for arguments of platform types -Xno-exception-on-explicit-equals-for-boxed-null diff --git a/libraries/stdlib/jvm/src/kotlin/jvm/JvmDefault.kt b/libraries/stdlib/jvm/src/kotlin/jvm/JvmDefault.kt index 784b4fb0995..4f6de68e950 100644 --- a/libraries/stdlib/jvm/src/kotlin/jvm/JvmDefault.kt +++ b/libraries/stdlib/jvm/src/kotlin/jvm/JvmDefault.kt @@ -9,6 +9,7 @@ import kotlin.internal.RequireKotlin import kotlin.internal.RequireKotlinVersionKind /** + * * Specifies that a JVM default method should be generated for non-abstract Kotlin interface member. * * Usages of this annotation require an explicit compilation argument to be specified: @@ -26,6 +27,13 @@ import kotlin.internal.RequireKotlinVersionKind * Generation of default methods is only possible with JVM target bytecode version 1.8 (`-jvm-target 1.8`) or higher. * * @[JvmDefault] methods are excluded from interface delegation. + * + * # + * This annotation is **deprecated** in favor of new compiler arguments `-Xjvm-default=all-compatibility` and `-Xjvm-default=all`. + * The new arguments allow all interface methods with bodies to be generated as JVM default methods on JVM target 1.8+. + * Please refer to the [official documentation](https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#default-methods-in-interfaces) + * for more information. + * */ @SinceKotlin("1.2") @RequireKotlin("1.2.40", versionKind = RequireKotlinVersionKind.COMPILER_VERSION)