Expand THIR section with more details (#1183)

* Expand THIR section with more details
* Remove incorrect reference to `HirId`s

Co-authored-by: Léo Lanteri Thauvin <leseulartichaut@gmail.com>
This commit is contained in:
Smittyvb 2021-08-21 19:55:56 -04:00 committed by GitHub
parent b5814b34da
commit cfffdd92ea
1 changed files with 183 additions and 7 deletions

View File

@ -4,10 +4,11 @@
The THIR ("Typed High-Level Intermediate Representation"), previously called HAIR for 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 "High-Level Abstract IR", is another IR used by rustc that is generated after
[type checking]. It is (as of <!-- date: 2021-03 --> March 2021) only used for [type checking]. It is (as of <!-- date: 2021-08 --> August 2021) only used for
[MIR construction] and [exhaustiveness checking], but [MIR construction] and [exhaustiveness checking]. There is also
[it may also soon be used for unsafety checking][thir-unsafeck] as a replacement [an experimental unsafety checker][thir-unsafeck] that operates on the THIR as a replacement for
for the current MIR unsafety checker. 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 [type checking]: ./type-checking.md
[MIR construction]: ./mir/construction.md [MIR construction]: ./mir/construction.md
@ -19,8 +20,8 @@ the types have been filled in, which is possible after type checking has complet
But it has some other interesting features that distinguish it from the HIR: 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 - Like the MIR, the THIR only represents bodies, i.e. "executable code"; this includes
function bodies, but also `const` initializers, for example. Consequently, the THIR function bodies, but also `const` initializers, for example. Specifically, all [body owners] have
has no representation for items like `struct`s or `trait`s. 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 - 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 needed, as opposed to being stored until the end of the compilation process (which
@ -31,7 +32,13 @@ But it has some other interesting features that distinguish it from the HIR:
are made explicit, and method calls and overloaded operators are converted into are made explicit, and method calls and overloaded operators are converted into
plain function calls. Destruction scopes are also made explicit. 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 [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`], 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 you can use the [`thir_body`] function, passing in the memory arena where the THIR
@ -40,7 +47,176 @@ 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. 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 You can get a debug representation of the THIR by passing the `-Zunpretty=thir-tree` flag
to `rustc`. 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-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::Expr`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/thir/struct.Expr.html