Kotlin 1.5 的兼容性指南
Keeping the Language Modern and Comfortable Updates are among the fundamental principles in Kotlin Language Design. The former says that constructs which obstruct language evolution should be removed, and the latter says that this removal should be well-communicated beforehand to make code migration as smooth as possible.
While most of the language changes were already announced through other channels, like update changelogs or compiler warnings, this document summarizes them all, providing a complete reference for migration from Kotlin 1.4 to Kotlin 1.5.
Basic terms
In this document we introduce several kinds of compatibility:
- source: source-incompatible change stops code that used to compile fine (without errors or warnings) from compiling anymore
- binary: two binary artifacts are said to be binary-compatible if interchanging them doesn't lead to loading or linkage errors
- behavioral: a change is said to be behavioral-incompatible if the same program demonstrates different behavior before and after applying the change
Remember that those definitions are given only for pure Kotlin. Compatibility of Kotlin code from the other languages perspective (for example, from Java) is out of the scope of this document.
Language and stdlib
Forbid spread operator in signature-polymorphic calls
Issue: KT-35226
Component: Core language
Incompatible change type: source
Short summary: Kotlin 1.5 will outlaw the use of spread operator (*) on signature-polymorphic calls
Deprecation cycle:
- < 1.5: introduce warning for the problematic operator at call-site
- >= 1.5: raise this warning to an error,
-XXLanguage:-ProhibitSpreadOnSignaturePolymorphicCall
can be used to temporarily revert to pre-1.5 behavior
Forbid non-abstract classes containing abstract members invisible from that classes (internal/package-private)
Issue: KT-27825
Component: Core language
Incompatible change type: source
Short summary: Kotlin 1.5 will outlaw non-abstract classes containing abstract members invisible from that classes (internal/package-private)
Deprecation cycle:
- < 1.5: introduce warning for the problematic classes
- >= 1.5: raise this warning to an error,
-XXLanguage:-ProhibitInvisibleAbstractMethodsInSuperclasses
can be used to temporarily revert to pre-1.5 behavior
Forbid using array based on non-reified type parameters as reified type arguments on JVM
Issue: KT-31227
Component: Core language
Incompatible change type: source
Short summary: Kotlin 1.5 will outlaw using array based on non-reified type parameters as reified type arguments on JVM
Deprecation cycle:
- < 1.5: introduce warning for the problematic calls
- >= 1.5: raise this warning to an error,
-XXLanguage:-ProhibitNonReifiedArraysAsReifiedTypeArguments
can be used to temporarily revert to pre-1.5 behavior
Forbid secondary enum class constructors which do not delegate to the primary constructor
Issue: KT-35870
Component: Core language
Incompatible change type: source
Short summary: Kotlin 1.5 will outlaw secondary enum class constructors which do not delegate to the primary constructor
Deprecation cycle:
- < 1.5: introduce warning for the problematic constructors
- >= 1.5: raise this warning to an error,
-XXLanguage:-RequiredPrimaryConstructorDelegationCallInEnums
can be used to temporarily revert to pre-1.5 behavior
Forbid exposing anonymous types from private inline functions
Issue: KT-33917
Component: Core language
Incompatible change type: source
Short summary: Kotlin 1.5 will outlaw exposing anonymous types from private inline functions
Deprecation cycle:
- < 1.5: introduce warning for the problematic constructors
- >= 1.5: raise this warning to an error,
-XXLanguage:-ApproximateAnonymousReturnTypesInPrivateInlineFunctions
can be used to temporarily revert to pre-1.5 behavior
Forbid passing non-spread arrays after arguments with SAM-conversion
Issue: KT-35224
Component: Core language
Incompatible change type: source
Short summary: Kotlin 1.5 will outlaw passing non-spread arrays after arguments with SAM-conversion
Deprecation cycle:
- 1.3.70: introduce warning for the problematic calls
- >= 1.5: raise this warning to an error,
-XXLanguage:-ProhibitVarargAsArrayAfterSamArgument
can be used to temporarily revert to pre-1.5 behavior
Support special semantics for underscore-named catch block parameters
Issue: KT-31567
Component: Core language
Incompatible change type: source
Short summary: Kotlin 1.5 will outlaw references to the underscore symbol (
_
) that is used to omit parameter name of an exception in the catch blockDeprecation cycle:
- 1.4.20: introduce warning for the problematic references
- >= 1.5: raise this warning to an error,
-XXLanguage:-ForbidReferencingToUnderscoreNamedParameterOfCatchBlock
can be used to temporarily revert to pre-1.5 behavior
Change implementation strategy of SAM conversion from anonymous class-based to invokedynamic
Issue: KT-44912
Component: Kotlin/JVM
Incompatible change type: behavioral
Short summary: Since Kotlin 1.5, implementation strategy of SAM (single abstract method) conversion will be changed from generating an anonymous class to using the
invokedynamic
JVM instructionDeprecation cycle:
- 1.5: change implementation strategy of SAM conversion,
-Xsam-conversions=class
can be used to revert implementation scheme to the one that used before
Performance issues with the JVM IR-based backend
Issue: KT-48233
Component: Kotlin/JVM
Incompatible change type: behavioral
Short summary: Kotlin 1.5 uses the IR-based backend for the Kotlin/JVM compiler by default. The old backend is still used by default for earlier language versions.
You might encounter some performance degradation issues using the new compiler in Kotlin 1.5. We are working on fixing such cases.
Deprecation cycle:
- < 1.5: by default, the old JVM backend is used
- >= 1.5: by default, the IR-based backend is used. If you need to use the old backend in Kotlin 1.5, add the following lines to the project's configuration file to temporarily revert to pre-1.5 behavior:
In Gradle:
>
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile> { kotlinOptions.useOldBackend = true }
tasks.withType(org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile) { kotlinOptions.useOldBackend = true }
In Maven:
<configuration> <args> <arg>-Xuse-old-backend</arg> </args> </configuration>
Support for this flag will be removed in one of the future releases.
New field sorting in the JVM IR-based backend
Issue: KT-46378
Component: Kotlin/JVM
Incompatible change type: behavioral
Short summary: Since version 1.5, Kotlin uses the IR-based backend that sorts JVM bytecode differently: it generates fields declared in the constructor before fields declared in the body, while it's vice versa for the old backend. The new sorting may change the behavior of programs that use serialization frameworks that depend on the field order, such as Java serialization.
Deprecation cycle:
- < 1.5: by default, the old JVM backend is used. It has fields declared in the body before fields declared in the constructor.
- >= 1.5: by default, the new IR-based backend is used. Fields declared in the constructor are generated before fields declared in the body. As a workaround, you can temporarily switch to the old backend in Kotlin 1.5. To do that, add the following lines to the project's configuration file:
In Gradle:
>
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile> { kotlinOptions.useOldBackend = true }
tasks.withType(org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile) { kotlinOptions.useOldBackend = true }
In Maven:
<configuration> <args> <arg>-Xuse-old-backend</arg> </args> </configuration>
Support for this flag will be removed in one of the future releases.
Generate nullability assertion for delegated properties with a generic call in the delegate expression
Issue: KT-44304
Component: Kotlin/JVM
Incompatible change type: behavioral
Short summary: Since Kotlin 1.5, the Kotlin compiler will emit nullability assertions for delegated properties with a generic call in the delegate expression
Deprecation cycle:
- 1.5: emit nullability assertion for delegated properties (see details in the issue),
-Xuse-old-backend
or-language-version 1.4
can be used to temporarily revert to pre-1.5 behavior
Turn warnings into errors for calls with type parameters annotated by @OnlyInputTypes
Issue: KT-45861
Component: Core language
Incompatible change type: source
Short summary: Kotlin 1.5 will outlaw calls like
contains
,indexOf
, andassertEquals
with senseless arguments to improve type safetyDeprecation cycle:
- 1.4.0: introduce warning for the problematic constructors
- >= 1.5: raise this warning to an error,
-XXLanguage:-StrictOnlyInputTypesChecks
can be used to temporarily revert to pre-1.5 behavior
Use the correct order of arguments execution in calls with named vararg
Issue: KT-17691
Component: Kotlin/JVM
Incompatible change type: behavioral
Short summary: Kotlin 1.5 will change the order of arguments execution in calls with named vararg
Deprecation cycle:
- < 1.5: introduce warning for the problematic constructors
- >= 1.5: raise this warning to an error,
-XXLanguage:-UseCorrectExecutionOrderForVarargArguments
can be used to temporarily revert to pre-1.5 behavior
Use default value of the parameter in operator functional calls
Issue: KT-42064
Component: Kotlin/JVM
Incompatible change type: behavioral
Short summary: Kotlin 1.5 will use default value of the parameter in operator calls
Deprecation cycle:
- < 1.5: old behavior (see details in the issue)
- >= 1.5: behavior changed,
-XXLanguage:-JvmIrEnabledByDefault
can be used to temporarily revert to pre-1.5 behavior
Produce empty reversed progressions in for loops if regular progression is also empty
Issue: KT-42533
Component: Kotlin/JVM
Incompatible change type: behavioral
Short summary: Kotlin 1.5 will produce empty reversed progressions in for loops if regular progression is also empty
Deprecation cycle:
- < 1.5: old behavior (see details in the issue)
- >= 1.5: behavior changed,
-XXLanguage:-JvmIrEnabledByDefault
can be used to temporarily revert to pre-1.5 behavior
Straighten Char-to-code and Char-to-digit conversions out
Issue: KT-23451
Component: kotlin-stdlib
Incompatible change type: source
Short summary: Since Kotlin 1.5, conversions of Char to number types will be deprecated
Deprecation cycle:
- 1.5: deprecate
Char.toInt()/toShort()/toLong()/toByte()/toDouble()/toFloat()
and the reverse functions likeLong.toChar()
, and propose replacement
Inconsistent case-insensitive comparison of characters in kotlin.text functions
Issue: KT-45496
Component: kotlin-stdlib
Incompatible change type: behavioral
Short summary: Since Kotlin 1.5,
Char.equals
will be improved in case-insensitive case by first comparing whether the uppercase variants of characters are equal, then whether the lowercase variants of those uppercase variants (as opposed to the characters themselves) are equalDeprecation cycle:
- < 1.5: old behavior (see details in the issue)
- 1.5: change behavior for
Char.equals
function
Remove default locale-sensitive case conversion API
Issue: KT-43023
Component: kotlin-stdlib
Incompatible change type: source
Short summary: Since Kotlin 1.5, default locale-sensitive case conversion functions like
String.toUpperCase()
will be deprecatedDeprecation cycle:
- 1.5: deprecate case conversions functions with the default locale (see details in the issue), and propose replacement
Gradually change the return type of collection min
and max
functions to non-nullable
Issue: KT-38854
Component: kotlin-stdlib (JVM)
Incompatible change type: source
Short summary: return type of collection
min
andmax
functions will be changed to non-nullable in 1.6Deprecation cycle:
- 1.4: introduce
...OrNull
functions as synonyms and deprecate the affected API (see details in the issue)- 1.5.0: raise the deprecation level of the affected API to error
- >=1.6: reintroduce the affected API but with non-nullable return type
Raise the deprecation level of conversions of floating-point types to Short
and Byte
Issue: KT-30360
Component: kotlin-stdlib (JVM)
Incompatible change type: source
Short summary: conversions of floating-point types to
Short
andByte
deprecated in Kotlin 1.4 withWARNING
level will cause errors since Kotlin 1.5.0.Deprecation cycle:
- 1.4: deprecate
Double.toShort()/toByte()
andFloat.toShort()/toByte()
and propose replacement- 1.5.0: raise the deprecation level to error
Tools
Do not mix several JVM variants of kotlin-test in a single project
Issue: KT-40225
Component: Gradle
Incompatible change type: behavioral
Short summary: several mutually exclusive
kotlin-test
variants for different testing frameworks could have been in a project if one of them is brought by a transitive dependency. From 1.5.0, Gradle won't allow having mutually exclusivekotlin-test
variants for different testing frameworks.Deprecation cycle:
- < 1.5: having several mutually exclusive
kotlin-test
variants for different testing frameworks is allowed- >= 1.5: behavior changed,
Gradle throws an exception like "Cannot select module with conflict on capability...". Possible solutions:
- use the same
kotlin-test
variant and the corresponding testing framework as the transitive dependency brings.- find another variant of the dependency that doesn't bring the
kotlin-test
variant transitively, so you can use the testing framework you would like to use.- find another variant of the dependency that brings another
kotlin-test
variant transitively, which uses the same testing framework you would like to use.- exclude the testing framework that is brought transitively. The following example is for excluding JUnit 4:
After excluding the testing framework, test your application. If it stopped working, rollback excluding changes, use the same testing framework as the library does, and exclude your testing framework.
configurations { testImplementation.get().exclude("org.jetbrains.kotlin", "kotlin-test-junit") }