summaryrefslogtreecommitdiffstats
path: root/src/doc/rustc-dev-guide/src/thir.md
diff options
context:
space:
mode:
Diffstat (limited to 'src/doc/rustc-dev-guide/src/thir.md')
-rw-r--r--src/doc/rustc-dev-guide/src/thir.md223
1 files changed, 223 insertions, 0 deletions
diff --git a/src/doc/rustc-dev-guide/src/thir.md b/src/doc/rustc-dev-guide/src/thir.md
new file mode 100644
index 000000000..4f8e6512c
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/thir.md
@@ -0,0 +1,223 @@
+# The THIR
+
+<!-- toc -->
+
+The THIR ("Typed High-Level Intermediate Representation"), previously called HAIR for
+"High-Level Abstract IR", is another IR used by rustc that is generated after
+[type checking]. It is (as of <!-- date: 2022-04 --> April 2022) only used for
+[MIR construction] and [exhaustiveness checking]. There is also
+[an experimental unsafety checker][thir-unsafeck] that operates on the THIR as a replacement for
+the current MIR unsafety checker, and can be used instead of the MIR unsafety checker by passing
+the `-Z thir-unsafeck` flag to `rustc`.
+
+[type checking]: ./type-checking.md
+[MIR construction]: ./mir/construction.md
+[exhaustiveness checking]: ./pat-exhaustive-checking.md
+[thir-unsafeck]: https://github.com/rust-lang/compiler-team/issues/402
+
+As the name might suggest, the THIR is a lowered version of the [HIR] where all
+the types have been filled in, which is possible after type checking has completed.
+But it has some other interesting features that distinguish it from the HIR:
+
+- Like the MIR, the THIR only represents bodies, i.e. "executable code"; this includes
+ function bodies, but also `const` initializers, for example. Specifically, all [body owners] have
+ THIR created. Consequently, the THIR has no representation for items like `struct`s or `trait`s.
+
+- Each body of THIR is only stored temporarily and is dropped as soon as it's no longer
+ needed, as opposed to being stored until the end of the compilation process (which
+ is what is done with the HIR).
+
+- Besides making the types of all nodes available, the THIR also has additional
+ desugaring compared to the HIR. For example, automatic references and dereferences
+ are made explicit, and method calls and overloaded operators are converted into
+ plain function calls. Destruction scopes are also made explicit.
+
+- Statements, expressions, and match arms are stored separately. For example, statements in the
+ `stmts` array reference expressions by their index (represented as a [`ExprId`]) in the `exprs`
+ array.
+
+[HIR]: ./hir.md
+[`ExprId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/thir/struct.ExprId.html
+[body owners]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/enum.BodyOwnerKind.html
+
+The THIR lives in [`rustc_mir_build::thir`][thir-docs]. To construct a [`thir::Expr`],
+you can use the [`thir_body`] function, passing in the memory arena where the THIR
+will be allocated. Dropping this arena will result in the THIR being destroyed,
+which is useful to keep peak memory in check. Having a THIR representation of
+all bodies of a crate in memory at the same time would be very heavy.
+
+You can get a debug representation of the THIR by passing the `-Zunpretty=thir-tree` flag
+to `rustc`. Here is how a function with just the statement `let x = 1 + 2;` gets represented in
+THIR:
+```rust
+Thir {
+ // no match arms
+ arms: [],
+ exprs: [
+ // expression 0, a literal with a value of 1
+ Expr {
+ ty: i32,
+ temp_lifetime: Some(Node(6)),
+ span: oneplustwo.rs:2:13: 2:14 (#0),
+ kind: Literal {
+ literal: Const {
+ ty: i32,
+ val: Value(Scalar(0x00000001)),
+ },
+ user_ty: None,
+ const_id: None,
+ },
+ },
+ // expression 1, scope surronding literal 1
+ Expr {
+ ty: i32,
+ temp_lifetime: Some(Node(6)),
+ span: oneplustwo.rs:2:13: 2:14 (#0),
+ kind: Scope {
+ region_scope: Node(1),
+ lint_level: Explicit(HirId {
+ owner: DefId(0:3 ~ oneplustwo[6ccc]::main),
+ local_id: 1,
+ }),
+ // reference to expression 0 above
+ value: e0,
+ },
+ },
+ // expression 2, literal 2
+ Expr {
+ ty: i32,
+ temp_lifetime: Some(Node(6)),
+ span: oneplustwo.rs:2:17: 2:18 (#0),
+ kind: Literal {
+ literal: Const {
+ ty: i32,
+ val: Value(Scalar(0x00000002)),
+ },
+ user_ty: None,
+ const_id: None,
+ },
+ },
+ // expression 3, scope surrounding literal 2
+ Expr {
+ ty: i32,
+ temp_lifetime: Some(Node(6)),
+ span: oneplustwo.rs:2:17: 2:18 (#0),
+ kind: Scope {
+ region_scope: Node(2),
+ lint_level: Explicit(HirId {
+ owner: DefId(0:3 ~ oneplustwo[6ccc]::main),
+ local_id: 2,
+ }),
+ // reference to expression 2 above
+ value: e2,
+ },
+ },
+ // expression 4, represents 1 + 2
+ Expr {
+ ty: i32,
+ temp_lifetime: Some(Node(6)),
+ span: oneplustwo.rs:2:13: 2:18 (#0),
+ kind: Binary {
+ op: Add,
+ // references to scopes surronding literals above
+ lhs: e1,
+ rhs: e3,
+ },
+ },
+ // expression 5, scope surronding expression 4
+ Expr {
+ ty: i32,
+ temp_lifetime: Some(Node(6)),
+ span: oneplustwo.rs:2:13: 2:18 (#0),
+ kind: Scope {
+ region_scope: Node(3),
+ lint_level: Explicit(HirId {
+ owner: DefId(0:3 ~ oneplustwo[6ccc]::main),
+ local_id: 3,
+ }),
+ value: e4,
+ },
+ },
+ // expression 6, block around statement
+ Expr {
+ ty: (),
+ temp_lifetime: Some(Node(8)),
+ span: oneplustwo.rs:1:11: 3:2 (#0),
+ kind: Block {
+ body: Block {
+ targeted_by_break: false,
+ region_scope: Node(7),
+ opt_destruction_scope: None,
+ span: oneplustwo.rs:1:11: 3:2 (#0),
+ // reference to statement 0 below
+ stmts: [ s0 ],
+ expr: None,
+ safety_mode: Safe,
+ },
+ },
+ },
+ // expression 7, scope around block in expression 6
+ Expr {
+ ty: (),
+ temp_lifetime: Some(
+ Node(8),
+ ),
+ span: oneplustwo.rs:1:11: 3:2 (#0),
+ kind: Scope {
+ region_scope: Node(8),
+ lint_level: Explicit(HirId {
+ owner: DefId(0:3 ~ oneplustwo[6ccc]::main),
+ local_id: 8,
+ }),
+ value: e6,
+ },
+ },
+ // destruction scope around expression 7
+ Expr {
+ ty: (),
+ temp_lifetime: Some(Node(8)),
+ span: oneplustwo.rs:1:11: 3:2 (#0),
+ kind: Scope {
+ region_scope: Destruction(8),
+ lint_level: Inherited,
+ value: e7,
+ },
+ },
+ ],
+ stmts: [
+ // let statement
+ Stmt {
+ kind: Let {
+ remainder_scope: Remainder { block: 7, first_statement_index: 0},
+ init_scope: Node(6),
+ pattern: Pat {
+ ty: i32,
+ span: oneplustwo.rs:2:9: 2:10 (#0),
+ kind: Binding {
+ mutability: Not,
+ name: "x",
+ mode: ByValue,
+ var: HirId {
+ owner: DefId(0:3 ~ oneplustwo[6ccc]::main),
+ local_id: 5,
+ },
+ ty: i32,
+ subpattern: None,
+ is_primary: true,
+ },
+ },
+ initializer: Some(e5),
+ lint_level: Explicit(HirId {
+ owner: DefId(0:3 ~ oneplustwo[6ccc]::main),
+ local_id: 4,
+ }),
+ },
+ opt_destruction_scope: Some(Destruction(6)),
+ },
+ ],
+}
+```
+
+[thir-docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_build/thir/index.html
+[`thir::Expr`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/thir/struct.Expr.html
+[`thir_body`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.thir_body