-
Notifications
You must be signed in to change notification settings - Fork 1
【Zig 日报】类型解析重构:伴随语言层面的优化 #312
Description
作者:Matthew Lugg
今天,在经过两个月(严格来说是三个月)的努力后,我合并了一个包含 3 万行代码的 PR。这个分支的目标是将 Zig 编译器的内部类型解析逻辑重构为更逻辑化、更简洁的设计。对我个人而言,这是一个非常令人兴奋的变化,因为它让我能够清理大量编译器内部的陈旧代码,同时也带来了一些你可能会感兴趣的、面向用户的改进!
首先,Zig 编译器现在在分析类型字段时变得更加“惰性”了:如果一个类型从未被初始化,那么 Zig 就没必要关心这个类型“长什么样”。当你把一个类型兼作命名空间使用时(这是现代 Zig 中的一种常见模式),这一点尤为重要。例如,当你使用 std.io.Writer 时,你并不希望编译器同时也把 std.io 中的一堆代码都拉进来!下面是一个直观的例子:
const Foo = struct {
bad_field: @compileError("我是个邪恶的字段,哈哈哈"),
const something = 123;
};
comptime {
_ = Foo.something; // `Foo` 仅被用作命名空间
}在以前,这段代码会触发编译错误。而现在,它可以顺利通过编译,因为 Zig 根本没有去理会那个 @compileError 调用。
我们做出的另一项改进是优化了“依赖循环(dependency loop)”的体验。任何以前在 Zig 中遇到过依赖循环编译错误的人都知道,那些错误提示完全没用——但现在情况改变了!如果你遇到依赖循环(现在发生的概率也比以前低了一些),你会得到一条详细的错误消息,准确地告诉你循环是从哪里产生的。看看这个:
const Foo = struct { inner: Bar };
const Bar = struct { x: u32 align(@alignOf(Foo)) };
comptime {
_ = @as(Foo, undefined);
}编译输出:
$ zig build-obj repro.zig
error: dependency loop with length 2
repro.zig:1:29: note: type 'repro.Foo' depends on type 'repro.Bar' for field declared here
const Foo = struct { inner: Bar };
^~~
repro.zig:2:44: note: type 'repro.Bar' depends on type 'repro.Foo' for alignment query here
const Bar = struct { x: u32 align(@alignOf(Foo)) };
^~~
note: eliminate any one of these dependencies to break the loop
当然,依赖循环可能会比这复杂得多,但在我测试过的每个案例中,错误消息都包含足够的信息,让人能轻松看清问题所在。
此外,这个 PR 对 Zig 编译器的“增量编译”功能也做了重大改进。简而言之,它修复了大量已知漏洞。特别值得一提的是,“过度分析”问题(即增量更新时做了比必要更多的功,有时甚至多出好几倍)应该终于被彻底消除了——这使得增量编译在许多情况下变得显著更快!如果你还没试过增量编译,建议尝试一下:它的开发体验真的很棒。这绝对是最令我兴奋的改进,也是当初推动这项重构的主要动力之一。
这个 PR 还带来了许多其他变化——几十个 Bug 修复、一些细微的语言变更(大多是相当冷门的特性)以及编译器性能的提升。这里的内容太多,无法一一列举,但如果你有兴趣深入了解,可以去 Codeberg 查看那个 PR。当然,如果你遇到任何 Bug,请随时提交 Issue。祝大家 Hack 愉快!
加入我们
Zig 中文社区是一个开放的组织,我们致力于推广 Zig 在中文群体中的使用,有多种方式可以参与进来:
- 供稿,分享自己使用 Zig 的心得
- 改进 ZigCC 组织下的开源项目
- 加入微信群、Telegram 群组