特性工作组 2020 年冲刺 3 总结

2020 年 7 月 17 日 · Jack Huey 代表 特性工作组

又来了?感觉好像几周前我们才做过一次...6 周前 😉。总之,本次冲刺的大部分工作是前两次的延续:努力使 Chalk 功能完善,并最终在 rustc 中使用它来进行特性解析。

对于以前没见过此类总结的人,如果你对特性工作组感到好奇,可以在此处找到一份总结。

鸣谢

一如既往,非常感谢所有参与本次冲刺的人

Chalk crate 清理和每周发布

自诞生以来,Chalk 在 crate 结构方面经历了不少变化,这对于任何规模适中的项目来说都很正常。在本次冲刺中,我们花时间稍微清理了一下 crate 结构。最简单的做法可能是简要介绍一下我们最终得到的结构。更全面的概述可以在Chalk 手册中找到。

  • chalk-derive - 定义 derive proc 宏
  • chalk-ir - 一个基本的“类型库”,将来可能在 rustc、Chalk 和 rust-analyzer 之间共享
  • chalk-solve - 定义来自 chalk-ir 的类型的 Rust 语义
  • chalk-engine - 实现 SLG 解析器
  • chalk-recursive - 实现递归解析器
  • chalk-parse - 用于测试,将类似 Rust 的语法解析为 chalk-irchalk-solve 类型
  • chalk-integration - 用于测试,提供有用的测试类型
  • chalk - 用于测试,提供 REPL

在本次冲刺期间,我们还设立了 Chalk crates 的每周定期发布。虽然目前这些都是 0.*.0 的补丁版本,但这为未来的稳定版本建立了基础设施,并提供了可用于 rustc 和 rust-analyzer 的已发布 crates。将来,当 Chalk 开发更加稳定时,我们希望切换到手动发布。我们还计划设置 bors 来确保 master 分支始终构建并通过测试。

推进 rustc 对 GATs 的支持

Chalk 对 GATs 的支持已经有一段时间了;在 Chalk 中,GATs 是其他一切的自然延伸。然而,在 rustc 中实现 GATs 却有些困难,过去几年进展相对停滞,主要精力都放在了让 Chalk 准备就绪上。但最近,在 rustc 中已经完成了一些工作,以便让 GATs 在当前的 rustc 特性系统下工作。

提取一个表示类型的共享库

作为一个长期目标,我们希望有一天在 Chalk 和 rustc 之间拥有一个共享的类型库。此外,这个类型库也可以用于其他项目,例如 rust-analyzer。在 Chalk 方面,添加了更多类型——例如闭包 (closures) 和枚举 (enums)——以及更多特性——例如 Fn 系列和 Unsize。此外,还做了一些反方向的工作:让 rustc 更接近 Chalk,例如Predicate 的内部化 (interning),以及引入 ForAll 谓词 (predicates)

编写 .chalk 文件用于调试

作为 Chalk 测试的一部分,我们可以编写类似 Rust 的“程序”,这些程序会被解析成 Chalk 类型。重要的是,这些程序比它们被降低成的类型简洁得多。为了更好地支持调试,我们实现了一个反向的系统:能够从底层类型生成类似 Rust 的程序。这对于调试 rustc 尝试编译的特定代码片段中的 bug 非常有用。此外,它还可以用于生成针对性能问题的程序。

改进对 impl Trait 的支持

在上次冲刺中,我们落地了初步的 impl Trait 支持,用于处理诸如 type Foo<T> = impl Bar 这样的简单情况。在本次冲刺中,我们开始着手添加对更复杂情况的支持,例如 type Foo<T>: Debug = impl Bar where T: Debug。此外,还进行了一些设计工作来支持检查这些结构的格式是否正确 (well-formed)。

扩展 Chalk 以支持 Rust 语义

这个目标与“提取一个表示类型的共享库”有些重叠,但它更侧重于表达类型的语义,而不是表示类型本身。例如,考虑下面的程序

trait Foo: Sized {
    fn foo(self) {}
}
impl Foo for u32 {}
impl Foo for String {}

fn main() {
  let x = 0;
  x.foo();
}

在本次冲刺之前,Chalk 无法正确处理这种情况;它不会知道你可以对 0 调用 foo。事实上,要正确编译这个程序,编译器必须知道 0 不可能是 String。考虑一下,如果你将 String 的实现改为 u64 会发生什么:rustc 不会知道你是希望 0u32 还是 u64。这基本上就是本次冲刺之前 Chalk 如何看待这个程序的。然而,现在 Chalk 能够正确处理这种情况了。

在 rustc 集成中处理生命周期约束

因此,作为特性解析的一部分,Chalk 和 rustc 有时可能会发现一个生命周期需要比另一个生命周期更长,或者一个类型必须比某个生命周期更长。例如,

trait Foo<'a, 'b, T> where 'a: 'b, T: 'a  {}

Chalk 本身不解决这些生命周期约束,而是将它们传回给 rustc。在本次冲刺期间,我们添加了在 Chalk 中表达这些 where 子句的能力。

其他工作

在本次冲刺期间还完成了一些不适合独立列出的零散工作。Chalk 在建议方面变得更智能了一些。我们引入了 tracing 用于日志记录。我们为递归解析器做了一些设计工作。当然,还有相当多的内部重构和清理。而且,rustc 集成也一直与时俱进,并针对 Chalk 的新特性进行了更新。

暑假

今年到目前为止一直很忙碌!自从第一次冲刺在二月初开始以来,我们取得了巨大的进展。然而,与前几次冲刺不同的是,我们不会立即开始下一次冲刺。相反,我们将休息几个月放假,并于九月份重新开始。在此之前,我们不会在 Zulip 上举行每周会议,也没有任何明确的目标。这部分是因为一些成员可能正在度假。但同时,代码倦怠 (burnout) 是真实存在的,时不时的休息会很有帮助。在此期间,还有一些项目需要完成/清理。

如果你有兴趣帮忙,请不要气馁!Zulip 应该仍然相当活跃,所以随时欢迎过来看看!