Rust 正式成立 Types Team:类型系统终于有了专属团队

2023 年 1 月,Rust 官方博客发布了一篇公告,正式宣布 Types Team(类型团队) 的成立。

说"正式宣布",是因为这个团队其实早在 2022 年 5 月底就已经悄然运作了------只是一直没有对外说过。这次公告,是在团队完成了一次为期三天的线上线下混合会议之后,借着年初的时机,向社区汇报:我们是谁、做了什么、接下来要去哪里。

本文就是基于 Rust 官方博客 2023 年 1 月 20 日发布的《Officially announcing the types team》整理撰写,作者为 Jack Huey,代表 The Types Team。

原文地址


两个数字,说明问题有多严重

公告开门见山地列出了两个数字,解释为什么需要成立这样一个团队。

220 个:Rust 目前有约 220 个已接受但尚未完整实现的语言、编译器或类型系统特性的追踪 Issue,其中约一半已经存在了至少三年,许多更是积压了更久。这些 Issue 之所以久拖不决,不单是人手不足的问题,更根本的原因是:在 Rust 这样复杂的语言里,想把一个特性的语义和整体语言上下文对齐,本身就极其困难。往往没有人能一眼看出"要把这件事做完,具体该做什么"。

62 个:目前有 62 个未解决的健全性漏洞(unsoundness issues)。听起来很吓人,但公告也做了说明:这些几乎都是在极端边界条件下才会触发的问题,是专门找 bug 的人刻意去戳才能发现的;正常写代码几乎不会踩到。尽管如此,这些漏洞不应该存在,而修复它们一直没有一个明确的归口。

这两个数字共同指向一个结论:Rust 的类型系统需要一个专职团队来系统性地治理。


类型系统到底管哪些东西?

公告把 Types Team 的职责范围划定在三个紧密相关的组件上:

  • 类型检查器(Type Checker):负责确定变量的类型,以及类型之间的关系是否合法;
  • Trait 求解器(Trait Solver):负责回答"类型 T 是否满足某个 trait 约束"这类问题;
  • 借用检查器(Borrow Checker):负责验证 Rust 的所有权模型在任何情况下都成立。

这三者合在一起,就是 Rust 的"类型系统"。它们在实现上深度耦合,往往牵一发而动全身,独立处理任何一个都很难不影响其他两个。

这个边界由 RFC 3254 正式确立,Types Team 对这个范围内的设计和实现拥有完整的决策权。


两个父团队,一项特殊授权

Types Team 在 Rust 的治理结构中有一个独特的位置:它同时拥有两个父团队------语言团队(Lang Team)和编译器团队(Compiler Team),这在 Rust 的团队体系中是独一份的。

这两个父团队分别向 Types Team 做了不同的授权:

  • 语言团队授权 Types Team 负责类型系统的设计------不是"这个特性用起来顺不顺手"这类体验层面的事,而是"这个机制在类型系统内部是怎么运作的"这类底层语义的决策;
  • 编译器团队授权 Types Team 负责 trait 系统实现层面的定义和维护。

更重要的是一项额外授权:健全性漏洞的修复。过去,修复一个涉及类型系统的健全性 bug,需要同时协调语言团队和编译器团队,流程繁琐。现在,Types Team 在大多数情况下可以独立完成评估和修复,无需两个父团队同步参与。

即便某个修复在技术上会破坏向后兼容性(修复安全漏洞本不在 Rust 的兼容性承诺范围内),类型团队也可以经过内部签字确认,并用 Crater 工具评估对生态系统的影响后,自行推进------而不需要跨团队拉会。这让关闭健全性漏洞这件事变得切实可行。


Chalk 的终结,以及两条新路

Types Team 公告中最让人瞩目的技术决策,是对 Chalk 命运的宣判。

Chalk 是一个从 2015 年就开始开发的实验性 trait 求解器。它的思路是把 Rust trait 系统的语法和语义翻译成一套类似 Prolog 的逻辑规则,用逻辑求解器来处理 trait 查询,然后替换编译器内部的旧求解器。Rust-analyzer 今天仍在使用 Chalk。

但经过多年的开发,团队得出了一个结论:Chalk 很可能不是 Rust 的长期解决方案。原因有两点:

第一,trait 求解器只是整个类型系统的一部分。如果只对这一部分单独建模,就很难把它和类型检查器、借用检查器之间的关系描述清楚;而对整个类型系统统一建模,才能得到完整的图景。

第二,编译器和形式化的需求其实是两件不同的事。编译器需要高性能,还要能追踪足够多的信息来生成有用的错误提示;而一个好的形式化模型,需要的是完整、易读、易维护。Chalk 多年来试图同时满足这两者,结果两者都没有做好。

于是,团队走向了两条并行的新路:

a-mir-formality:这是一个对 Rust 整个类型系统进行形式化描述的项目。它的目标不是直接跑在生产编译器里,而是成为评估新特性设计和健全性漏洞的"参考实现"------在一个干净的模型上验证想法,然后再把结论同步给实际的编译器。项目最初用 PLT Redex 编写,Rust 移植版本正在进行中。

新的内置 Trait 求解器(New In-Tree Trait Solver):这是一个直接在 rustc 代码树内编写的新 trait 求解器,目标是最终替换掉现有的旧求解器。它的范围比 a-mir-formality 小,设计上会尽可能复用现有编译器的基础设施,以减少迁移代价。为了将来可能被独立拆出,它从一开始就被设计为尽可能模块化。


已经完成的健全性修复

在去年 5 月到公告发布的约七个月内,团队已经落地了一系列健全性修复:

  • Rust 1.65 修复了隐含边界(implied bounds)在非规范化类型下的处理,未发现兼容性回归;
  • Rust 1.66 修复了不透明类型(opaque type)上不应存在的隐式生命周期约束,未发现兼容性回归;
  • Rust 1.68 将引入 IMPLIED_BOUNDS_ENTAILMENT lint,标记一类发现了大量历史代码回归的不健全模式,以"未来兼容性警告"的方式给出过渡期;
  • 另有若干修复正在推进中,部分因发现兼容性回归而需要额外工作。

这些数字说明了一件事:修复健全性问题并不总是无痛的。有时确实会让旧代码无法编译,即使那些代码从技术上讲本来就不应该通过编译。团队的做法是尽量给出过渡期,并用 Crater 提前评估影响范围。


正在推进的新特性

公告还列出了几个与类型系统深度绑定、类型团队深度参与的特性:

GATs(泛型关联类型):这是列表里唯一一个已经稳定的特性,于 Rust 1.65 稳定。GATs 早在类型团队成立之前就存在,但稳定化最后阶段的推进工作由团队主导完成。

TAITs(类型别名 impl Trait):正确实现这个特性需要对类型检查器有深入的理解。公告时点已接近稳定。

Trait 向上转型(Trait Upcasting):允许把一个 trait 对象向上转型为它的父 trait,改动不大但涉及类型系统交互。

否定 impl(Negative Impls):允许显式声明某个类型不实现某个 trait。还有若干 bug 和健全性问题未解决,距稳定还有距离。

RPITITs 和 AFITs:分别是"在 trait 方法中返回 impl Trait"和"在 trait 方法中使用 async fn"。这两个特性依赖 GATs 和 TAITs 的基础,目前一起追踪。


分四阶段的路线图

公告给出了一张具体的时间表,把目标切成了四段:

2023 年夏季(6 个月内)

  • 新 trait 求解器达到可测试状态;
  • a-mir-formality 能够针对 Rust 测试套件运行;
  • TAITs 和 RPITITs/AFITs 稳定,或走上稳定路径。

2023 年底

  • 新 trait 求解器替换旧求解器的部分功能(不是全部);
  • 新求解器有完整的入门文档;
  • a-mir-formality 正式纳入语言设计流程。

2024 年底

  • rustc 和 rust-analyzer 共用同一个新 trait 求解器;
  • 可扩展的 trait 错误 API 在内部可用;
  • Polonius 借用检查器达到可用状态;
  • 更高阶 trait 约束中的隐含边界问题得到解决;
  • impl Trait 基本上可以出现在任何应该出现的地方。

2027 年底

  • 类型系统相关的健全性问题全部解决;
  • 大多数语言扩展变得容易实现,大型扩展变得可行;
  • a-mir-formality 通过 Rust 测试套件的 99.9%。

一个团队的成立,意味着什么

这篇公告读下来,有一点很值得注意:Types Team 的成立,首先解决的不是技术问题,而是组织问题

过去,类型系统相关的决策需要在语言团队和编译器团队之间反复协调。一个健全性 bug 的修复,往往因为归口不清而搁置。一个新特性的推进,往往因为没有明确的负责人而在追踪 Issue 里沉睡。

现在,这些问题有了一个明确的主人。设计、实现、健全性修复------在这个范围内,Types Team 说了算,不需要每次都拉两个团队协调。

这件事的重要性,可能不比任何一个具体的技术突破低。


相关推荐
掘金码甲哥14 分钟前
当对话模型遇上向量模型,vllm production stack 又该如何应对?
后端
传奇开心果编程37 分钟前
【springboot基础语法学与练】第 1 课:从零开始
java·spring boot·后端·学习
Bruce_Liuxiaowei41 分钟前
Python 实例赋值遮蔽类属性:一个从不报错的静默陷阱
开发语言·python·语法糖
IT_陈寒1 小时前
Java线程池用错参数,我的服务居然悄悄崩溃了
前端·人工智能·后端
光影少年1 小时前
Express 中间件原理
后端·node.js·express
梦醒沉醉1 小时前
std1.97.1——cmp模块细览
rust
aramae2 小时前
MySQL内置函数(7)
开发语言·笔记·后端·mysql·其他
徐小夕3 小时前
存量.doc 文档怎么办?JitWord 开源转换库打通旧文档到在线协同全链路
后端·架构·github
ee又momo3 小时前
一次 JWT Token 过期续期的踩坑记录
后端
二月龙3 小时前
App 瘦身实战:图片、so 库、资源压缩,安装包体积减小 40%
后端