Lowering
Lowering步骤将AST转换为HIR。 这意味着许多与类型分析或类似的语法无关分析无关的代码在这一阶段被删除了。 这种结构的例子包括但不限于
- 括号
- 无需替换,直接删除,树结构本身就能明确运算顺序
for循环和while (let)循环- 转换为
loop+match和一些letbinding
- 转换为
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时也会检查是否存在现有的HirIds) - 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中不存在的新节点,则必须为它们创建新的ID。 这是通过调用next_id方法来完成的,该方法会生成一个新的NodeId并自动为您lowering它,以便您也可以获得HirId。
如果您要创建新的DefId,由于每个DefId需要具有一个对应的NodeId,建议将这些NodeId添加到AST中,这样您就不必在lowering时生成新的DefId。
这样做的好处是创建了一种通过NodeId查找某物的DefID的方法。
如果lower操作需要在多个位置使用该DefId,则不能在所有这些位置生成一个新的NodeId,因为那样的话,您将获得多余的的DefId。
对于来自AST的NodeId来说,这不是问题。
有一个NodeId也允许了DefCollector生成DefId,而不需要立即进行操作。将DefId生成集中在一个地方可以使重构和推理变得更加容易。