13.6.4.3 Kotlin 2.0.x 兼容性指南
12 分钟阅读
原文链接: https://kotlinlang.org/docs/compatibility-guide-20.html
13.6.4.3 Kotlin 2.0.x 兼容性指南
保持语言的现代性 和 舒适的更新 是 Kotlin 语言设计中的基本原则。前者指出,阻碍语言演进的构造应该被移除;后者指出,这种移除应事先充分沟通,以便代码迁移尽可能顺畅。
虽然大多数语言变更已经通过其他渠道公布过(例如更新日志或编译器警告),但本文为从 Kotlin 1.9 迁移到 Kotlin 2.0 提供完整参考。
注意: Kotlin K2 编译器是作为 Kotlin 2.0 的一部分引入的。关于新编译器的优势、迁移期间可能遇到的变更以及如何回退到之前的编译器,请参阅 K2 编译器迁移指南。
基本术语
本文介绍了以下几种兼容性:
- 源码级:源码不兼容的变更会让原本能正常编译(无错误或警告)的代码不再能编译
- 二进制级:如果互换两个二进制产物不会导致加载或链接错误,则称它们是二进制兼容的
- 行为级:如果同一个程序在应用变更前后的行为不同,则该变更属于行为不兼容
请记住,这些定义仅针对纯 Kotlin。从其他语言(例如 Java)的视角来看 Kotlin 代码的兼容性不在本文讨论范围内。
语言
弃用在投影接收者上使用合成 setter
Issue:KT-54309 组件:核心语言 不兼容变更类型:源码级 简要说明:如果你使用 Java 类的合成 setter 赋一个与该类的投影类型冲突的值,就会触发错误。弃用周期:- 1.8.20:当合成属性 setter 在逆变位置上有投影参数类型、导致调用点实参类型不兼容时报告警告 - 2.0.0:把该警告提升为错误
修正调用在 Java 子类中被重载的、带内联类参数的函数时的名称改写
Issue:KT-56545 组件:核心语言 不兼容变更类型:行为级 弃用周期:- 2.0.0:在函数调用中使用正确的名称改写行为;要恢复之前的行为,请使用
-XXLanguage:-MangleCallsToJavaMethodsWithValueClasses编译器选项。
修正逆变捕获类型的类型近似算法
Issue:KT-49404 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 1.8.20:对有问题的调用报告警告 - 2.0.0:把该警告提升为错误
禁止在属性初始化之前访问属性值
Issue:KT-56408 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 2.0.0:在受影响的上下文中,当属性在初始化之前被访问时报告错误
当同名的已导入类存在歧义时报告错误
Issue:KT-57750 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 2.0.0:当解析一个出现在多个通过星号导入的包中的类名时报告错误
默认通过 invokedynamic 和 LambdaMetafactory 生成 Kotlin lambda
Issue:KT-45375 组件:核心语言 不兼容变更类型:行为级 弃用周期:- 2.0.0:实现新行为;lambda 默认使用
invokedynamic和LambdaMetafactory生成
在需要表达式时禁止只有单个分支的 if 条件
Issue:KT-57871 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 2.0.0:如果
if条件只有一个分支则报告错误
禁止通过传入泛型类型的星投影来违反自身上界
Issue:KT-61718 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 2.0.0:当通过传入泛型类型的星投影违反自身上界时报告错误
在私有内联函数的返回类型中近似匿名类型
Issue:KT-54862 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 1.9.0:如果推断出的返回类型包含匿名类型,则对私有内联函数报告警告 - 2.0.0:把这类私有内联函数的返回类型近似为一个父类型
修改重载解析行为,优先调用局部扩展函数而不是局部函数类型属性的 invoke 约定
Issue:KT-37592 组件:核心语言 不兼容变更类型:行为级 弃用周期:- 2.0.0:新的重载解析行为;函数调用一致地优先于 invoke 约定
当二进制依赖中的父类型变化导致继承成员冲突时报告错误
Issue:KT-51194 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 1.7.0:对在来自二进制依赖的父类型中发生继承成员冲突的声明报告警告 CONFLICTING_INHERITED_MEMBERS_WARNING - 2.0.0:把该警告提升为错误:CONFLICTING_INHERITED_MEMBERS
忽略不变类型参数上的 @UnsafeVariance 注解
Issue:KT-57609 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 2.0.0:实现新行为;在对逆变参数的类型不匹配报错时会忽略
@UnsafeVariance注解
修改对伴生对象成员的调用外引用的类型
Issue:KT-54316 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 1.8.20:对推断为未绑定引用的伴生对象函数引用类型报告警告 - 2.0.0:修改行为,使伴生对象函数引用在所有使用上下文中都被推断为绑定引用
禁止从私有内联函数暴露匿名类型
Issue:KT-33917 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 1.3.0:对从私有内联函数返回的匿名对象自身成员的调用报告警告 - 2.0.0:把这类私有内联函数的返回类型近似为父类型,并且不再解析对匿名对象成员的调用
对 while 循环 break 之后不健全的智能转换报告错误
Issue:KT-22379 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 2.0.0:实现新行为;切换回语言版本 1.9 可以恢复旧行为
当为交叉类型的变量赋一个不是该交叉类型子类型的值时报告错误
Issue:KT-53752 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 2.0.0:当交叉类型的变量被赋一个不是该交叉类型子类型的值时报告错误
当通过 SAM 构造器构造的接口包含需要选择启用的方法时要求选择启用
Issue:KT-52628 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 1.7.20:对通过 SAM 构造器使用
OptIn的情况报告警告 - 2.0.0:把通过 SAM 构造器使用OptIn的警告提升为错误(或者当OptIn标记的严重性为警告时继续报告警告)
禁止在类型别名构造器中违反上界
Issue:KT-54066 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 1.8.0:对在类型别名构造器中违反上界的情况引入警告 - 2.0.0:在 K2 编译器中把该警告提升为错误
让解构变量的真实类型在指定显式类型时与之一致
Issue:KT-57011 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 2.0.0:实现新行为;当指定了显式类型时,解构变量的真实类型现在与该显式类型一致
调用其参数类型的默认值需要选择启用的构造器时要求选择启用
Issue:KT-55111 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 1.8.20:对参数类型需要选择启用的构造器调用报告警告 - 2.0.0:把该警告提升为错误(或者当
OptIn标记的严重性为警告时继续报告警告)
报告同一作用域层级中同名属性与枚举条目之间的歧义
Issue:KT-52802 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 1.7.20:当编译器在同一作用域层级解析到属性而不是枚举条目时报告警告 - 2.0.0:在 K2 编译器中,当编译器在同一作用域层级同时遇到同名属性和枚举条目时报告歧义(旧编译器中仍保持警告)
修改限定符解析行为,优先选择伴生属性而不是枚举条目
Issue:KT-47310 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 2.0.0:实现新的解析行为;优先选择伴生属性而不是枚举条目
像脱糖写法那样解析 invoke 调用的接收者类型与 invoke 函数类型
Issue:KT-58260 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 2.0.0:像脱糖写法那样独立解析 invoke 调用的接收者类型和 invoke 函数类型
禁止通过非私有内联函数暴露私有类成员
Issue:KT-55179 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 1.9.0:当从 internal 内联函数调用私有类的伴生对象成员时报告
PRIVATE_CLASS_MEMBER_FROM_INLINE_WARNING警告 - 2.0.0:把该警告提升为PRIVATE_CLASS_MEMBER_FROM_INLINE错误
修正投影泛型类型中“确定为非空”类型的可空性
Issue:KT-54663 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 2.0.0:实现新行为;投影类型会考虑所有就地非空类型
修改前缀自增的推断类型,使其与 getter 的返回类型一致,而不是 inc() 运算符的返回类型
Issue:KT-57178 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 2.0.0:实现新行为;前缀自增的推断类型改为与 getter 的返回类型一致,而不是
inc()运算符的返回类型
在从父类中声明的泛型内部类继承内部类时实施边界检查
Issue:KT-61749 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 2.0.0:当违反泛型内部父类的类型参数上界时报告错误
当期望类型是带函数类型参数的函数类型时,禁止赋值 SAM 类型的可调用引用
Issue:KT-64342 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 2.0.0:当期望类型是带函数类型参数的函数类型时,对 SAM 类型的可调用引用报告编译错误
在为伴生对象上的注解做解析时考虑伴生对象作用域
Issue:KT-64299 组件:核心语言 不兼容变更类型:行为级 弃用周期:- 2.0.0:实现新行为;在为伴生对象上的注解做解析时,不再忽略伴生对象作用域
修改安全调用与约定运算符组合的求值语义
Issue:KT-41034 组件:核心语言 不兼容变更类型:行为级 弃用周期:- 1.4.0:对每个不正确的调用报告警告 - 2.0.0:实现新的解析行为
要求带幕后字段和自定义 setter 的属性立即初始化
Issue:KT-58589 组件:核心语言 不兼容变更类型:行为级 弃用周期:- 1.9.20:对没有主构造器的情况引入
MUST_BE_INITIALIZED警告 - 2.0.0:把该警告提升为错误
禁止在 invoke 运算符约定调用中对任意表达式做 Unit 转换
Issue:KT-61182 组件:核心语言 不兼容变更类型:行为级 弃用周期:- 2.0.0:在变量解析和 invoke 解析中,当对任意表达式应用 Unit 转换时报告错误;使用
-XXLanguage:+UnitConversionsOnArbitraryExpressions编译器选项可以让受影响的表达式保持之前的行为。
当通过安全调用访问非空 Java 字段时,禁止为其赋可空值
Issue:KT-62998 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 2.0.0:如果给非空 Java 字段赋可空值,则报告错误
覆盖包含原始类型参数的 Java 方法时要求使用星投影类型
Issue:KT-57600 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 2.0.0:实现新行为;禁止对原始类型参数进行覆盖
当 V 有伴生对象时修改 (V)::foo 引用的解析
Issue:KT-47313 组件:核心语言 不兼容变更类型:行为级 弃用周期:- 1.6.0:对目前绑定到伴生对象实例的可调用引用报告警告 - 2.0.0:实现新行为;在类型两边加括号不再使它成为对该类型伴生对象实例的引用
禁止在实际上公开的内联函数中隐式访问非公开 API
Issue:KT-54997 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 1.8.20:在公共内联函数中隐式访问非公开 API 时报告编译警告 - 2.0.0:把该警告提升为错误
禁止在属性 getter 上使用使用处 get 注解
Issue:KT-57422 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 1.9.0:对 getter 上的使用处
get注解报告警告(在渐进模式下报告错误)- 2.0.0:把该警告提升为INAPPLICABLE_TARGET_ON_PROPERTY错误;使用-XXLanguage:-ProhibitUseSiteGetTargetAnnotations可以恢复为警告
禁止在构建器推断 lambda 函数中把类型参数隐式推断为上界
Issue:KT-47986 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 1.7.20:当类型实参对应的类型参数无法被推断进声明的上界时报告警告(在渐进模式下报告错误)- 2.0.0:把该警告提升为错误
在公共签名中近似局部类型时保留可空性
Issue:KT-53982 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 1.8.0:用灵活的父类型近似灵活类型;当某个声明被推断为不可为空、但本应可为空的类型时报告警告,提示显式指定类型以避免 NPE - 2.0.0:用可为空的父类型近似可为空的类型
出于智能转换的目的,移除对 false && … 和 false || … 的特殊处理
Issue:KT-65776 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 2.0.0:实现新行为;对
false && ...和false || ...不再做特殊处理
禁止在枚举中使用 inline open 函数
Issue:KT-34372 组件:核心语言 不兼容变更类型:源码级 弃用周期:- 1.8.0:对枚举中的 inline open 函数报告警告 - 2.0.0:把该警告提升为错误
工具
Gradle 中的可见性变化
Issue:KT-64653 组件:Gradle 不兼容变更类型:源码级 简要说明:此前,某些针对特定 DSL 上下文设计保留的 Kotlin DSL 函数和属性会无意间泄漏到其他 DSL 上下文中。我们添加了
@KotlinGradlePluginDsl注解,它会阻止把 Kotlin Gradle 插件 DSL 的函数和属性暴露到它们不应可用的层级。以下层级彼此分隔:* Kotlin 扩展 * Kotlin 目标 * Kotlin 编译 * Kotlin 编译任务 弃用周期:- 2.0.0:对于最常见的情况,如果你的构建脚本配置不正确,编译器会报告警告并给出修复建议;其他情况下则报告错误
弃用 kotlinOptions DSL
Issue:KT-63419 组件:Gradle 不兼容变更类型:源码级 简要说明:通过
kotlinOptionsDSL 及相关KotlinCompile<KotlinOptions>任务接口配置编译器选项的能力已被弃用。弃用周期:- 2.0.0:报告警告
弃用 KotlinCompilation DSL 中的 compilerOptions
Issue:KT-65568 组件:Gradle 不兼容变更类型:源码级 简要说明:在
KotlinCompilationDSL 中配置compilerOptions属性的能力已被弃用。弃用周期:- 2.0.0:报告警告
弃用旧的 CInteropProcess 处理方式
Issue:KT-62795 组件:Gradle 不兼容变更类型:源码级 简要说明:
CInteropProcess任务和CInteropSettings类现在使用definitionFile属性,而不再使用defFile和defFileProperty。这样当defFile是动态生成时,就不再需要在CInteropProcess任务与生成defFile的任务之间添加额外的dependsOn关系。在 Kotlin/Native 项目中,Gradle 现在会在相关任务于构建过程中稍后运行之后,惰性地校验definitionFile属性是否存在。弃用周期:- 2.0.0:defFile和defFileProperty参数被弃用 - 2.4.0:对已弃用的defFile属性报告错误
移除 kotlin.useK2 Gradle 属性
Issue:KT-64379 组件:Gradle 不兼容变更类型:行为级 简要说明:
kotlin.useK2Gradle 属性已被移除。在 Kotlin 1.9.* 中,它可用于启用 K2 编译器。在 Kotlin 2.0.0 及更高版本中,K2 编译器默认启用,因此该属性没有效果,也不能用来切换回之前的编译器。弃用周期:- 1.8.20:kotlin.useK2Gradle 属性被弃用 - 2.0.0:kotlin.useK2Gradle 属性被移除
移除已弃用的平台插件 ID
Issue:KT-65187 组件:Gradle 不兼容变更类型:源码级 简要说明:已移除对这些平台插件 ID 的支持:*
kotlin-platform-android*kotlin-platform-jvm*kotlin-platform-js*org.jetbrains.kotlin.platform.android*org.jetbrains.kotlin.platform.jvm*org.jetbrains.kotlin.platform.js弃用周期:- 1.3:这些平台插件 ID 被弃用 - 2.0.0:这些平台插件 ID 不再受支持
移除 outputFile JavaScript 编译器选项
Issue:KT-61116 组件:Gradle 不兼容变更类型:源码级 简要说明:
outputFileJavaScript 编译器选项已被移除。你可以改用Kotlin2JsCompile任务的destinationDirectory属性来指定编译后的 JavaScript 输出文件写入的目录。弃用周期:- 1.9.25:outputFile编译器选项被弃用 - 2.0.0:outputFile编译器选项被移除