Lowering
The lowering step converts AST to HIR. This means many structures are removed if they are irrelevant for type analysis or similar syntax agnostic analyses. Examples of such structures include but are not limited to
- Parenthesis
- Removed without replacement, the tree structure makes order explicit
forloops andwhile (let)loops- Converted to
loop+matchand someletbindings
- Converted to
if let- Converted to
match
- Converted to
- Universal
impl Trait- Converted to generic arguments (but with some flags, to know that the user didn't write them)
- Existential
impl Trait- Converted to a virtual
existential typedeclaration
- Converted to a virtual
Lowering needs to uphold several invariants in order to not trigger the
sanity checks in src/librustc/hir/map/hir_id_validator.rs:
- A
HirIdmust be used if created. So if you use thelower_node_id, you must use the resultingNodeIdorHirId(either is fine, since anyNodeIds in theHIRare checked for existingHirIds) - Lowering a
HirIdmust be done in the scope of the owning item. This means you need to usewith_hir_id_ownerif you are creating parts of an item other than the one being currently lowered. This happens for example during the lowering of existentialimpl Trait - A
NodeIdthat will be placed into a HIR structure must be lowered, even if itsHirIdis unused. Callinglet _ = self.lower_node_id(node_id);is perfectly legitimate. - If you are creating new nodes that didn't exist in the
AST, you must create new ids for them. This is done by calling thenext_idmethod, which produces both a newNodeIdas well as automatically lowering it for you so you also get theHirId.
If you are creating new DefIds, since each DefId needs to have a
corresponding NodeId, it is advisable to add these NodeIds to the
AST so you don't have to generate new ones during lowering. This has
the advantage of creating a way to find the DefId of something via its
NodeId. If lowering needs this DefId in multiple places, you can't
generate a new NodeId in all those places because you'd also get a new
DefId then. With a NodeId from the AST this is not an issue.
Having the NodeId also allows the DefCollector to generate the DefIds
instead of lowering having to do it on the fly. Centralizing the DefId
generation in one place makes it easier to refactor and reason about.