13.6.7.4 Kotlin 1.7.0 兼容性指南

原文链接: https://kotlinlang.org/docs/compatibility-guide-17.html

13.6.7.4 Kotlin 1.7.0 兼容性指南

保持语言现代性 和 平滑升级 是 Kotlin 语言设计的基本原则。前者指出,阻碍语言演进的构造应当被移除;后者指出,这种移除应当事先充分沟通,以便代码迁移尽可能顺畅。

虽然大多数语言变更已经通过其他渠道公布(例如更新日志或编译器警告),本文仍然把它们全部汇总,为从 Kotlin 1.6 迁移到 Kotlin 1.7 提供完整参考。

基本术语

本文介绍几种兼容性:

  • 源码:源码不兼容的变更会让原本能正常编译(没有错误或警告)的代码无法再编译
  • 二进制:如果互换两个二进制构件不会导致加载或链接错误,就称它们是二进制兼容的
  • 行为:如果同一个程序在应用变更前后表现出不同行为,就称该变更是行为不兼容的

请记住,这些定义仅针对纯 Kotlin。从其他语言(例如 Java)的视角来看 Kotlin 代码的兼容性不在本文讨论范围内。

语言

让安全调用的结果始终可空

问题:KT-46860 组件:核心语言 不兼容变更类型:源码 简要说明:Kotlin 1.7 会把安全调用的结果类型始终视为可空,即使安全调用的接收者是非空的 弃用周期:- <1.3:对非空接收者上不必要的安全调用报告警告 - 1.6.20:额外警告该不必要的安全调用的结果类型将在下个版本中改变 - 1.7.0:把安全调用结果的类型改为可空,可以使用 -XXLanguage:-SafeCallsAreAlwaysNullable 暂时回退到 1.7 之前的行为

禁止把 super 调用委托给抽象的超类成员

问题:KT-45508、KT-49017、KT-38078 组件:核心语言 不兼容变更类型:源码 简要说明:当显式或隐式的 super 调用被委托给超类的_抽象_成员时,Kotlin 会报告编译错误,即使超接口中有默认实现 弃用周期:- 1.5.20:当未重写全部抽象成员的非抽象类被使用时引入警告 - 1.6.0:在渐进模式下把该警告升级为错误 - 1.7.0:把该警告升级为错误

禁止通过非 public 主构造函数中声明的 public 属性暴露非 public 类型

问题:KT-28078 组件:核心语言 不兼容变更类型:源码 简要说明:Kotlin 将禁止在私有主构造函数中声明类型为非 public 的 public 属性。从其他包访问这类属性可能导致 IllegalAccessError 弃用周期:- 1.3.20:对类型非 public 且在非 public 构造函数中声明的 public 属性报告警告 - 1.6.20:在渐进模式下把该警告升级为错误 - 1.7.0:把该警告升级为错误

禁止通过枚举名访问未初始化的枚举项

问题:KT-41124 组件:核心语言 不兼容变更类型:源码 简要说明:当这些枚举项通过枚举名限定时,Kotlin 1.7 将禁止从枚举的静态初始化块访问未初始化的枚举项 弃用周期:- 1.7.0:当从枚举的静态初始化块访问未初始化的枚举项时报告错误

禁止在 when 条件分支和循环条件中计算复杂布尔表达式的常量值

问题:KT-39883 组件:核心语言 不兼容变更类型:源码 简要说明:Kotlin 将不再基于字面量 true 和 false 之外的常量布尔表达式做出穷尽性和控制流假设 弃用周期:- 1.5.30:当 when 的穷尽性或控制流可达性是基于 when 分支或循环条件中的复杂常量布尔表达式判定时,报告警告 - 1.7.0:把该警告升级为错误

让带枚举、密封类和布尔主语的 when 语句默认具有穷尽性

问题:KT-47709 组件:核心语言 不兼容变更类型:源码 简要说明:Kotlin 1.7 会对主语为枚举、密封类或布尔的 when 语句不具备穷尽性报告错误 弃用周期:- 1.6.0:当主语为枚举、密封类或布尔的 when 语句不具备穷尽性时引入警告(渐进模式下为错误)- 1.7.0:把该警告升级为错误

弃用 when-with-subject 中容易混淆的语法

问题:KT-48385 组件:核心语言 不兼容变更类型:源码 简要说明:Kotlin 1.6 弃用了 when 条件表达式中的若干容易混淆的语法结构 弃用周期:- 1.6.20:对受影响的表达式引入弃用警告 - 1.8.0:把该警告升级为错误 - >= 1.8:把某些已弃用的构造重新用于新的语言特性

类型可空性增强的改进

问题:KT-48623 组件:Kotlin/JVM 不兼容变更类型:源码 简要说明:Kotlin 1.7 将改变它加载和解释 Java 代码中类型可空性注解的方式 弃用周期:- 1.4.30:对更精确的类型可空性可能导致错误的情况引入警告 - 1.7.0:推断更精确的 Java 类型可空性,可以使用 -XXLanguage:-TypeEnhancementImprovementsInStrictMode 暂时回退到 1.7 之前的行为

防止不同数值类型之间的隐式强制转换

问题:KT-48645 组件:Kotlin/JVM 不兼容变更类型:行为 简要说明:当语义上只需要向下转换到某个基本数值类型时,Kotlin 将避免把数值自动转换为该类型 弃用周期:- < 1.5.30:所有受影响的情况下都保持旧行为 - 1.5.30:修复生成的属性委托访问器中的向下转换行为,可以使用 -Xuse-old-backend 暂时回退到 1.5.30 修复之前的行为 - >= 1.7.20:修复其他受影响情况下的向下转换行为

弃用 -Xjvm-default 编译器选项的 enable 和 compatibility 模式

问题:KT-46329 组件:Kotlin/JVM 不兼容变更类型:源码 简要说明:Kotlin 1.6.20 对使用 -Xjvm-default 编译器选项的 enable 和 compatibility 模式发出警告 弃用周期:- 1.6.20:对 -Xjvm-default 编译器选项的 enable 和 compatibility 模式引入警告 - >= 1.8.0:把该警告升级为错误

禁止调用名为 suspend 且带尾随 lambda 的函数

问题:KT-22562 组件:核心语言 不兼容变更类型:源码 简要说明:Kotlin 1.6 不再允许调用名为 suspend、其唯一参数为函数类型并以尾随 lambda 形式传入的用户函数 弃用周期:- 1.3.0:对这类函数调用引入警告 - 1.6.0:把该警告升级为错误 - 1.7.0:修改语言语法,使 { 之前的 suspend 被解析为关键字

当基类来自其他模块时,禁止对基类属性做智能转换

问题:KT-52629 组件:核心语言 不兼容变更类型:源码 简要说明:如果超类位于另一个模块中,Kotlin 1.7 将不再允许对该超类的属性做智能转换 弃用周期:- 1.6.0:对位于另一个模块中的超类所声明属性上的智能转换报告警告 - 1.7.0:把该警告升级为错误,可以使用 -XXLanguage:-ProhibitSmartcastsOnPropertyFromAlienBaseClass 暂时回退到 1.7 之前的行为

在类型推断中不要忽略有意义的约束

问题:KT-52668 组件:核心语言 不兼容变更类型:源码 简要说明:由于一处不正确的优化,Kotlin 1.4−1.6 在类型推断期间忽略了一些类型约束。这可能允许编写不健全的代码,从而在运行时导致 ClassCastException。Kotlin 1.7 会把这些问题纳入考虑,从而禁止不健全的代码 弃用周期:- 1.5.20:如果考虑所有类型推断约束后会出现类型不匹配,则对这些表达式报告警告 - 1.7.0:考虑所有约束,从而把该警告升级为错误,可以使用 -XXLanguage:-ProperTypeInferenceConstraintsProcessing 暂时回退到 1.7 之前的行为

标准库

逐步把集合 min 与 max 函数的返回类型改为非空

问题:KT-38854 组件:kotlin-stdlib 不兼容变更类型:源码 简要说明:集合 min 和 max 函数的返回类型将在 Kotlin 1.7 中改为非空 弃用周期:- 1.4.0:引入 ...OrNull 函数作为同义函数,并弃用受影响的 API(细节见该问题)- 1.5.0:把受影响 API 的弃用级别提升为错误 - 1.6.0:把已弃用的函数从公开 API 中隐藏 - 1.7.0:重新引入受影响的 API,但返回类型为非空

弃用浮点数组函数:contains、indexOf、lastIndexOf

问题:KT-28753 组件:kotlin-stdlib 不兼容变更类型:源码 简要说明:Kotlin 弃用了使用 IEEE-754 顺序(而不是全序)比较值的浮点数组函数 contains、indexOf、lastIndexOf 弃用周期:- 1.4.0:以警告级别弃用受影响的函数 - 1.6.0:把弃用级别提升为错误 - 1.7.0:把已弃用的函数从公开 API 中隐藏

把声明从 kotlin.dom 和 kotlin.browser 包迁移到 kotlinx.*

问题:KT-39330 组件:kotlin-stdlib (JS) 不兼容变更类型:源码 简要说明:为准备把它们从标准库中抽取出来,kotlin.dom 和 kotlin.browser 包中的声明被移到相应的 kotlinx.* 包中 弃用周期:- 1.4.0:在 kotlinx.dom 和 kotlinx.browser 包中引入替代 API - 1.4.0:弃用 kotlin.dom 和 kotlin.browser 包中的 API,并把上面的新 API 作为替代方案 - 1.6.0:把弃用级别提升为错误 - >= 1.8:从标准库中移除已弃用的函数 - >= 1.8:把 kotlinx.* 包中的 API 移到单独的库

弃用部分仅 JS 的 API

问题:KT-48587 组件:kotlin-stdlib (JS) 不兼容变更类型:源码 简要说明:标准库中若干仅 JS 的函数被弃用并将在未来移除。它们包括:String.concat(String)、String.match(regex: String)、String.matches(regex: String),以及数组上接受比较函数的 sort 函数,例如 Array<out T>.sort(comparison: (a: T, b: T) -> Int) 弃用周期:- 1.6.0:以警告级别弃用受影响的函数 - 1.8.0:把弃用级别提升为错误 - 1.9.0:把已弃用的函数从公开 API 中移除

工具

移除 KotlinGradleSubplugin 类

问题:KT-48831 组件:Gradle 不兼容变更类型:源码 简要说明:移除 KotlinGradleSubplugin 类。请改用 KotlinCompilerPluginSupportPlugin 类 弃用周期:- 1.6.0:把弃用级别提升为错误 - 1.7.0:移除已弃用的类

移除 useIR 编译器选项

问题:KT-48847 组件:Gradle 不兼容变更类型:源码 简要说明:移除已弃用且隐藏的 useIR 编译器选项 弃用周期:- 1.5.0:把弃用级别提升为警告 - 1.6.0:隐藏该选项 - 1.7.0:移除已弃用的选项

弃用 kapt.use.worker.api Gradle 属性

问题:KT-48826 组件:Gradle 不兼容变更类型:源码 简要说明:弃用 kapt.use.worker.api 属性,它曾用于允许通过 Gradle Workers API 运行 kapt(默认值:true) 弃用周期:- 1.6.20:把弃用级别提升为警告 - >= 1.8.0:移除该属性

移除 kotlin.experimental.coroutines Gradle DSL 选项和 kotlin.coroutines Gradle 属性

问题:KT-50494 组件:Gradle 不兼容变更类型:源码 简要说明:移除 kotlin.experimental.coroutines Gradle DSL 选项和 kotlin.coroutines 属性 弃用周期:- 1.6.20:把弃用级别提升为警告 - 1.7.0:移除该 DSL 选项、包含它的 experimental 块以及该属性

弃用 useExperimentalAnnotation 编译器选项

问题:KT-47763 组件:Gradle 不兼容变更类型:源码 简要说明:移除隐藏的 useExperimentalAnnotation() Gradle 函数,它曾用于在模块中选择启用某个 API。可以改用 optIn() 函数 弃用周期: - 1.6.0:隐藏该弃用选项 - 1.7.0:移除已弃用的选项

弃用 kotlin.compiler.execution.strategy 系统属性

问题:KT-51830 组件:Gradle 不兼容变更类型:源码 简要说明:弃用用于选择编译器执行策略的 kotlin.compiler.execution.strategy 系统属性。请改用 Gradle 属性 kotlin.compiler.execution.strategy 或编译任务属性 compilerExecutionStrategy 弃用周期: - 1.7.0:把弃用级别提升为警告 - > 1.7.0:移除该属性

移除 kotlinOptions.jdkHome 编译器选项

问题:KT-46541 组件:Gradle 不兼容变更类型:源码 简要说明:移除 kotlinOptions.jdkHome 编译器选项,它曾用于把指定位置的自定义 JDK 加入 classpath 而不是使用默认的 JAVA_HOME。请改用 Java 工具链 弃用周期: - 1.5.30:把弃用级别提升为警告 - > 1.7.0:移除该选项

移除 noStdlib 编译器选项

问题:KT-49011 组件:Gradle 不兼容变更类型:源码 简要说明:移除 noStdlib 编译器选项。Gradle 插件使用 kotlin.stdlib.default.dependency=true 属性来控制是否引入 Kotlin 标准库 弃用周期: - 1.5.0:把弃用级别提升为警告 - 1.7.0:移除该选项

移除 kotlin2js 和 kotlin-dce-plugin 插件

问题:KT-48276 组件:Gradle 不兼容变更类型:源码 简要说明:移除 kotlin2js 和 kotlin-dce-plugin 插件。请用新的 org.jetbrains.kotlin.js 插件替代 kotlin2js。只要正确配置 Kotlin/JS Gradle 插件,死代码消除(DCE)就会工作

弃用周期: - 1.4.0:把弃用级别提升为警告 - 1.7.0:移除这些插件

编译任务的变化

问题:KT-32805 组件:Gradle 不兼容变更类型:源码 简要说明:Kotlin 编译任务不再继承 Gradle 的 AbstractCompile 任务,因此 Kotlin 用户的脚本中不再能使用 sourceCompatibility 和 targetCompatibility 输入。SourceTask.stableSources 输入不再可用。sourceFilesExtensions 输入已被移除。已弃用的 Gradle destinationDir: File 输出被替换为 destinationDirectory: DirectoryProperty 输出。KotlinCompile 任务的 classpath 属性已被弃用 弃用周期: - 1.7.0:这些输入不可用,输出被替换,classpath 属性被弃用