]>
Commit | Line | Data |
---|---|---|
a1dfa0c6 XL |
1 | # The HIR |
2 | ||
6a06907d XL |
3 | <!-- toc --> |
4 | ||
a1dfa0c6 XL |
5 | The HIR – "High-Level Intermediate Representation" – is the primary IR used |
6 | in most of rustc. It is a compiler-friendly representation of the abstract | |
7 | syntax tree (AST) that is generated after parsing, macro expansion, and name | |
8 | resolution (see [Lowering](./lowering.html) for how the HIR is created). | |
9 | Many parts of HIR resemble Rust surface syntax quite closely, with | |
10 | the exception that some of Rust's expression forms have been desugared away. | |
11 | For example, `for` loops are converted into a `loop` and do not appear in | |
12 | the HIR. This makes HIR more amenable to analysis than a normal AST. | |
13 | ||
14 | This chapter covers the main concepts of the HIR. | |
15 | ||
16 | You can view the HIR representation of your code by passing the | |
6a06907d | 17 | `-Z unpretty=hir-tree` flag to rustc: |
a1dfa0c6 XL |
18 | |
19 | ```bash | |
6a06907d | 20 | cargo rustc -- -Z unpretty=hir-tree |
a1dfa0c6 XL |
21 | ``` |
22 | ||
6a06907d | 23 | ## Out-of-band storage and the `Crate` type |
a1dfa0c6 XL |
24 | |
25 | The top-level data-structure in the HIR is the [`Crate`], which stores | |
26 | the contents of the crate currently being compiled (we only ever | |
27 | construct HIR for the current crate). Whereas in the AST the crate | |
28 | data structure basically just contains the root module, the HIR | |
29 | `Crate` structure contains a number of maps and other things that | |
30 | serve to organize the content of the crate for easier access. | |
31 | ||
dfeec247 | 32 | [`Crate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/struct.Crate.html |
a1dfa0c6 XL |
33 | |
34 | For example, the contents of individual items (e.g. modules, | |
35 | functions, traits, impls, etc) in the HIR are not immediately | |
36 | accessible in the parents. So, for example, if there is a module item | |
37 | `foo` containing a function `bar()`: | |
38 | ||
39 | ```rust | |
40 | mod foo { | |
41 | fn bar() { } | |
42 | } | |
43 | ``` | |
44 | ||
45 | then in the HIR the representation of module `foo` (the [`Mod`] | |
46 | struct) would only have the **`ItemId`** `I` of `bar()`. To get the | |
47 | details of the function `bar()`, we would lookup `I` in the | |
48 | `items` map. | |
49 | ||
dfeec247 | 50 | [`Mod`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/struct.Mod.html |
a1dfa0c6 XL |
51 | |
52 | One nice result from this representation is that one can iterate | |
53 | over all items in the crate by iterating over the key-value pairs | |
54 | in these maps (without the need to trawl through the whole HIR). | |
55 | There are similar maps for things like trait items and impl items, | |
56 | as well as "bodies" (explained below). | |
57 | ||
58 | The other reason to set up the representation this way is for better | |
59 | integration with incremental compilation. This way, if you gain access | |
dfeec247 | 60 | to an [`&rustc_hir::Item`] (e.g. for the mod `foo`), you do not immediately |
a1dfa0c6 XL |
61 | gain access to the contents of the function `bar()`. Instead, you only |
62 | gain access to the **id** for `bar()`, and you must invoke some | |
63 | function to lookup the contents of `bar()` given its id; this gives | |
64 | the compiler a chance to observe that you accessed the data for | |
65 | `bar()`, and then record the dependency. | |
66 | ||
dfeec247 | 67 | [`&rustc_hir::Item`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/struct.Item.html |
a1dfa0c6 XL |
68 | |
69 | <a name="hir-id"></a> | |
70 | ||
6a06907d XL |
71 | ## Identifiers in the HIR |
72 | ||
73 | There are a bunch of different identifiers to refer to other nodes or definitions | |
74 | in the HIR. In short: | |
75 | - A [`DefId`] refers to a *definition* in any crate. | |
76 | - A [`LocalDefId`] refers to a *definition* in the currently compiled crate. | |
77 | - A [`HirId`] refers to *any node* in the HIR. | |
78 | ||
79 | For more detailed information, check out the [chapter on identifiers][ids]. | |
a1dfa0c6 | 80 | |
dfeec247 | 81 | [`DefId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefId.html |
6a06907d | 82 | [`LocalDefId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.LocalDefId.html |
dfeec247 | 83 | [`HirId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir_id/struct.HirId.html |
6a06907d | 84 | [ids]: ./identifiers.md#in-the-hir |
dfeec247 | 85 | |
6a06907d | 86 | ## The HIR Map |
a1dfa0c6 XL |
87 | |
88 | Most of the time when you are working with the HIR, you will do so via | |
6a06907d | 89 | the **HIR Map**, accessible in the tcx via [`tcx.hir()`] (and defined in |
a1dfa0c6 XL |
90 | the [`hir::map`] module). The [HIR map] contains a [number of methods] to |
91 | convert between IDs of various kinds and to lookup data associated | |
6a06907d | 92 | with a HIR node. |
a1dfa0c6 | 93 | |
6a06907d | 94 | [`tcx.hir()`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.hir |
ba9703b0 XL |
95 | [`hir::map`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/index.html |
96 | [HIR map]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html | |
97 | [number of methods]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#methods | |
a1dfa0c6 XL |
98 | |
99 | For example, if you have a [`DefId`], and you would like to convert it | |
100 | to a [`NodeId`], you can use | |
6a06907d | 101 | [`tcx.hir().as_local_node_id(def_id)`][as_local_node_id]. This returns |
a1dfa0c6 XL |
102 | an `Option<NodeId>` – this will be `None` if the def-id refers to |
103 | something outside of the current crate (since then it has no HIR | |
104 | node), but otherwise returns `Some(n)` where `n` is the node-id of the | |
105 | definition. | |
106 | ||
6a06907d | 107 | [`NodeId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/node_id/struct.NodeId.html |
ba9703b0 | 108 | [as_local_node_id]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.as_local_node_id |
a1dfa0c6 | 109 | |
6a06907d | 110 | Similarly, you can use [`tcx.hir().find(n)`][find] to lookup the node for a |
a1dfa0c6 XL |
111 | [`NodeId`]. This returns a `Option<Node<'tcx>>`, where [`Node`] is an enum |
112 | defined in the map; by matching on this you can find out what sort of | |
113 | node the node-id referred to and also get a pointer to the data | |
114 | itself. Often, you know what sort of node `n` is – e.g. if you know | |
115 | that `n` must be some HIR expression, you can do | |
6a06907d | 116 | [`tcx.hir().expect_expr(n)`][expect_expr], which will extract and return the |
a1dfa0c6 XL |
117 | [`&hir::Expr`][Expr], panicking if `n` is not in fact an expression. |
118 | ||
ba9703b0 | 119 | [find]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.find |
dfeec247 | 120 | [`Node`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/enum.Node.html |
ba9703b0 | 121 | [expect_expr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.expect_expr |
dfeec247 | 122 | [Expr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/struct.Expr.html |
a1dfa0c6 XL |
123 | |
124 | Finally, you can use the HIR map to find the parents of nodes, via | |
6a06907d | 125 | calls like [`tcx.hir().get_parent_node(n)`][get_parent_node]. |
a1dfa0c6 | 126 | |
ba9703b0 | 127 | [get_parent_node]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.get_parent_node |
a1dfa0c6 | 128 | |
6a06907d | 129 | ## HIR Bodies |
a1dfa0c6 | 130 | |
dfeec247 | 131 | A [`rustc_hir::Body`] represents some kind of executable code, such as the body |
a1dfa0c6 XL |
132 | of a function/closure or the definition of a constant. Bodies are |
133 | associated with an **owner**, which is typically some kind of item | |
134 | (e.g. an `fn()` or `const`), but could also be a closure expression | |
135 | (e.g. `|x, y| x + y`). You can use the HIR map to find the body | |
136 | associated with a given def-id ([`maybe_body_owned_by`]) or to find | |
137 | the owner of a body ([`body_owner_def_id`]). | |
138 | ||
dfeec247 | 139 | [`rustc_hir::Body`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/struct.Body.html |
ba9703b0 XL |
140 | [`maybe_body_owned_by`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.maybe_body_owned_by |
141 | [`body_owner_def_id`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.body_owner_def_id |