Swift 5.2 已发布!

Swift 5.2 现在正式发布了!🎉

此版本专注于改善开发者体验

… 以及更多。此外,还添加了一些语言特性,为构建富有表现力的 API 提供了新的能力。这篇博文快速浏览了主要的更改。

语言更新

Swift 5.2 实现了来自 Swift 演进流程的以下语言提案

要体验这些更改,请浏览由 Paul Hudson 整理的 playgroundJohn Sundell 也撰写了一篇文章 “探索 Swift 5.2 的新函数式特性”,阐述了这些新功能的表现力。

改进的编译器诊断

我们大幅提高了 Swift 编译器中错误消息的质量和精确度。

以前,编译器尝试通过分解表达式来搜索每个子表达式中的失败,从而猜测错误的准确位置。当有可能将错误位置缩小到单个子表达式,而无需使用有关其父表达式的任何信息时,此方法效果良好。但是,有许多编程错误是这种策略无法准确识别的。

编译器在表达式中推断类型时遇到失败时会留下“面包屑”,记录沿途的每个特定失败。这些面包屑使编译器能够生成精确的诊断信息,通常带有可操作的修复,从而引导开发者编写正确的代码。以下是一些改进的错误消息的示例。

以下代码尝试将枚举值与不存在的 case 进行比较

enum E { case one, two }

func check(e: E) {
  if e != .three {
    print("okay")
  }
}

使用 Swift 5.1,您可能会对错误消息感到困惑

error: binary operator '!=' cannot be applied to operands of type 'E' and '_'
  if e != .three {
     ~ ^  ~~~~~~

使用 Swift 5.2,您将立即看到问题所在

error: type 'E' has no member 'three'
  if e != .three {
          ~^~~~~

下一个代码片段错误地调用了 SwiftUI 中 TextField 的初始化器

import SwiftUI

struct RoomDetails: View {
  @State var roomName: String
  @State var imageName: String

  var body: some View {
    VStack {
      TextField("Room Name")

      Image(imageName)
        .frame(maxWidth: 300)
    }
  }
}

在 Swift 5.1 中,误导性的错误消息出现在完全不同的行上

error: 'Int' is not convertible to 'CGFloat?'
        .frame(maxWidth: 300)
                         ^~~

Swift 5.2 编译器现在正确地指出 TextField 初始化器缺少参数

error: missing argument for parameter 'text' in call
      TextField("Room Name")
                           ^

此错误还包括一个 Fix-It,用于插入缺少的参数。

您可以在 先前发布的关于新诊断架构的博文 中找到更多信息。

代码补全改进

改进的构建算法

Swift 编译器支持两种操作模式

在 Xcode 中,可以在 Swift 项目的构建设置中看到这些

Swift compilation modes

这两种模式在编译速度和执行的代码优化量方面有所权衡。增量式构建在开发期间非常有用,因为并非项目中的每个文件都需要重新编译,并且最大优化不是关键。全模块优化使编译器能够更完整地查看整个代码库,因此具有更强大的优化能力。

在增量式模式构建中,重建模块的工作在多个并行运行的编译任务之间进行拆分。对于每个重新构建的源文件,都有一个相关的编译任务负责类型检查和为该源文件中的声明生成代码。

由于 Swift 声明(例如函数、属性、类型等)可以在源文件之间相互引用,因此有时编译任务需要检查其他源文件中的声明的类型。这种跨文件引用声明可能会降低增量式模式构建的效率,因为它可能会在编译任务之间重复类型检查工作。

相比之下,全模块编译通过在一个编译任务中处理模块中的所有代码来工作。虽然编译任务之间没有重复的类型检查工作,但是在编译模块中的代码时没有并行性。但是,全模块编译使编译器可以一次性更全面地了解模块中的代码,从而实现更多的代码优化。

增量式编译相对于全模块编译的构建时间优势随着每个编译任务执行的重复工作量而减小。如果此重复工作量过高,则可能出现增量式模式执行的工作量大于全模块编译的情况。只要开销不超过处理器核心的数量,增量式模式构建总体上仍然会更快,但是减少此开销是提高构建时间的关键

使增量式构建更高效

为了最大限度地减少增量式模式构建造成的浪费工作,Swift 5.2 编译器(特别是类型检查器)利用了一种新的集中式逻辑,用于在请求之间进行缓存、延迟求值和依赖项跟踪,其中请求是自包含的计算单元。编译器现在使用此逻辑来更有效地解析声明及其相互引用。

在 Swift 5.2 之前,当在另一个源文件中引用声明时,类型检查器将显式地对该声明执行称为验证的操作。验证使用了可变状态,并且粒度相当粗糙,试图预先计算声明的任何数量的属性,这些属性可能在稍后的代码生成期间需要。这种急切地预先计算信息通常是不必要的和浪费的。

在 Swift 5.2 中,编译器中声明的内部表示是不可变的,编译器的代码生成阶段能够触发请求的延迟求值,其结果会被缓存。由于请求比旧的验证步骤更精细,因此可以通过避免浪费的工作来提高性能。它还提高了正确性,修复了大量正确性问题,在这些问题中,类型检查器没有预料到需要验证稍后代码生成所需的内容。

其他改进

除了改进的增量式模式构建之外,Swift 5.2 编译器还包括许多对基础组件的性能优化,例如编译器为将命名符号解析为其声明(即,名称查找)所做的工作。我们预计这些改进将改善全模块和增量式模式构建的构建时间。由于这些更改降低了名称查找内部各种算法的算法(大 O)复杂度,因此它们应特别有助于具有许多源文件的大型项目。

调试器改进

在所有支持 Swift 调试的平台上,LLDB 现在在从调试信息中重建 Swift 程序的类型信息方面更具弹性。这种弹性使调试器能够使用更多关于 Swift 类型的信息。

特别是,LLDB 现在还可以从 DWARF 调试信息中导入 C 和 Objective-C 类型,而不是从源代码编译 Clang 模块。此行为可以通过 symbols.use-swift-dwarfimporter LLDB 设置来控制。默认情况下,当传统的 Clang 模块导入失败时,此设置将作为回退路径启用。

示例:Xcode 变量视图和表达式求值器

要查看这些改进的实际效果,可以查看 Xcode 中的变量视图或 LLDB 表达式求值器。为了支持这些调试工作流程,LLDB 需要导入在当前调试上下文(例如,文件、函数等)中可见的所有 Swift 模块。虽然 Swift 模块具有丰富的类型信息,但 Swift 模块通常不能单独使用,而必须依赖于 Clang(C/C++/Objective-C 编译器)生成的单独模块文件,这些文件用于 Swift 代码与 C 和 Objective-C 的互操作。由于 LLDB 具有整个程序及其所有动态库及其所有依赖项的全局视图,因此导入 Clang 模块有时可能会失败。一种常见的失败情况是来自不同动态库的搜索路径发生冲突时。

Swift Package Manager

Swift 5.2 中的 Swift Package Manager 包含以下新增强功能

这些更改是 Swift 演进流程中讨论和审查的结果

SwiftSyntax 更新

SwiftSyntax 的 API 中的语法节点层次结构已通过将协议替换为结构体进行了优化。因此,树遍历,尤其是在使用 SyntaxRewriter 重写时,现在更快了。这提高了树遍历期间的性能,尤其是在使用 SyntaxRewriter 重写树时。

有关 Swift 5.2 版本中更改的更多详细信息,请参阅更新日志

语言服务器协议更新

Xcode 11.4 和相应的 Command Line Tools 包包含了 Swift 5.2 版本的 SourceKit-LSP 语言服务器,用于 Swift 和基于 C 的语言。

要在 macOS 上查找 sourcekit-lsp 服务器可执行文件,同时 Xcode 11.4 是活动的 Xcode

# Run the server.
xcrun sourcekit-lsp
# Get the full path to the server.
xcrun --find sourcekit-lsp

SourceKit-LSP 现在包含对以下 LSP 功能的支持

SourceKit-LSP 在支持 C/C++/Objective-C 代码方面也有许多改进。 特别是,在确定用于处理头文件的编译器参数时,SourceKit-LSP 现在使用索引来查找其主文件,以提高结果的准确性。

对于使用 JSON 编译数据库的项目(例如 CMake 项目),也有一些值得注意的改进

文档

上现在提供了 Swift 5.2 的更新版本 The Swift Programming Language。 它也可以在 Apple Books 商店 中免费获得。

平台

Linux

Ubuntu 18.04 和 Ubuntu 16.04 的官方二进制文件可供下载

Apple (Xcode)

为了在 Apple 平台上进行开发,Swift 5.2 作为 Xcode 11.4 的一部分发布。

也可以从 下载工具链

来源

Swift 5.2 的开发在 GitHub 上以下存储库的 swift-5.2-branch 分支中进行跟踪

标签 swift-5.2-RELEASE 指定了这些存储库中构成 Swift 5.2 最终版本的特定修订版本。

swift-5.2-branch 将保持开放,但在相同的发布管理流程下,以累积下一次发布更改。