Lowering
Lowering 步骤将 AST 转换为 HIR。 这意味着许多在类型分析或类似的语法无关分析中没有用的代码在这一阶段被删除了。 这种结构的例子包括但不限于
- 括号
- 无需替换,直接删除,树结构本身就能明确运算顺序
for
循环和while (let)
循环- 转换为
loop
+match
和一些let
binding
- 转换为
if let
- 转换为
match
- 转换为
- Universal
impl Trait
- 转换成范型参数(会添加flag来标志这些参数不是由用户写的)
- Existential
impl Trait
- 转换为虚拟的
existential type
声明
- 转换为虚拟的
Lowering 需要遵守几点,否则就会违反 src/librustc_middle/hir/map/hir_id_validator.rs
中的制定的检查规则:
- 如果创建了一个
HirId
,那就必须使用它。 因此,如果您使用了lower_node_id
,则必须使用生成的NodeId
或HirId
(两个都可以,因为检查HIR
中的NodeId
时也会检查是否存在现有的HirId
) - Lowering
HirId
必须在对 item 有所有权的作用域内完成。 这意味着如果要创建除当前正在 Lower 的 item 之外的其他 item,则需要使用with_hir_id_owner
。 例如,在lower existential的impl Trait
时会发生这种情况. - 即使其
HirId
未使用,要放入HIR结构中的NodeId
也必须被 lower。 此时一个合理的方案是调用let _ = self.lower_node_id(node_id);
。 - 如果要创建在
AST
中不存在的新节点,则必须通过调用next_id
方法为它们创建新的 ID。 该方法会生成一个新的NodeId
并自动为您 lowering 它,以便您获得HirId
。
如果您要创建新的 DefId
,由于每个 DefId
需要具有一个对应的 NodeId
,建议将这些 NodeId
添加到 AST
中,这样您就不必在lowering时生成新的DefId
。
这样做的好处是创建了一种通过 NodeId
查找某物的 DefID
的方法。
如果 lower 操作需要在多个位置使用该 DefId
,则不能在所有这些位置生成一个新的 NodeId
,因为那样的话,您将获得多余的的 DefId
。
而对于来自AST的NodeId
来说,这些就都不是问题了。
有一个 NodeId
也使得 DefCollector
可以生成 DefId
,而不需要立即进行操作。
将 DefId
的生成集中在一个地方可以使重构和理解变得更加容易。