正式宣布类型团队

2023 年 1 月 20 日 · Jack Huey 代表 类型团队

哦,嗨,这是另一个新团队的公告。但我承认:如果你关注 RFC 仓库Rust zulip,或者特别关注 GATs 稳定公告帖子,那么这可能对你来说不是什么惊喜。事实上,这个“新”团队在去年 5 月底就已经正式成立了。

我们现在分享这篇文章有几个原因(而不是几个月前或...永远不分享)。首先,该团队在 12 月初完成了一次为期三天的面对面/混合会议,我们想分享这次会议的目的和成果。其次,现在发布此公告恰好是该团队成立约 7 个月,我们很乐意分享我们在这段时间内所取得的成就。最后,随着我们进入 2023 年新年,这是一个分享我们预计今年及以后发展方向的好时机。

背景 - 我们是如何走到这里的?

在过去的几年里,Rust 在许多指标上都取得了显著增长:用户、贡献者、功能、工具、文档等等。随着它的增长,人们希望用它来做的事情清单也增长得同样快。除了强大且符合人体工程学的功能外,对功能强大的工具(如 IDE 或语言学习工具)的需求也越来越明显。新的编译器(前端和后端)正在编写中。最重要的是,我们希望 Rust 继续保持其核心设计原则之一:安全性。

所有这些点都突出了关键需求:能够知道 Rust 语言应该如何工作,能够以相对轻松的方式扩展语言和编译器的新功能,能够连接到编译器并能够查询有关程序的重要信息,最后能够以易于管理且健壮的方式维护语言和编译器。多年来,人们为满足这些需求付出了相当大的努力,但我们还没有完全实现这些关键要求。

为了进一步说明并用数字来表示,目前大约有 220 个未完成的跟踪问题,涉及 语言编译器类型 功能,这些功能已被接受但尚未完全实现,其中大约一半至少有 3 年的历史,许多甚至比这更老。许多跟踪问题之所以开放这么久,不仅仅是因为带宽问题,还因为开发这些功能很困难,很大程度上是因为将相关语义置于更大的语言上下文中很困难;任何人都很难查看它们并知道需要做些什么才能完成它们。很明显,我们仍然需要更好的基础来更改语言和编译器。

另一个可能会让你震惊的数字:目前有 62 个未解决的 不健全问题。这听起来比实际情况可怕得多:几乎所有这些都是由专门进行探测和尝试以发现问题的人发现的编译器和语言的边缘;在实践中,这些不会在您编写的程序中弹出。尽管如此,这些都是我们想要解决的边缘问题。

类型团队

接下来,让我们谈谈 Rust 的一个较小的子集,而不是整个语言和编译器。具体来说,这里相关的部分包括类型检查器(大致定义变量如何被分配类型的语义和实现)、trait 求解(确定为哪些类型定义了哪些 trait)以及借用检查(证明 Rust 的所有权模型始终成立)。所有这些都可以被统一地视为“类型系统”。

根据 RFC 3254,上述 Rust 语言和编译器的子集属于类型团队的管辖范围。那么,这究竟意味着什么?

首先,自 2018 年左右以来,就存在一个“trait 工作组”,其主要目标是创建 Rust trait 系统的性能良好且可扩展的定义和实现(包括 Chalk trait 求解库)。随着时间的推移,尤其是在 2021 年下半年到 2022 年,工作组的影响力和责任自然地扩展到类型检查器和借用检查器——它们实际上是紧密联系的,并且通常很难将 trait 求解器与其他两个分开。因此,在某种程度上,类型团队本质上取代了以前的 trait 工作组。

另一个相关的工作组是 polonius 工作组,该工作组主要负责 Polonius 借用检查库的设计和实现。虽然工作组本身将保留,但它现在也属于类型团队的管辖范围。

现在,尽管 trait 工作组基本上被并入了类型团队,但创建一个团队有一些好处。首先,像 风格团队(以及许多其他团队)一样,类型团队不是顶级团队。它实际上目前独一无二,拥有两个父团队:lang 和 compiler 团队。两个团队都决定委托涵盖类型系统的决策权。

语言团队委托了类型系统设计的部分。然而,重要的是,这种设计更多地涵盖了类型系统如何“工作”,而不是其功能的“感觉”,期望类型团队在需要时就新的语言扩展提出建议并提出担忧。(这种划分没有明确定义,但通常的期望是偏向于更加谨慎)。另一方面,编译器团队委托了定义和维护 trait 系统实现的责任。

语言和编译器团队传统上共享的一个特殊责任是评估和修复与类型系统相关的语言中的不健全错误。这些错误通常源于实现定义的语言语义,并且过去需要 lang 和 compiler 团队的同步和输入。在大多数情况下,类型团队现在有权评估和实施修复,而无需任何父团队的直接输入。重要的是,这适用于技术上向后不兼容的修复。虽然修复安全漏洞不在 Rust 的向后兼容性保证范围内,但这些决策并非轻率做出,通常需要团队签字并使用 crater 评估对潜在生态系统的破坏。然而,现在可以在一个团队下完成,而无需协调两个单独的团队,这使得关闭这些不健全漏洞更容易(稍后我将对此进行更多讨论。)

形式化 Rust 类型系统

如上所述,不断发展的 Rust 语言的一个几乎必不可少的要素是知道它应该如何工作(并且有充分的文档记录)。最近有一些努力在推动 Rust 规范(如 Ferrocene这个开放的 RFC),但无论它是否有可能集成到更通用的规范中,拥有类型系统的形式化定义都将是非常有益的。事实上,形式化的存在将允许更好地评估潜在的新功能或不健全漏洞,而无需考虑编译器的其他微妙之处。

早在 2015 年,即 Rust 1.0 发布后不久,就开始编写一个名为 Chalk 的实验性 Rust trait 求解器。Chalk 的核心思想是将 Rust trait 系统的表面语法和思想(例如 trait、impl、where 子句)转换为一组可以使用类似 Prolog 的求解器求解的逻辑规则。然后,一旦这组逻辑和求解与编译器本身的 trait 求解器达到对等,计划是简单地替换现有的求解器。与此同时(并继续前进),其他工具可以使用这个新的求解器,例如 rust-analyzer,它今天就在使用。

现在,考虑到 Chalk 的年龄以及人们希望它能够实现的目标,您可能会想问一个问题“Chalk,何时?”——很多人都问过。然而,多年来我们了解到,由于一些原因,Chalk 可能不是 Rust 的正确长期解决方案。首先,正如本文多次提到的那样,trait 求解器只是一个更大的类型系统的一部分;并且对整个类型系统如何组合进行建模比尝试单独建模各个部分更能完整地了解其细节。其次,编译器的需求与形式化的需求截然不同:编译器需要性能良好的代码,并能够跟踪强大的诊断所需的信息;一个好的形式化不仅是完整的,而且易于维护、阅读和理解。多年来,Chalk 一直试图同时拥有两者,但到目前为止,两者都没有。

那么,未来的计划是什么?首先,类型团队已经开始形式化 Rust 类型系统,目前称为 a-mir-formality。最初的实验阶段是使用 PLT redex 编写的,但 Rust 端口正在进行中。还有很多工作要做(包括对更多的 trait 系统进行建模、编写 RFC 并将其移入 rust-lang org),但它已经显示出巨大的希望。

其次,我们已经启动了一个 倡议,用于在树内编写一个新的 trait 求解器。这个新的 trait 求解器的范围比 a-mir-formality 更有限(即,不打算涵盖整个类型系统)。在许多方面,它预计与 Chalk 非常相似,但会利用现有编译器和 trait 求解器的部分内容,以尽可能无痛地进行转换。我们确实希望它在某个时候从树中提取出来,因此它被编写得尽可能模块化。在本月早些时候的类型团队会议期间,我们能够讨论我们希望求解器的结构是什么样的,并且我们已经将其 合并到源代码树中

最后,Chalk 将不再是团队的关注重点。短期内,它仍然可能是一个有用的实验工具。如前所述,rust-analyzer 使用 Chalk 作为其特征求解器。它也可以在 rustc 中通过不稳定的特性标志使用。因此,目前可以在 Chalk 中实现新的想法,并在实践中进行实战测试。然而,随着 a-mir-formality 和新的内部特征求解器变得更加可用,以及它们的接口变得更加容易访问,这种优势可能不会持续太久。所有这些并不是说 Chalk 已经失败了。事实上,Chalk 教会了我们很多关于如何以逻辑方式思考 Rust 特征求解器,并且当前的 Rust 特征求解器随着时间的推移不断发展,更接近 Chalk 的模型,即使是不完全的。我们预计在一段时间内仍然会以某种方式支持 Chalk,用于 rust-analyzer,并且可能供那些有兴趣进行实验的人使用。

修复健全性漏洞

正如之前所提出的,创建一个新的类型团队,并由 lang 和 compiler 团队授予委托权限的一个巨大好处是,它可以主要独立地评估和修复不健全问题。然而,第二个好处实际上是更好的程序和知识共享,这使得团队成员可以在关于存在哪些健全性问题、它们存在的原因以及修复它们需要什么方面达成共识。例如,在我们本月早些时候的会议期间,我们能够浏览完整的健全性问题列表(重点关注与类型系统相关的问题),确定它们的原因,并讨论预期的修复方案(尽管大多数需要上一节中讨论的先决条件工作)。

此外,该团队已经修复了一些健全性问题,并且还有一些正在进行中。我不会详细说明,而是选择以列表形式列出它们

如你所见,我们正在修复健全性漏洞方面取得进展。正如 crater 所评估的那样,这些有时会破坏代码。然而,即使被破坏的代码在技术上是不健全的,我们也会尽力缓解这种情况。

新特性

虽然 *提出和设计* 新特性在技术上不属于类型团队的职责范围(这些更多地属于 lang 团队本身),但在某些情况下,该团队会深度参与(如果不是主导)特性设计。

这些可以是接近错误修复的小型添加。例如,这个 PR 允许比以前编译的更多的生命周期外生存边界排列。或者,这些 PR 可以是更大、更有影响的变化,它们不属于“特性”,而是与类型系统紧密相关。例如,这个 PR 使 Sized 特性成为协同归纳的,这实际上使得更多的循环边界能够编译(有关示例,请参见 这个测试)。

还有一些更大的特性和特性集是由类型团队推动的,这主要是由于与类型系统的深度交叉。以下是一些示例

  • 泛型关联类型 (GAT) - 该特性早在类型团队成立之前就已存在,并且是此列表中唯一一个到目前为止已稳定的特性。但由于与类型系统的大量交互,该团队能够解决其最终稳定路径上出现的问题。有关更多详细信息,请参阅这篇博客文章
  • 类型别名 impl 特性 (TAIT) - 要 *正确* 实现此特性,需要深入了解类型检查器。这已接近稳定。有关更多信息,请参阅跟踪问题
  • 特性向上转型 - 这个相对较小,但有一些类型系统交互。同样,有关该特性的解释,请参阅跟踪问题
  • 负 impl - 这个特性也早在类型团队成立之前就已存在,但最近由该团队进行开发。仍然存在未解决的错误和健全性问题,因此距离稳定还有一段距离,但你可以在此处关注。
  • 特性中的返回位置 impl 特性 (RPITIT) 和特性中的异步函数 (AFIT) - 这些功能只有在 GAT 和 TAIT 取得进展后才有可能实现。它们目前在一个单独的 跟踪问题下进行跟踪。

路线图

最后,让我们将所有这些放到路线图上。与往常一样,当目标是具体的、可衡量的和有时间限制的时,目标是最好的。为此,我们决定将我们的目标大致分为 4 个阶段:2023 年夏季、2023 年年底、2024 年年底和 2027 年年底(6 个月、1 年、2 年和 5 年)。总的来说,我们的目标是构建一个平台来维护一个健全的、可测试的和有文档的类型系统,该系统可以扩展到 Rust 语言需要的新特性。此外,我们希望培养一个可持续的开源团队(类型团队)来维护该平台和类型系统。

快速说明:这里的一些内容尚未在这篇文章中得到充分解释,但为了完整起见,它们已被包含在内。所以,事不宜迟

6 个月

  • 正在进行中的新的特征求解器应该是可测试的
  • a-mir-formality 应该可以针对 Rust 测试套件进行测试
  • TAIT 和 RPITIT/AFIT 都应该稳定或正在稳定化的道路上。

2023 年底

  • 新的特征求解器替换了现有特征求解器的部分,但不是在所有地方都使用
  • 我们有(针对团队的)入职计划和新特征求解器的文档
  • a-mir-formality 已集成到语言设计过程中

2024 年底

  • 新的特征求解器由 rustc 和 rust-analyzer 共享
    • 里程碑:类型 IR 共享
  • 我们有一个干净的 API 用于可扩展的特性错误,该 API 至少在内部可用
  • “闪亮的功能”
    • Polonius 处于可用状态
    • 高阶特性边界中的隐含边界(有关此功能将修复的问题的示例,请参见此问题
    • 能够在任何地方使用 impl Trait
  • 潜在的版本边界更改

2027 年底

  • (类型)不健全问题已解决
  • 大多数语言扩展都很容易做到;大型扩展是可行的
  • a-mir-formality 通过了 99.9% 的 Rust 测试套件

结论

对于 Rust 来说,这是一个激动人心的时刻。随着其用户群和受欢迎程度的增长,该语言也在增长。随着语言的增长,对支持该语言的可持续类型系统的需求也变得越来越明显。该项目已经成立了这个新的类型团队来满足这一需求,并且希望,在这篇文章中,你可以看到该团队到目前为止已经完成了很多工作。我们预计这种趋势将在未来许多年内继续下去。

与往常一样,如果你想参与或有任何疑问,请访问Rust zulip