13.6.3.3 Kotlin 2.1.x 兼容性指南

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

13.6.3.3 Kotlin 2.1.x 兼容性指南

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

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

基本术语

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

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

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

语言

移除语言版本 1.4 和 1.5

Issue:KT-60521 组件:核心语言 不兼容变更类型:源码级 简要说明:Kotlin 2.1 引入了语言版本 2.1,并移除了对语言版本 1.4 和 1.5 的支持。语言版本 1.6 和 1.7 已被弃用。弃用周期:- 1.6.0:对语言版本 1.4 报告警告 - 1.9.0:对语言版本 1.5 报告警告 - 2.1.0:对语言版本 1.6 和 1.7 报告警告;把语言版本 1.4 和 1.5 的警告提升为错误

修改 Kotlin/Native 上 typeOf() 函数的行为

Issue:KT-70754 组件:核心语言 不兼容变更类型:行为级 简要说明:Kotlin/Native 上 typeOf() 函数的行为已与 Kotlin/JVM 对齐,以确保跨平台一致性。弃用周期:- 2.1.0:对齐 Kotlin/Native 上 typeOf() 函数的行为

禁止通过类型参数的边界暴露类型

Issue:KT-69653 组件:核心语言 不兼容变更类型:源码级 简要说明:现在禁止通过类型参数边界暴露可见性更低的类型,从而解决了类型可见性规则中的不一致问题。这一变更确保类型参数的边界遵循与类相同的可见性规则,防止在 JVM 中出现 IR 校验错误之类的问题。弃用周期:- 2.1.0:对通过类型参数边界暴露可见性更低类型的情况报告警告 - 2.2.0:把该警告提升为错误

禁止继承同名的抽象 var 属性和 val 属性

Issue:KT-58659 组件:核心语言 不兼容变更类型:源码级 简要说明:如果某个类从接口继承了抽象的 var 属性,同时从父类继承了同名的 val 属性,现在会触发编译错误。这解决了此类情况下因缺少 setter 而导致的运行时崩溃。弃用周期:- 2.1.0:当类从接口继承抽象 var 属性并从父类继承同名 val 属性时报告警告(在渐进模式下报告错误)- 2.2.0:把该警告提升为错误

访问未初始化的枚举条目时报告错误

Issue:KT-68451 组件:核心语言 不兼容变更类型:源码级 简要说明:当在枚举类或枚举条目初始化期间访问未初始化的枚举条目时,编译器现在会报告错误。这使行为与成员属性初始化规则保持一致,防止运行时异常并确保逻辑一致。弃用周期:- 2.1.0:访问未初始化的枚举条目时报告错误

K2 智能转换传播的变化

Issue:KTLC-34 组件:核心语言 不兼容变更类型:行为级 简要说明:K2 编译器改变了智能转换传播的行为,为推断出的变量(如 val x = y)引入了类型信息的双向传播。显式指定类型的变量(如 val x: T = y)不再传播类型信息,从而更严格地遵循声明的类型。弃用周期:- 2.1.0:启用新行为

修正 Java 子类中成员扩展属性覆盖的处理

Issue:KTLC-35 组件:核心语言 不兼容变更类型:行为级 简要说明:被 Java 子类覆盖的成员扩展属性的 getter 现在被隐藏在子类的作用域中,使其行为与普通 Kotlin 属性一致。弃用周期:- 2.1.0:启用新行为

修正覆盖 protected val 的 var 属性 getter 和 setter 的可见性对齐

Issue:KTLC-36 组件:核心语言 不兼容变更类型:二进制级 简要说明:覆盖 protected val 属性的 var 属性,其 getter 和 setter 的可见性现在保持一致,两者都继承被覆盖 val 属性的可见性。弃用周期:- 2.1.0:在 K2 中为 getter 和 setter 强制一致的可见性;K1 不受影响

把 JSpecify 可空性不匹配诊断的严重性提升为错误

Issue:KTLC-11 组件:核心语言 不兼容变更类型:源码级 简要说明:来自 org.jspecify.annotations 的可空性不匹配(例如 @NonNull、@Nullable 和 @NullMarked)现在被视为错误而不是警告,从而对 Java 互操作实施更严格的类型安全。要调整这些诊断的严重性,请使用 -Xnullability-annotations 编译器选项。弃用周期:- 1.6.0:对潜在的可空性不匹配报告警告 - 1.8.20:把警告扩展到特定的 JSpecify 注解,包括:@Nullable、@NullnessUnspecified、@NullMarked 以及 org.jspecify.nullness 中的旧注解(JSpecify 0.2 及更早版本)- 2.0.0:添加对 @NonNull 注解的支持 - 2.1.0:把 JSpecify 注解的默认模式改为 strict,将警告转换为错误;使用 -Xnullability-annotations=@org.jspecify.annotations:warning 或 -Xnullability-annotations=@org.jspecify.annotations:ignore 覆盖默认行为

调整重载解析,在歧义情况下优先选择扩展函数而不是 invoke 调用

Issue:KTLC-37 组件:核心语言 不兼容变更类型:行为级 简要说明:在歧义情况下,重载解析现在一致地优先选择扩展函数而不是 invoke 调用。这解决了局部函数和属性解析逻辑中的不一致问题。该变更仅在重新编译后生效,不影响预编译的二进制文件。弃用周期:- 2.1.0:对于签名匹配的扩展函数,调整重载解析以一致地优先选择扩展函数而不是 invoke 调用;该变更仅在重新编译后生效,不影响预编译的二进制文件

禁止在 JDK 函数接口的 SAM 构造器 lambda 中返回可空值

Issue:KTLC-42 组件:核心语言 不兼容变更类型:源码级 简要说明:如果指定的类型实参不可为空,那么从 JDK 函数接口的 SAM 构造器中的 lambda 返回可空值现在会触发编译错误。这解决了可空性不匹配可能导致运行时异常的问题,确保更严格的类型安全。弃用周期:- 2.0.0:对 JDK 函数接口 SAM 构造器中的可空返回值报告弃用警告 - 2.1.0:默认启用新行为

修正 Kotlin/Native 中私有成员与公共成员冲突的处理

Issue:KTLC-43 组件:核心语言 不兼容变更类型:行为级 简要说明:在 Kotlin/Native 中,私有成员不再覆盖或与父类中的公共成员冲突,行为与 Kotlin/JVM 保持一致。这解决了覆盖解析中的不一致问题,并消除了由分离编译导致的意外行为。弃用周期:- 2.1.0:Kotlin/Native 中的私有函数和属性不再覆盖或影响父类中的公共成员,与 JVM 行为保持一致

禁止在公共内联函数中访问私有运算符函数

Issue:KTLC-71 组件:核心语言 不兼容变更类型:源码级 简要说明:诸如 getValue()、setValue()、provideDelegate()、hasNext() 和 next() 等私有运算符函数不再能在公共内联函数中访问。弃用周期:- 2.0.0:对在公共内联函数中访问私有运算符函数报告弃用警告 - 2.1.0:把该警告提升为错误

禁止向带有 @UnsafeVariance 注解的不可变参数传递无效实参

Issue:KTLC-72 组件:核心语言 不兼容变更类型:源码级 简要说明:编译器在类型检查期间现在会忽略 @UnsafeVariance 注解,对不可变类型参数实施更严格的类型安全。这防止了那些依赖 @UnsafeVariance 绕过预期类型检查的无效调用。弃用周期:- 2.1.0:启用新行为

对警告级 Java 类型的错误级可空实参报告可空性错误

Issue:KTLC-100 组件:核心语言 不兼容变更类型:源码级 简要说明:编译器现在会检测 Java 方法中的可空性不匹配,即警告级可空类型包含具有更严格的错误级可空性的类型实参。这确保此前被忽略的类型实参错误能够被正确报告。弃用周期:- 2.0.0:对带有更严格类型实参的 Java 方法中的可空性不匹配报告弃用警告 - 2.1.0:把该警告提升为错误

报告对不可访问类型的隐式使用

Issue:KTLC-3 组件:核心语言 不兼容变更类型:源码级 简要说明:编译器现在会报告函数字面量和类型实参中对不可访问类型的使用,防止因类型信息不完整而导致的编译和运行时失败。弃用周期:- 2.0.0:对参数或接收者为不可访问的非泛型类型的函数字面量、以及带有不可访问类型实参的类型报告警告;在特定场景下,对参数或接收者为不可访问的泛型类型的函数字面量、以及带有不可访问泛型类型实参的类型报告错误 - 2.1.0:把参数和接收者为不可访问非泛型类型的函数字面量的警告提升为错误 - 2.2.0:把带有不可访问类型实参的类型的警告提升为错误

标准库

弃用 Char 和 String 中区分区域设置的大小写转换函数

Issue:KT-43023 组件:kotlin-stdlib 不兼容变更类型:源码级 简要说明:在 Kotlin 标准库的其他 API 中,针对 Char 和 String 的区分区域设置的大小写转换函数(例如 Char.toUpperCase() 和 String.toLowerCase())已被弃用。请改用与区域设置无关的替代方案,例如 String.lowercase(),或者为区分区域设置的行为显式指定区域设置,例如 String.lowercase(Locale.getDefault())。关于 Kotlin 2.1.0 中已弃用的 Kotlin 标准库 API 的完整列表,请参阅 KT-71628。弃用周期:- 1.4.30:引入与区域设置无关的替代方案作为实验性 API - 1.5.0:以警告形式弃用区分区域设置的大小写转换函数 - 2.1.0:把该警告提升为错误

移除 kotlin-stdlib-common JAR 产物

Issue:KT-62159 组件:kotlin-stdlib 不兼容变更类型:二进制级 简要说明:kotlin-stdlib-common.jar 产物此前用于旧式的多平台声明元数据,现已被弃用,并由 .klib 文件替代,作为公共多平台声明元数据的标准格式。该变更不影响主要的 kotlin-stdlib.jar 或 kotlin-stdlib-all.jar 产物。弃用周期:- 2.1.0:弃用并移除 kotlin-stdlib-common.jar 产物

弃用 appendln(),改用 appendLine()

Issue:KTLC-27 组件:kotlin-stdlib 不兼容变更类型:源码级 简要说明:StringBuilder.appendln() 已被弃用,改用 StringBuilder.appendLine()。弃用周期:- 1.4.0:appendln() 函数被弃用;使用时报告警告 - 2.1.0:把该警告提升为错误

Issue:KT-69545 组件:kotlin-stdlib 不兼容变更类型:源码级 简要说明:Kotlin/Native 中与冻结相关的 API 此前带有 @FreezingIsDeprecated 注解,现已被弃用。这与新内存管理器的引入相一致,后者不再需要为了跨线程共享而冻结对象。迁移细节请参阅 Kotlin/Native 迁移指南。弃用周期:- 1.7.20:以警告形式弃用与冻结相关的 API - 2.1.0:把该警告提升为错误

把 Map.Entry 的行为改为在结构修改时快速失败

Issue:KTLC-23 组件:kotlin-stdlib 不兼容变更类型:行为级 简要说明:在关联的映射发生结构修改之后访问 Map.Entry 键值对,现在会抛出 ConcurrentModificationException。弃用周期:- 2.1.0:检测到映射结构修改时抛出异常

工具

弃用 KotlinCompilationOutput#resourcesDirProvider

Issue:KT-69255 组件:Gradle 不兼容变更类型:源码级 简要说明:KotlinCompilationOutput#resourcesDirProvider 字段已被弃用。请改为在 Gradle 构建脚本中使用 KotlinSourceSet.resources 来添加额外的资源目录。弃用周期:- 2.1.0:KotlinCompilationOutput#resourcesDirProvider 被弃用

弃用 registerKotlinJvmCompileTask(taskName, moduleName) 函数

Issue:KT-69927 组件:Gradle 不兼容变更类型:源码级 简要说明:registerKotlinJvmCompileTask(taskName, moduleName) 函数已被弃用,改用新的 registerKotlinJvmCompileTask(taskName, compilerOptions, explicitApiMode) 函数,后者现在接受 KotlinJvmCompilerOptions。这允许你传入 compilerOptions 实例(通常来自扩展或目标),其中的值会作为该任务选项的约定值。弃用周期:- 2.1.0:registerKotlinJvmCompileTask(taskName, moduleName) 函数被弃用

弃用 registerKaptGenerateStubsTask(taskName) 函数

Issue:KT-70383 组件:Gradle 不兼容变更类型:源码级 简要说明:registerKaptGenerateStubsTask(taskName) 函数已被弃用。请改用新的 registerKaptGenerateStubsTask(compileTask, kaptExtension, explicitApiMode) 函数。这个新版本允许你从相关的 KotlinJvmCompile 任务把值链接为约定值,确保两个任务使用相同的选项集。弃用周期:- 2.1.0:registerKaptGenerateStubsTask(taskName) 函数被弃用

弃用 KotlinTopLevelExtension 和 KotlinTopLevelExtensionConfig 接口

Issue:KT-71602 组件:Gradle 不兼容变更类型:行为级 简要说明:KotlinTopLevelExtension 和 KotlinTopLevelExtensionConfig 接口已被弃用,改用新的 KotlinTopLevelExtension 接口。该接口合并了 KotlinTopLevelExtensionConfig、KotlinTopLevelExtension 和 KotlinProjectExtension,以精简 API 层级,并提供对 JVM 工具链和编译器属性的官方访问方式。弃用周期:- 2.1.0:KotlinTopLevelExtension 和 KotlinTopLevelExtensionConfig 接口被弃用

从构建运行时依赖中移除 kotlin-compiler-embeddable

Issue:KT-61706 组件:Gradle 不兼容变更类型:源码级 简要说明:kotlin-compiler-embeddable 依赖已从 Kotlin Gradle 插件(KGP)的运行时中移除。所需的模块现在直接包含在 KGP 产物中,并且 Kotlin 语言版本被限制为 2.0,以支持与低于 8.2 的 Gradle Kotlin 运行时保持兼容。弃用周期:- 2.1.0:使用 kotlin-compiler-embeddable 时报告警告 - 2.2.0:把该警告提升为错误

从 Kotlin Gradle 插件 API 中隐藏编译器符号

Issue:KT-70251 组件:Gradle 不兼容变更类型:源码级 简要说明:Kotlin Gradle 插件(KGP)中捆绑的编译器模块符号(例如 KotlinCompilerVersion)已从公共 API 中隐藏,以防止在构建脚本中被意外访问。弃用周期:- 2.1.0:访问这些符号时报告警告 - 2.2.0:把该警告提升为错误

添加对多个稳定性配置文件的支持

Issue:KT-68345 组件:Gradle 不兼容变更类型:源码级 简要说明:Compose 扩展中的 stabilityConfigurationFile 属性已被弃用,改用新的 stabilityConfigurationFiles 属性,后者允许指定多个配置文件。弃用周期:- 2.1.0:stabilityConfigurationFile 属性被弃用

移除已弃用的平台插件 ID

Issue:KT-65565 组件:Gradle 不兼容变更类型:源码级 简要说明:已移除对这些平台插件 ID 的支持:* kotlin-platform-common * org.jetbrains.kotlin.platform.common 弃用周期:- 1.3:这些平台插件 ID 被弃用 - 2.1.0:这些平台插件 ID 不再受支持