13.6.6.3 Kotlin 1.8.x 兼容性指南

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

13.6.6.3 Kotlin 1.8.x 兼容性指南

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

虽然大多数语言变更已经通过其他渠道公布过(例如更新日志或编译器警告),但本文汇总了所有这些变更,为从 Kotlin 1.7 迁移到 Kotlin 1.8 提供完整参考。

基本术语

本文介绍了以下几种兼容性:

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

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

语言

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

Issues:KT-45508、KT-49017、KT-38078 组件:核心语言 不兼容变更类型:源码级 简要说明:当显式或隐式的父调用被委托给父类的_抽象_成员时,Kotlin 会报告编译错误,即使父接口中存在默认实现 弃用周期:- 1.5.20:当使用未覆盖所有抽象成员的非抽象类时引入警告 - 1.7.0:如果父调用实际上访问的是父类中的抽象成员,则报告警告 - 1.7.0:如果启用了 -Xjvm-default=all 或 -Xjvm-default=all-compatibility 兼容模式,则在所有受影响的情况下报告错误;在渐进模式下也报告错误 - 1.8.0:在声明具体类但未覆盖父类抽象方法、以及 Any 方法的父调用在父类中被覆盖为抽象的情况下报告错误 - 1.9.0:在所有受影响的情况下报告错误,包括对父类抽象方法的显式父调用

弃用 when 带主语中令人困惑的语法

Issue:KT-48385 组件:核心语言 不兼容变更类型:源码级 简要说明:Kotlin 1.6 弃用了 when 条件表达式中若干令人困惑的语法构造 弃用周期:- 1.6.20:对受影响的表达式引入弃用警告 - 1.8.0:把该警告提升为错误,可以用 -XXLanguage:-ProhibitConfusingSyntaxInWhenBranches 临时回退到 1.8 之前的行为 - >= 1.9:把某些已弃用的构造重新用于新的语言特性

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

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

让密封类的私有构造器真正私有

Issue:KT-44866 组件:核心语言 不兼容变更类型:源码级 简要说明:在放宽了密封类继承者可以声明在项目结构中何处的限制之后,密封类构造器的默认可见性变为 protected。然而直到 1.8,Kotlin 仍然允许在这些类的范围之外调用显式声明的私有构造器 弃用周期:- 1.6.20:在该类之外调用密封类的私有构造器时报告警告(在渐进模式下报告错误)- 1.8.0:对私有构造器采用默认的可见性规则(只有在相应类内部才能解析对私有构造器的调用),可以通过指定 -XXLanguage:-UseConsistentRulesForPrivateConstructorsOfSealedClasses 编译器参数临时恢复旧行为

禁止在构建器推断上下文中对不兼容的数值类型使用运算符 ==

Issue:KT-45508 组件:核心语言 不兼容变更类型:源码级 简要说明:Kotlin 1.8 将在构建器推断 lambda 函数的作用域中,禁止对不兼容的数值类型(例如 Int 和 Long)使用运算符 ==,就像它目前在其他上下文中已禁止的那样 弃用周期:- 1.6.20:对不兼容数值类型使用运算符 == 时报告警告(在渐进模式下报告错误)- 1.8.0:把该警告提升为错误,可以用 -XXLanguage:-ProperEqualityChecksInBuilderInferenceCalls 临时回退到 1.8 之前的行为

禁止在 Elvis 运算符右侧使用没有 else 的 if 和非完备的 when

Issue:KT-44705 组件:核心语言 不兼容变更类型:源码级 简要说明:Kotlin 1.8 将禁止在 Elvis 运算符(?:)右侧使用非完备的 when 或没有 else 分支的 if 表达式。此前,如果 Elvis 运算符的结果没有被当作表达式使用,则允许这样做 弃用周期:- 1.6.20:对此类非完备的 if 和 when 表达式报告警告(在渐进模式下报告错误)- 1.8.0:把该警告提升为错误,可以用 -XXLanguage:-ProhibitNonExhaustiveIfInRhsOfElvis 临时回退到 1.8 之前的行为

禁止在泛型类型别名使用中违反上界(一个类型参数用于别名类型的多个类型实参)

Issues:KT-29168 组件:核心语言 不兼容变更类型:源码级 简要说明:当类型别名的某个类型参数被用在别名类型的多个类型实参中时(例如 typealias Alias<T> = Base<T, T>),Kotlin 1.8 将禁止使用违反别名类型相应类型参数上界限制的类型实参来使用该类型别名 弃用周期:- 1.7.0:对使用违反别名类型相应类型参数上界约束的类型实参的类型别名用法报告警告(在渐进模式下报告错误)- 1.8.0:把该警告提升为错误,可以用 -XXLanguage:-ReportMissingUpperBoundsViolatedErrorOnAbbreviationAtSupertypes 临时回退到 1.8 之前的行为

禁止在泛型类型别名使用中违反上界(在别名类型某个类型实参的泛型类型实参中使用类型参数)

Issue:KT-54066 组件:核心语言 不兼容变更类型:源码级 简要说明:当类型别名的类型参数被用作别名类型某个类型实参的泛型类型实参时(例如 typealias Alias<T> = Base<List<T>>),Kotlin 将禁止使用违反别名类型相应类型参数上界限制的类型实参来使用该类型别名 弃用周期:- 1.8.0:当泛型类型别名的用法中存在违反别名类型相应类型参数上界约束的类型实参时报告警告 - >=1.10:把该警告提升为错误

禁止在委托中使用为扩展属性声明的类型参数

Issue:KT-24643 组件:核心语言 不兼容变更类型:源码级 简要说明:Kotlin 1.8 将禁止把泛型类型上的扩展属性以不安全的方式委托给使用接收者类型参数的泛型类型 弃用周期:- 1.6.0:当把扩展属性委托给以某种特定方式使用从被委托属性类型实参推断出的类型参数的类型时,报告警告(在渐进模式下报告错误)- 1.8.0:把该警告提升为错误,可以用 -XXLanguage:-ForbidUsingExtensionPropertyTypeParameterInDelegate 临时回退到 1.8 之前的行为

禁止在 suspend 函数上使用 @Synchronized 注解

Issue:KT-48516 组件:核心语言 不兼容变更类型:源码级 简要说明:Kotlin 1.8 将禁止在 suspend 函数上放置 @Synchronized 注解,因为不应允许在同步块内部发生挂起调用 弃用周期:- 1.6.0:对带有 @Synchronized 注解的 suspend 函数报告警告, 该警告在渐进模式下作为错误报告

  • 1.8.0:把该警告提升为错误, 可以用 -XXLanguage:-SynchronizedSuspendError 临时回退到 1.8 之前的行为

禁止用展开运算符向非 vararg 参数传参

Issue:KT-48162 组件:核心语言 不兼容变更类型:源码级 简要说明:Kotlin 曾允许在某些条件下使用展开运算符(*)把数组传给非 vararg 的数组参数。从 Kotlin 1.8 起,这将不再允许 弃用周期:- 1.6.0:在期望非 vararg 数组参数的位置使用展开运算符时报告警告(在渐进模式下报告错误)- 1.8.0:把该警告提升为错误,可以用 -XXLanguage:-ReportNonVarargSpreadOnGenericCalls 临时回退到 1.8 之前的行为

禁止在传给按 lambda 返回类型重载的函数的 lambda 中违反空安全

Issue:KT-49658 组件:核心语言 不兼容变更类型:源码级 简要说明:Kotlin 1.8 将禁止从传给按 lambda 返回类型重载的函数的 lambda 中返回 null,前提是这些重载不允许可空返回类型。此前,当 when 运算符的某个分支返回 null 时是允许的 弃用周期:- 1.6.20:报告类型不匹配警告(在渐进模式下报告错误)- 1.8.0:把该警告提升为错误,可以用 -XXLanguage:-DontLoseDiagnosticsDuringOverloadResolutionByReturnType 临时回退到 1.8 之前的行为

在公共签名中近似局部类型时保留可空性

Issue:KT-53982 组件:核心语言 不兼容变更类型:源码级、二进制级 简要说明:当局部类型或匿名类型从未显式指定返回类型的表达式体函数中返回时,Kotlin 编译器会使用该类型已知的父类型来推断(或近似)返回类型。在此过程中,编译器可能推断出不可为空的类型,而实际上可能返回 null 值 弃用周期:- 1.8.0:用灵活的父类型近似灵活类型 - 1.8.0:当某个声明被推断为不可为空、但本应可为空的类型时报告警告,提示用户显式指定类型 - 1.9.0:用可为空的父类型近似可为空的类型,可以用 -XXLanguage:-KeepNullabilityWhenApproximatingLocalType 临时回退到 1.9 之前的行为

不通过覆盖传播弃用

Issue:KT-47902 组件:核心语言 不兼容变更类型:源码级 简要说明:Kotlin 1.9 不再把父类中某个已弃用成员的弃用状态传播到子类中覆盖它的成员,从而提供了一种明确的机制:可以弃用父类的某个成员,同时在子类中保持它未被弃用 弃用周期:- 1.6.20:报告一条警告,说明未来的行为变更,并提示要么抑制该警告,要么在已弃用成员的覆盖上显式写上 @Deprecated 注解 - 1.9.0:停止把弃用状态传播给被覆盖的成员。该变更在渐进模式下也会立即生效

禁止在构建器推断上下文中把类型变量隐式推断为某个上界

Issue:KT-47986 组件:核心语言 不兼容变更类型:源码级 简要说明:在构建器推断 lambda 函数的作用域内,如果没有任何使用处的类型信息,Kotlin 1.9 将禁止把类型变量推断为相应类型参数的上界,就像它目前在其他上下文中已禁止的那样 弃用周期:- 1.7.20:当在使用处没有类型信息的情况下把类型参数推断为声明的上界时报告警告(在渐进模式下报告错误)- 1.9.0:把该警告提升为错误,可以用 -XXLanguage:-ForbidInferringPostponedTypeVariableIntoDeclaredUpperBound 临时回退到 1.9 之前的行为

禁止在注解类中除参数声明之外的任何地方使用集合字面量

Issue:KT-39041 组件:核心语言 不兼容变更类型:源码级 简要说明:Kotlin 允许以受限的方式使用集合字面量——把数组传给注解类的参数,或为这些参数指定默认值。但除此之外,Kotlin 曾允许在注解类内部的任何其他地方使用集合字面量,例如在其嵌套对象中。Kotlin 1.9 将禁止在注解类中除参数默认值之外的任何地方使用集合字面量。弃用周期:- 1.7.0:对注解类嵌套对象中的数组字面量报告警告(在渐进模式下报告错误)- 1.9.0:把该警告提升为错误

禁止在默认值表达式中前向引用带默认值的参数

Issue:KT-25694 组件:核心语言 不兼容变更类型:源码级 简要说明:Kotlin 1.9 将禁止在其他参数的默认值表达式中前向引用带默认值的参数。这确保当某个参数在默认值表达式中被访问时,它已经具有值:要么是传给函数的值,要么是由它自己的默认值表达式初始化得到的值 弃用周期:- 1.7.0:当带有默认值的参数在它之前的另一个参数的默认值中被引用时报告警告(在渐进模式下报告错误)- 1.9.0:把该警告提升为错误,可以用 -XXLanguage:-ProhibitIllegalValueParameterUsageInDefaultArguments 临时回退到 1.9 之前的行为

禁止对内联函数式参数进行扩展调用

Issue:KT-52502 组件:核心语言 不兼容变更类型:源码级 简要说明:虽然 Kotlin 曾允许把内联函数式参数作为接收者传给另一个内联函数,但编译这类代码时总是导致编译器异常。Kotlin 1.9 将禁止这一做法,从而报告错误而不是让编译器崩溃 弃用周期:- 1.7.20:对针对内联函数式参数的内联扩展调用报告警告(在渐进模式下报告错误)- 1.9.0:把该警告提升为错误

禁止以匿名函数实参调用名为 suspend 的中缀函数

Issue:KT-49264 组件:核心语言 不兼容变更类型:源码级 简要说明:Kotlin 1.9 不再允许调用名为 suspend、且其唯一参数为函数类型并以匿名函数字面量形式传入的中缀函数 弃用周期:- 1.7.20:对带匿名函数字面量的 suspend 中缀调用报告警告 - 1.9.0:把该警告提升为错误,可以用 -XXLanguage:-ModifierNonBuiltinSuspendFunError 临时回退到 1.9 之前的行为 - >=1.10:改变解析器对 suspend fun 记号序列的解释方式

禁止在内部类中违反型变规则使用捕获的类型参数

Issue:KT-50947 组件:核心语言 不兼容变更类型:源码级 简要说明:如果外部类的类型参数具有 in 或 out 型变,Kotlin 1.9 将禁止在该类的内部类中,以违反该类型参数所声明型变的位置使用它 弃用周期:- 1.7.0:当外部类类型参数的使用位置违反该参数的型变规则时报告警告(在渐进模式下报告错误)- 1.9.0:把该警告提升为错误,可以用 -XXLanguage:-ReportTypeVarianceConflictOnQualifierArguments 临时回退到 1.9 之前的行为

禁止在复合赋值运算符中递归调用没有显式返回类型的函数

Issue:KT-48546 组件:核心语言 不兼容变更类型:源码级 简要说明:Kotlin 1.9 将禁止在函数体内复合赋值运算符的实参中调用一个没有显式指定返回类型的函数,就像它目前在该函数体内其他表达式中已禁止的那样 弃用周期:- 1.7.0:当没有显式指定返回类型的函数在其函数体内复合赋值运算符的实参中被递归调用时报告警告(在渐进模式下报告错误)- 1.9.0:把该警告提升为错误

禁止在期望 @NotNull T 而给出的 Kotlin 泛型参数有可空边界时进行不健全的调用

Issue:KT-36770 组件:Kotlin/JVM 不兼容变更类型:源码级 简要说明:Kotlin 1.9 将禁止这样的方法调用:为 Java 方法中带有 @NotNull 注解的参数传入一个可能可为空的泛型类型的值 弃用周期:- 1.5.20:当把不受约束的泛型类型参数传给期望非空类型的位置时报告警告 - 1.9.0:用类型不匹配错误取代上述警告,可以用 -XXLanguage:-ProhibitUsingNullableTypeParameterAgainstNotNullAnnotated 临时回退到 1.8 之前的行为

禁止从枚举的条目初始化器中访问该枚举伴生对象的成员

Issue:KT-49110 组件:核心语言 不兼容变更类型:源码级 简要说明:Kotlin 1.9 将禁止从枚举条目初始化器中对枚举的伴生对象进行任何形式的访问 弃用周期:- 1.6.20:对此类伴生成员访问报告警告(在渐进模式下报告错误)- 1.9.0:把该警告提升为错误,可以用 -XXLanguage:-ProhibitAccessToEnumCompanionMembersInEnumConstructorCall 临时回退到 1.8 之前的行为

弃用并移除 Enum.declaringClass 合成属性

Issue:KT-49653 组件:Kotlin/JVM 不兼容变更类型:源码级 简要说明:Kotlin 曾允许在由底层 Java 类 java.lang.Enum 的 getDeclaringClass() 方法生成的 Enum 值上使用合成属性 declaringClass,尽管该方法对 Kotlin 的 Enum 类型并不可用。Kotlin 1.9 将禁止使用该属性,并建议迁移到扩展属性 declaringJavaClass 弃用周期:- 1.7.0:对 declaringClass 属性的使用报告警告(在渐进模式下报告错误),并建议迁移到 declaringJavaClass 扩展 - 1.9.0:把该警告提升为错误,可以用 -XXLanguage:-ProhibitEnumDeclaringClass 临时回退到 1.9 之前的行为 - >=1.10:移除 declaringClass 合成属性

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

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

标准库

当 Range/Progression 开始实现 Collection 时对潜在的重载解析变化发出警告

Issue:KT-49276 组件:核心语言 / kotlin-stdlib 不兼容变更类型:源码级 简要说明:计划在 Kotlin 1.9 中让标准 progression 及继承自它们的具名 range 实现 Collection 接口。如果某个方法有两个重载(一个接受元素,另一个接受集合),这可能导致重载解析选中不同的重载。Kotlin 会通过在以 range 或 progression 为实参调用此类重载方法时报告警告或错误来让这种情况显现出来 弃用周期:- 1.6.20:如果该 progression/range 实现 Collection 接口会导致此次调用将来选中另一个重载,则以标准 progression 或其 range 继承者作为实参调用重载方法时报告警告 - 1.8.0:把该警告提升为错误 - 1.9.0:停止报告该错误,在 progression 中实现 Collection 接口,从而在受影响的情况下改变重载解析结果

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

Issue: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.20:从 JS-IR 目标的标准库中移除已弃用的函数 - >= 1.9:把 kotlinx.* 包中的 API 移到一个单独的库

弃用部分仅 JS 的 API

Issue: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.9.0:把弃用级别提升为错误 - >=1.10.0:从公共 API 中移除这些已弃用的函数

工具

提高 KotlinCompile 任务 classpath 属性的弃用级别

Issue:KT-51679 组件:Gradle 不兼容变更类型:源码级 简要说明:KotlinCompile 任务的 classpath 属性已被弃用 弃用周期:- 1.7.0:classpath 属性被弃用 - 1.8.0:把弃用级别提升为错误 - >=1.9.0:从公共 API 中移除这些已弃用的函数

移除 kapt.use.worker.api Gradle 属性

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

移除 kotlin.compiler.execution.strategy 系统属性

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

编译器选项中的变化

Issues:KT-27301、KT-48532 组件:Gradle 不兼容变更类型:源码级、二进制级 简要说明:该变更可能影响 Gradle 插件的作者。在 kotlin-gradle-plugin 中,某些内部类型增加了额外的泛型参数(你应补上泛型类型或 *)。KotlinNativeLink 任务不再继承 AbstractKotlinNativeCompile 任务。KotlinJsCompilerOptions.outputFile 及相关的 KotlinJsOptions.outputFile 选项已被弃用。请改用 Kotlin2JsCompile.outputFileProperty 任务输入。kotlinOptions 任务输入和 kotlinOptions{...} 任务 DSL 处于支持模式,将在未来的版本中被弃用。compilerOptions 和 kotlinOptions 不能在任务执行阶段被修改(参见 Kotlin 1.8 的新变化中的一个例外)。freeCompilerArgs 返回不可变的 List<String>——kotlinOptions.freeCompilerArgs.remove("something") 会失败。用于启用旧 JVM 后端的 useOldBackend 属性已被移除 弃用周期:- 1.8.0:KotlinNativeLink 任务不再继承 AbstractKotlinNativeCompile。KotlinJsCompilerOptions.outputFile 及相关的 KotlinJsOptions.outputFile 选项已被弃用。用于启用旧 JVM 后端的 useOldBackend 属性已被移除。

弃用 kotlin.internal.single.build.metrics.file 属性

Issue:KT-53357 组件:Gradle 不兼容变更类型:源码级 简要说明:弃用用于为构建报告指定单个文件的 kotlin.internal.single.build.metrics.file 属性。请改用 kotlin.build.report.single_file 属性并配合 kotlin.build.report.output=single_file 弃用周期:- 1.8.0:把弃用级别提升为警告 >= 1.9:删除该属性