哦,嘿,这是 另一个 新团队公告。但我必须承认:如果你关注 RFC 仓库、Rust zulip,或者对 GATs 稳定化公告帖子 尤其关注,那么这可能对你来说并不意外。事实上,这个“新”团队是在去年 5 月底正式成立的。
我们现在(而不是几个月前或...永远)分享这篇文章的原因有几个。首先,团队在 12 月初完成了为期三天的线下/混合会议,我们想分享这次会议的目的和成果。其次,现在发布这个公告正好是团队成立 7 个月左右,我们想分享这段时间取得的成就。最后,随着我们进入 2023 年新的一年,现在是分享我们对今年及以后发展方向的绝佳时机。
背景 - 我们是如何走到这一步的?
Rust 在过去几年中取得了显著增长,在许多指标上都如此:用户、贡献者、功能、工具、文档等等。随着它的发展,人们想要用它做的事情清单也同样快速增长。除了强大而符合人体工程学的功能外,对 IDE 或语言学习工具等强大工具的需求也越来越明显。新的编译器(前端和后端)正在被编写。最重要的是,我们希望 Rust 继续保持其核心设计原则之一:安全性。
所有这些都突出了几个关键需求:能够知道 Rust 语言应该如何工作,能够以相对轻松的方式扩展语言和编译器以添加新功能,能够接入编译器并能够查询有关程序的重要信息,最后能够以一种易于管理和稳健的方式维护语言和编译器。多年来,人们在这些需求上付出了相当大的努力,但我们还没有完全实现这些关键要求。
为了进一步说明,并给出一些数据,目前有大约 220 个针对 语言、编译器 或 类型 功能的开放跟踪问题已被接受,但尚未完全实现,其中大约一半至少有 3 年历史,许多问题比这还要古老。许多这些跟踪问题之所以开放了这么长时间,不仅仅是因为带宽问题,还因为开发这些功能很困难,很大程度上是因为将相关的语义正确地放在整个语言的上下文中很困难;对于任何人都很难查看它们并知道需要做些什么才能完成它们。很明显,我们仍然需要更好的基础来对语言和编译器进行更改。
另一个可能让你震惊的数字是:目前有 62 个开放的 不安全问题。这听起来比实际情况可怕得多:几乎所有这些问题都是编译器和语言的边缘情况,这些边缘情况是由专门进行探测和测试以发现它们的人发现的;在实践中,这些问题不会出现在你编写的程序中。尽管如此,我们还是希望消除这些边缘情况。
类型团队
展望未来,让我们谈谈 Rust 的一个更小的子集,而不是整个语言和编译器。具体来说,这里相关的部分包括类型检查器 - 粗略地说,定义变量如何被分配其类型的语义和实现,特征求解 - 决定哪些类型定义了哪些特征,以及借用检查 - 证明 Rust 的所有权模型始终有效。所有这些都可以被认为是“类型系统”的凝聚力。
根据 RFC 3254,Rust 语言和编译器的上述子集属于类型团队的管辖范围。那么,这究竟意味着什么呢?
首先,从 2018 年左右开始,就存在一个“特征工作组”,其主要目标是创建 Rust 特征系统的性能良好且可扩展的定义和实现(包括 Chalk 特征求解库)。随着时间的推移,特别是在 2021 年下半年到 2022 年,工作组的影响力和责任自然扩展到了类型检查器和借用检查器 - 它们实际上是紧密相连的,很难将特征求解器与其他两个分离。因此,在某种程度上,类型团队本质上取代了以前的特征工作组。
另一个相关的 工作组是 polonius 工作组,它主要负责 Polonius 借用检查库的设计和实现。虽然工作组本身将继续存在,但现在也属于类型团队的管辖范围。
现在,虽然特征工作组基本上被合并到类型团队中,但创建一个团队有一些好处。首先,与 样式团队(以及许多其他团队)一样,类型团队不是一个顶级团队。它实际上,目前唯一地,有两个父团队:lang 团队和编译器团队。这两个团队都决定将涵盖类型系统的决策权委托给类型团队。
语言团队委托了类型系统设计的部分。然而,重要的是,这种设计涵盖了类型系统功能的“感觉”的较少部分,而更多地涵盖了它的“工作原理”,期望类型团队在需要时提供建议并提出对新语言扩展的担忧。(这种划分没有明确定义,但期望一般是谨慎行事)。另一方面,编译器团队委托了定义和维护特征系统实现的责任。
一项传统上由语言团队和编译器团队共同承担的责任是评估和修复与类型系统相关的语言中的健全性错误。这些错误通常源于实现定义的语言语义,并且过去需要语言团队和编译器团队的同步和输入。在大多数情况下,类型团队现在有权评估和实施修复,而无需直接从任何父团队获得输入。重要的是,这适用于技术上向后不兼容的修复。虽然修复安全漏洞 不属于 Rust 的向后兼容性保证,但这些决定并非轻率做出,通常需要团队签字,并使用 crater 评估潜在的生态系统破坏。然而,这现在可以在一个团队内完成,而无需协调两个独立的团队,这使得关闭这些健全性漏洞变得更容易(我将在后面进一步讨论这一点)。
形式化 Rust 类型系统
如上所述,不断发展的 Rust 语言的一个几乎必不可少的要素是了解它应该如何工作(以及将其很好地记录下来)。最近有一些努力推动 Rust 规范(如 Ferrocene 或 这个开放的 RFC),但无论其是否可能集成到更通用的规范中,拥有一个形式化的类型系统定义都将非常有益。事实上,形式化的存在将允许更好地评估潜在的新功能或健全性漏洞,而无需考虑编译器其他部分的微妙复杂性。
早在 2015 年,Rust 1.0 发布后不久,一个名为 Chalk 的实验性 Rust 特征求解器就开始编写。Chalk 的核心思想是将 Rust 特征系统的表面语法和概念(例如特征、实现、where 子句)转换为一组逻辑规则,这些规则可以使用类似 Prolog 的求解器来求解。然后,一旦这组逻辑和求解达到与编译器本身内的特征求解器相同的水平,计划就是简单地替换现有的求解器。在此期间(以及继续向前),这个新的求解器可以被其他工具使用,例如 rust-analyzer,它在今天被使用。
现在,考虑到 Chalk 的年龄以及人们希望它能够实现的承诺,你可能会忍不住问“Chalk,什么时候?” - 而且很多人确实问了。然而,我们多年来已经了解到,Chalk 可能不是 Rust 的正确长期解决方案,原因有几个。首先,正如本文中多次提到的,特征求解器只是更大的类型系统的一部分;对整个类型系统如何组合在一起进行建模,比尝试分别对各个部分进行建模,能够更完整地了解其细节。其次,编译器的需求与形式化的需求大不相同:编译器需要性能良好的代码,并且能够跟踪诊断所需的信息;一个好的形式化不仅要完整,而且要易于维护、阅读和理解。多年来,Chalk 试图同时满足这两个需求,但到目前为止,它都没有实现。
那么,未来的计划是什么呢?首先,类型团队已经开始着手对 Rust 类型系统进行形式化,目前代号为 a-mir-formality。最初的实验阶段使用 PLT redex 编写,但 Rust 移植正在进行中。还有很多工作要做(包括对更多特征系统进行建模、编写 RFC,以及将其移入 rust-lang 组织),但它已经展现出巨大的潜力。
其次,我们已经开始了一个 计划,用于在树内编写一个新的特征求解器。这个新的特征求解器在范围上比 a-mir-formality 更有限(即不打算涵盖整个类型系统)。在很多方面,它预计与 Chalk 非常相似,但会利用现有编译器和特征求解器的部分功能,以使过渡尽可能平滑。我们确实希望它在某个时候被提取到树外,因此它被设计得尽可能模块化。在本月早些时候的类型团队会议上,我们能够确定我们期望求解器的结构,并且我们已经将它 合并到源代码树中。
最后,Chalk 将不再是团队的重点。在短期内,它可能仍然是实验的有用工具。如前所述,rust-analyzer 使用 Chalk 作为其特征求解器。它也可以在 rustc 中使用不稳定的特性标志。因此,新的想法目前可以在 Chalk 中实现,并在实践中进行测试。然而,随着 a-mir-formality 和新的树内特征求解器变得更加可用,以及它们的接口变得更加容易访问,这种优势可能不会持续太久。所有这些并不是说 Chalk 失败了。事实上,Chalk 教会了我们很多关于如何以逻辑的方式思考 Rust 特征求解器,并且当前的 Rust 特征求解器已经随着时间的推移而演变,以更紧密地模拟 Chalk,即使是不完整的。我们预计在一段时间内仍然会以某种方式支持 Chalk,用于 rust-analyzer,以及可能用于那些有兴趣对其进行实验的人。
修复健壮性漏洞
如前所述,创建一个新的类型团队,并从 lang 和编译器团队获得授权,一个很大的好处是能够独立地评估和修复健壮性问题。然而,一个次要的好处实际上只是更好的流程和知识共享,使团队成员能够就存在的健壮性问题、它们存在的原因以及修复它们需要什么达成一致。例如,在本月早些时候的会议上,我们能够浏览完整的健壮性问题列表(重点关注与类型系统相关的那些问题),确定它们的原因,并讨论预期的修复方法(尽管大多数修复需要上一节中讨论的先决条件)。
此外,团队已经修复了许多健壮性问题,并且还有几个正在进行中。我不会详细介绍,而是选择将它们列出来。
- 考虑对隐式边界使用非规范化类型:已在 1.65 中落地,未发现回归
- 对不透明类型既不要求也不暗示生命周期边界以进行良好形式化:已在 1.66 中落地,未发现回归
- 添加
IMPLIED_BOUNDS_ENTAILMENT
警告:将在 1.68 中落地,未来兼容警告,因为发现许多回归(健壮性问题) - 检查 ADT 字段的复制实现,考虑区域:目前已打开,准备落地
- 在 wfcheck 中规范化之前注册 wf 义务:目前已打开,发现回归,需要额外工作
- 在一致性检查期间将投影处理为未覆盖类型:目前已打开,发现一些回归,建议使用未来兼容警告
- 不要在 AstConv 中规范化:将在 1.68 中落地,发现 1 个小回归
如您所见,我们在修复健壮性漏洞方面取得了进展。这些有时会破坏代码,如 crater 所评估的那样。但是,我们尽力减轻这种情况,即使被破坏的代码在技术上是不健壮的。
新功能
虽然从技术上讲,类型团队没有权限提出和设计新功能(这些更多地属于 lang 团队),但有一些情况是团队深度参与(如果不是驱动)功能设计的。
这些可以是小的补充,接近于错误修复。例如,这个 PR 允许比以前编译的更多生命周期超越边界的排列。或者,这些 PR 可以是更大的、更具影响力的更改,不适合“功能”,而是与类型系统紧密相关。例如,这个 PR 使 Sized
特征成为共递归的,这实际上使更多循环边界编译(参见 这个测试 以了解示例)。
还有一些更大的功能和功能集是由类型团队驱动的,这主要是因为它们与类型系统有很大的交集。以下是一些例子
- 泛型关联类型 (GAT) - 该功能早于类型团队,并且是此列表中唯一一个到目前为止已经稳定化的功能。但由于与类型系统的紧密交互,团队能够解决其最终稳定化道路上遇到的问题。参见 这篇博文 以了解更多详细信息。
- 类型别名实现特征 (TAIT) - 正确地实现此功能需要对类型检查器有透彻的了解。这接近于稳定化。有关更多信息,请参见 跟踪问题。
- 特征向上转型 - 这个功能相对较小,但与类型系统有一些交互。同样,请参见 跟踪问题 以了解该功能的解释。
- 负面实现 - 这也早于类型团队,但最近由团队进行了研究。仍然存在未解决的错误和健壮性问题,因此它距离稳定化还有一段时间,但您可以 在这里 关注它。
- 特征中的返回位置实现特征 (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,至少在内部可用
- “闪亮的功能”
- Polonius 处于可用状态
- 更高阶特征边界中的隐式边界(参见 此问题 以了解此修复程序的示例)
- 能够在几乎任何地方使用
impl Trait
- 潜在的版本边界更改
2027 年年底
- (类型)健壮性问题已解决
- 大多数语言扩展很容易实现;大型扩展是可行的
- a-mir-formality 通过了 99.9% 的 Rust 测试套件
结论
对于 Rust 来说,这是一个激动人心的时刻。随着其用户群和流行度的增长,语言也在不断发展。随着语言的增长,对可持续的类型系统来支持语言的需求变得越来越明显。该项目组建了这个新的类型团队来解决这一需求,希望通过这篇文章,您能看到该团队迄今为止取得了很大的成就。我们预计这种趋势将在未来几年内持续下去。
与往常一样,如果您想参与或有任何问题,请访问 Rust zulip。