mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-26 13:01:27 +03:00
sembr src/hir/lowering.md
This commit is contained in:
@@ -2,8 +2,8 @@
|
||||
|
||||
The AST lowering step converts AST to [HIR](../hir.md).
|
||||
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
|
||||
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
|
||||
@@ -19,16 +19,19 @@ The implementation of AST lowering is in the [`rustc_ast_lowering`] crate.
|
||||
The entry point is [`lower_to_hir`], which retrieves the post-expansion AST
|
||||
and resolver data from [`TyCtxt`] and builds the [`hir::Crate`] for the whole crate.
|
||||
|
||||
Lowering is organized around HIR owners. [`lower_to_hir`] first indexes the
|
||||
Lowering is organized around HIR owners.
|
||||
[`lower_to_hir`] first indexes the
|
||||
crate and then [`ItemLowerer::lower_node`] lowers each crate, item, associated
|
||||
item, and foreign item.
|
||||
|
||||
Most of the lowering logic lives on [`LoweringContext`]. The implementation is
|
||||
Most of the lowering logic lives on [`LoweringContext`].
|
||||
The implementation is
|
||||
split across multiple files in the [`rustc_ast_lowering`] crate such as `item.rs`,
|
||||
`expr.rs`, `pat.rs`, `path.rs`, and others, but they all share the same [`LoweringContext`]
|
||||
state and ID‑lowering machinery.
|
||||
|
||||
Each owner is lowered in its own [`with_hir_id_owner`] scope. This is why the
|
||||
Each owner is lowered in its own [`with_hir_id_owner`] scope.
|
||||
This is why the
|
||||
`HirId` invariants below matter: `lower_node_id` maps AST `NodeId`s into the
|
||||
current owner, while `next_id` creates fresh HIR-only nodes introduced during
|
||||
desugaring.
|
||||
@@ -36,18 +39,20 @@ desugaring.
|
||||
Lowering needs to uphold several invariants in order to not trigger the
|
||||
sanity checks in [`compiler/rustc_passes/src/hir_id_validator.rs`][hir_id_validator]:
|
||||
|
||||
1. A `HirId` must be used if created. So if you use the `lower_node_id`,
|
||||
1. A `HirId` must be used if created.
|
||||
So if you use the `lower_node_id`,
|
||||
you *must* use the resulting `NodeId` or `HirId` (either is fine, since
|
||||
any `NodeId`s in the `HIR` are checked for existing `HirId`s)
|
||||
2. Lowering a `HirId` must be done in the scope of the *owning* item.
|
||||
This means you need to use `with_hir_id_owner` if you are creating parts
|
||||
of an item other than the one being currently lowered. This happens for
|
||||
example during the lowering of existential `impl Trait`
|
||||
of an item other than the one being currently lowered.
|
||||
This happens for example during the lowering of existential `impl Trait`
|
||||
3. A `NodeId` that will be placed into a HIR structure must be lowered,
|
||||
even if its `HirId` is unused. Calling
|
||||
`let _ = self.lower_node_id(node_id);` is perfectly legitimate.
|
||||
even if its `HirId` is unused.
|
||||
Calling `let _ = self.lower_node_id(node_id);` is perfectly legitimate.
|
||||
4. 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 the `next_id` method,
|
||||
create new ids for them.
|
||||
This is done by calling the `next_id` method,
|
||||
which produces both a new `NodeId` as well as automatically lowering it
|
||||
for you so you also get the `HirId`.
|
||||
|
||||
@@ -62,12 +67,16 @@ sanity checks in [`compiler/rustc_passes/src/hir_id_validator.rs`][hir_id_valida
|
||||
|
||||
If you are creating new `DefId`s, since each `DefId` needs to have a
|
||||
corresponding `NodeId`, it is advisable to add these `NodeId`s to the
|
||||
`AST` so you don't have to generate new ones during lowering. This has
|
||||
`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
|
||||
`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.
|
||||
`DefId` then.
|
||||
With a `NodeId` from the `AST` this is not an issue.
|
||||
|
||||
Having the `NodeId` also allows the `DefCollector` to generate the `DefId`s
|
||||
instead of lowering having to do it on the fly. Centralizing the `DefId`
|
||||
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.
|
||||
|
||||
Reference in New Issue
Block a user